diff --git a/.gitignore b/.gitignore
index b312630..cf2aea2e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,23 +62,7 @@
 /ash/ash_unittests_run.xml
 /base/base_unittests_run.xml
 /breakpad/src/
-/build/android/bin
-/build/Debug
-/build/Debug_x64
-/build/goma
-/build/gomacc.lock
-/build/ipch/
-/build/Release
-/build/Release_x64
-/build/win_toolchain.json
-/build/util/LASTCHANGE*
-/build/util/support
-/build/x64/
-/build/linux/bin/eu-strip
-/build/linux/debian_*-sysroot/
-/build/linux/ubuntu_*-sysroot/
-/build/ios_files
-/build/mac_files
+# See build/.gitignore for entries covering src/build.
 /buildtools
 # The Chrome OS build creates a /c symlink due to http://crbug.com/54866.
 /c
@@ -289,202 +273,7 @@
 /tools/luci-go/linux64/isolate
 /tools/luci-go/mac64/isolate
 /tools/luci-go/win64/isolate.exe
-/third_party/__START__
-/third_party/accessibility-developer-tools/
-/third_party/accessibility_test_framework/lib/*.jar
-/third_party/adobe/flash/binaries
-/third_party/adobe/flash/symbols
-/third_party/amd/
-/third_party/android_protobuf/src
-/third_party/android_support_test_runner/lib/*.aar
-/third_party/android_support_test_runner/lib/*.jar
-/third_party/android_tools/
-/third_party/android_tools_internal/
-/third_party/android_webview_glue/src
-/third_party/angle
-/third_party/angle_dx11
-/third_party/apache-portable-runtime/src
-/third_party/apache_velocity/lib/*.jar
-/third_party/apache-win32/bin/*.exe
-/third_party/apache-win32/bin/*.dll
-/third_party/apache-win32/bin/iconv/*.so
-/third_party/apache-win32/modules/*.so
-/third_party/apache-win32/modules/*.dll
-/third_party/asan
-/third_party/bidichecker
-/third_party/bison
-/third_party/boringssl/src
-/third_party/bouncycastle/lib/*.jar
-/third_party/byte_buddy/lib/*.jar
-/third_party/cacheinvalidation/cacheinvalidation_unittests_run.xml
-/third_party/cardboard-java/src
-/third_party/catapult
-/third_party/ced/src
-/third_party/chromeos_login_manager
-/third_party/chromeos_text_input
-/third_party/chromite
-/third_party/cld_2/src
-/third_party/cld_3/src
-/third_party/colorama/src
-/third_party/cros
-/third_party/cros_system_api
-/third_party/custom_tabs_client/src
-/third_party/cygwin
-/third_party/deqp/src
-/third_party/directxsdk
-/third_party/dom_distiller_js/dist
-/third_party/drmemory/drmemory-windows-sfx.exe
-/third_party/drmemory/unpacked
-/third_party/elfutils/src
-/third_party/errorprone/lib
-/third_party/espresso/lib/*.jar
-/third_party/eyesfree/src
-/third_party/ffmpeg
-/third_party/findbugs
-/third_party/flac
-/third_party/flatbuffers/src
-/third_party/fontconfig/src
-/third_party/freetype-android/src
-/third_party/freetype2/src
-/third_party/gestures/gestures
-/third_party/gles2_conform
-/third_party/glslang/src
-/third_party/glslang-angle/src
-/third_party/gnu_binutils/
-/third_party/google_appengine_cloudstorage
-/third_party/google_toolbox_for_mac/src
-/third_party/googlemac
-/third_party/gvr-android-sdk/common_library.aar
-/third_party/gvr-android-sdk/libgvr_shim_static_arm.a
-/third_party/gvr-android-sdk/libgvr_shim_static_arm64.a
-/third_party/gvr-android-sdk/src
-/third_party/gperf
-/third_party/guava/lib/*.jar
-/third_party/hamcrest/lib/*.jar
-/third_party/hunspell_dictionaries
-/third_party/icu
-/third_party/icu4j/lib/*.jar
-/third_party/intellij/lib/*.jar
-/third_party/inspector_protocol
-/third_party/javax_inject/lib/*.jar
-/third_party/jsoncpp/source
-/third_party/jsr-305/src
-/third_party/junit/src
-/third_party/khronos_glcts
-/third_party/leakcanary/src
-/third_party/leveldatabase/src
-/third_party/leveldb
-/third_party/libc++-static/libc++.a
-/third_party/libaddressinput/src
-/third_party/libdrm/src
-/third_party/libevdev/src
-/third_party/libexif/sources
-/third_party/libFuzzer/src
-/third_party/libjingle/source
-/third_party/libjpeg_turbo
-/third_party/liblouis/src
-/third_party/libphonenumber/dist
-/third_party/libsrtp
-/third_party/libupnp
-/third_party/libvpx/source/libvpx
-/third_party/libwebm/source
-/third_party/libyuv
-/third_party/lighttpd
-/third_party/llvm
-/third_party/llvm-allocated-type
-/third_party/llvm-bootstrap
-/third_party/llvm-build
-/third_party/lss
-/third_party/mesa/src
-/third_party/mingw-w64
-/third_party/minigbm/src
-/third_party/mkl
-/third_party/mocha
-/third_party/mockito/src
-/third_party/nacl_sdk_binaries/
-/third_party/netty-tcnative/src
-/third_party/netty4/src
-/third_party/node/linux
-/third_party/node/mac
-/third_party/node/node_modules
-/third_party/node/*.tar.gz
-/third_party/node/win
-/third_party/nss
-/third_party/objenesis/lib/*.jar
-/third_party/omaha/src/omaha
-/third_party/openmax_dl/
-/third_party/openh264/src
-/third_party/ow2_asm/lib/*.jar
-/third_party/pdfsqueeze
-/third_party/pdfium
-/third_party/pefile
-/third_party/perl
-/third_party/ppapi
-/third_party/psyco_win32
-/third_party/pthreads-win32
-/third_party/py_trace_event/src
-/third_party/pyelftools
-/third_party/pyftpdlib/src
-/third_party/pylib
-/third_party/pymox/src
-/third_party/python_24
-/third_party/python_26
-/third_party/pywebsocket/src
-/third_party/pywebsocket/src
-/third_party/re2/src
-/third_party/requests/src
-/third_party/retrolambda/*.jar
-/third_party/robolectric/lib/*.jar
-/third_party/robolectric/robolectric
-/third_party/scan-build/src
-/third_party/scons-2.0.1
-/third_party/sfntly/src
-/third_party/shaderc/src
-/third_party/skia
-/third_party/smhasher/src
-/third_party/snappy/src
-/third_party/spirv-headers/src
-/third_party/SPIRV-Tools/src
-/third_party/spirv-tools-angle/src
-/third_party/sqlite4java/lib/**/*.dll
-/third_party/sqlite4java/lib/**/*.jar
-/third_party/sqlite4java/lib/**/*.jnilib
-/third_party/sqlite4java/lib/**/*.so
-/third_party/swiftshader/
-/third_party/syzygy
-/third_party/syzygy/binaries
-/third_party/tsan/
-/third_party/ub-uiautomator/lib
-/third_party/usb_ids
-/third_party/usrsctp/usrsctplib
-/third_party/v8-i18n
-/third_party/valgrind
-/third_party/vulkan-validation-layers/src
-/third_party/visualmetrics
-/third_party/wayland/src
-/third_party/wayland-protocols/src
-/third_party/wds/src
-/third_party/webdriver/pylib
-/third_party/webdriver/python/selenium
-/third_party/webgl
-/third_party/webgl/src
-/third_party/webpagereplay/
-/third_party/webrtc
-/third_party/widevine/cdm/chromeos
-/third_party/widevine/cdm/linux
-/third_party/widevine/cdm/mac
-/third_party/widevine/cdm/win
-/third_party/widevine/scripts
-/third_party/widevine/test/license_server
-/third_party/win_toolchain/.timestamps
-/third_party/win_toolchain/files
-/third_party/wix
-/third_party/xdg-utils
-/third_party/xulrunner-sdk
-/third_party/yasm/binaries
-/third_party/yasm/generate_files.xml
-/third_party/yasm/source/patched-yasm
-/third_party/yasm/yasm.xml
+# See third_party/.gitignore for entries covering src/third_party.
 /tools/.bisect-builds-cache.json
 /tools/distcc
 /tools/gn/bin/linux
diff --git a/DEPS b/DEPS
index 7a082e7..8ec3049 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # 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': '8a0bfc5201f14c994fe8062ecf1ca34a172de9d3',
+  'skia_revision': 'ca70b59d8c83dda0a31915ab824995cf49c830a1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'cde4f024e2d00a49c170a82a50aef31e17068d1e',
+  'angle_revision': '0a17c92c292706bb818d8fed16f64a8708cddd0b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '60fd9fc63744419a760201af596515d411b7e194',
+  'pdfium_revision': 'e3f237740fd8bea50b4a6f37f56455dfa0328546',
   # 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.
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'ee10b35a44f89833c0048a2b242f1de734108411',
+  'nacl_revision': '81142aef3ec03dbc554e1cb0e22e4243e8aa69af',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype-android
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'bbfc356b5b6ec0200b27805acef8486938522968',
+  'catapult_revision': '42d9cffaa797712c58d7b5fb59820f0aa3e82138',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -154,7 +154,7 @@
     Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '9cd2828740572ba6f694b9365236a8356fd06147',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '450be73c9ee8ae29d43d4fdc82febb2a5f62bfb5',
 
   'src/third_party/hunspell_dictionaries':
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'dc6e7c25bf47cbfb466e0701fd2728b4a12e79d5',
@@ -202,7 +202,7 @@
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
 
   'src/third_party/libvpx/source/libvpx':
-    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '91f87e75135cc9722ee72daf5154424f628a906e',
+    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '4d4231352c8cefdae2e76b7bad4286ec21747c89',
 
   'src/third_party/ffmpeg':
     Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '3f3ad2ea90df08f5907bd997e1ce22e1c19ce215',
@@ -769,6 +769,28 @@
                '-l', 'third_party/objenesis'
     ],
   },
+  # Downloads the VR Services and Daydream Home APKs used for VR testing on
+  # Android.
+  {
+    'name': 'vr_services_apks',
+    'pattern': '.',
+    'action': ['python',
+               'src/build/android/update_deps/update_third_party_deps.py',
+               'download',
+               '-b', 'chrome-vr-test-apks/vr_services',
+               '-l', 'third_party/gvr-android-sdk/test-apks/vr_services'
+    ],
+  },
+  {
+    'name': 'daydream_home_apks',
+    'pattern': '.',
+    'action': ['python',
+               'src/build/android/update_deps/update_third_party_deps.py',
+               'download',
+               '-b', 'chrome-vr-test-apks/daydream_home',
+               '-l', 'third_party/gvr-android-sdk/test-apks/daydream_home'
+    ],
+  },
   {
     # Downloads the current stable linux sysroot to build/linux/ if needed.
     # This sysroot updates at about the same rate that the chrome build deps
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 6334c05..e56d4b3 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -431,7 +431,7 @@
 
 
 def _CheckDCHECK_IS_ONHasBraces(input_api, output_api):
-  """Checks to make sure DCHECK_IS_ON() does not skip the braces."""
+  """Checks to make sure DCHECK_IS_ON() does not skip the parentheses."""
   errors = []
   pattern = input_api.re.compile(r'DCHECK_IS_ON(?!\(\))',
                                  input_api.re.MULTILINE)
@@ -442,7 +442,7 @@
       if input_api.re.search(pattern, line):
         errors.append(output_api.PresubmitError(
           ('%s:%d: Use of DCHECK_IS_ON() must be written as "#if ' +
-           'DCHECK_IS_ON()", not forgetting the braces.')
+           'DCHECK_IS_ON()", not forgetting the parentheses.')
           % (f.LocalPath(), lnum)))
   return errors
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 3a0cdb3a0..6712d66 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -813,6 +813,13 @@
                   '|components/payments'\
                   '|third_party/WebKit/LayoutTests/payments/'\
                   '|third_party/WebKit/Source/modules/payments'\
+                  '|ios/web/payments/'\
+                  '|ios/web/public/payments/'\
+                  '|ios/chrome/browser/payments/'
+    },
+    'payments_ios': {
+      'filepath': 'ios/web/payments/'\
+                  '|ios/web/public/payments/'\
                   '|ios/chrome/browser/payments/'
     },
     'pepper_api': {
@@ -2024,7 +2031,9 @@
                          'vabr+watchlistpasswordmanager@chromium.org'],
     'payments': ['rouslan+payments@chromium.org',
                  'sebsg+paymentswatch@chromium.org',
-                 'gogerald+paymentswatch@chromium.org'],
+                 'gogerald+paymentswatch@chromium.org',
+                 'mahmadi+paymentswatch@chromium.org'],
+    'payments_ios': ['mahmadi+paymentsioswatch@chromium.org'],
     'pepper_api': ['binji+watch@chromium.org',
                    'bradnelson+warch@chromium.org',
                    'ihf+watch@chromium.org',
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
index 7ea0f81d5..36a08c2 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientFullScreenTest.java
@@ -307,7 +307,7 @@
 
         // Enter fullscreen and verify that the power save blocker is
         // still there.
-        DOMUtils.clickNode(this, mContentViewCore, CUSTOM_FULLSCREEN_CONTROL_ID);
+        DOMUtils.clickNode(mContentViewCore, CUSTOM_FULLSCREEN_CONTROL_ID);
         mContentsClient.waitForCustomViewShown();
         assertKeepScreenOnActive(mTestContainerView, true);
 
@@ -354,7 +354,7 @@
             // (containing the fullscreen <video>) so we just rely on that fact here.
             TouchCommon.singleClickView(mContentsClient.getCustomView());
         } else {
-            DOMUtils.clickNode(this, mContentViewCore, CUSTOM_PLAY_CONTROL_ID);
+            DOMUtils.clickNode(mContentViewCore, CUSTOM_PLAY_CONTROL_ID);
         }
     }
 
@@ -472,7 +472,7 @@
 
     private void loadTestPageAndClickFullscreen(String videoTestUrl) throws Exception {
         loadTestPage(videoTestUrl);
-        DOMUtils.clickNode(this, mContentViewCore, CUSTOM_FULLSCREEN_CONTROL_ID);
+        DOMUtils.clickNode(mContentViewCore, CUSTOM_FULLSCREEN_CONTROL_ID);
     }
 
     private void loadTestPage(String videoTestUrl) throws Exception {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
index fe74a78a..95d4d81 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientGetVideoLoadingProgressViewTest.java
@@ -71,9 +71,9 @@
         enableJavaScriptOnUiThread(awContents);
         loadUrlSync(awContents, contentsClient.getOnPageFinishedHelper(), VIDEO_TEST_URL);
         Thread.sleep(5 * 1000);
-        DOMUtils.clickNode(this, awContents.getContentViewCore(), CUSTOM_FULLSCREEN_CONTROL_ID);
+        DOMUtils.clickNode(awContents.getContentViewCore(), CUSTOM_FULLSCREEN_CONTROL_ID);
         Thread.sleep(1 * 1000);
-        DOMUtils.clickNode(this, awContents.getContentViewCore(), CUSTOM_PLAY_CONTROL_ID);
+        DOMUtils.clickNode(awContents.getContentViewCore(), CUSTOM_PLAY_CONTROL_ID);
         waitForViewAttached();
     }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
index 5ec6e32d6..95b1b9d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwContentsClientShouldOverrideUrlLoadingTest.java
@@ -722,7 +722,7 @@
         assertEquals(indirectLoadCallCount, mShouldOverrideUrlLoadingHelper.getCallCount());
 
         // Simulate touch, hasUserGesture must be true only on the first call.
-        DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "link");
+        DOMUtils.clickNode(mAwContents.getContentViewCore(), "link");
 
         mShouldOverrideUrlLoadingHelper.waitForCallback(indirectLoadCallCount, 1);
         assertEquals(redirectUrl,
@@ -941,7 +941,7 @@
             assertNull(getActivity().getLastSentIntent());
 
             // Clicking on a link should create an intent.
-            DOMUtils.clickNode(this, mAwContents.getContentViewCore(), "link");
+            DOMUtils.clickNode(mAwContents.getContentViewCore(), "link");
             pollUiThread(new Callable<Boolean>() {
                 @Override
                 public Boolean call() {
@@ -999,7 +999,7 @@
 
             final String findContentJs = setupForContentClickTest(pageContent, true);
             // Clicking on the content should create an intent.
-            DOMUtils.clickNodeByJs(this, mAwContents.getContentViewCore(), findContentJs);
+            DOMUtils.clickNodeByJs(mAwContents.getContentViewCore(), findContentJs);
             pollUiThread(new Callable<Boolean>() {
                 @Override
                 public Boolean call() {
@@ -1041,7 +1041,7 @@
 
         final String findContentJs = setupForContentClickTest(pageContent, inMainFrame);
         int callCount = mShouldOverrideUrlLoadingHelper.getCallCount();
-        DOMUtils.clickNodeByJs(this, mAwContents.getContentViewCore(), findContentJs);
+        DOMUtils.clickNodeByJs(mAwContents.getContentViewCore(), findContentJs);
         mShouldOverrideUrlLoadingHelper.waitForCallback(callCount);
         assertEquals(intentContent,
                 mShouldOverrideUrlLoadingHelper.getShouldOverrideUrlLoadingUrl());
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
index d1f8f36..cff6568 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwSettingsTest.java
@@ -2111,7 +2111,7 @@
             int count = callback.getCallCount();
             loadDataSync(awContents, contentClient.getOnPageFinishedHelper(), pageHtml,
                     "text/html", false);
-            DOMUtils.clickNode(this, testContainer.getContentViewCore(), "play");
+            DOMUtils.clickNode(testContainer.getContentViewCore(), "play");
             callback.waitForCallback(count, 1);
             assertEquals(0, webServer.getRequestCount(httpPath));
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java
index 2ddcd72..f499e073 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PlatformMediaCodecTest.java
@@ -37,7 +37,7 @@
     public void testCanPlayPlatformMediaCodecs() throws Throwable {
         loadUrlSync(mTestContainerView.getAwContents(), mContentsClient.getOnPageFinishedHelper(),
                 "file:///android_asset/platform-media-codec-test.html");
-        DOMUtils.clickNode(this, mContentViewCore, "playButton");
+        DOMUtils.clickNode(mContentViewCore, "playButton");
         DOMUtils.waitForMediaPlay(getWebContentsOnUiThread(), "videoTag");
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index da92ce0..e9f0386c 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -122,7 +122,7 @@
         enableJavaScriptOnUiThread(popupContents);
 
         // Now long press on some texts and see if the text handles show up.
-        DOMUtils.longPressNode(this, popupContents.getContentViewCore(), "plain_text");
+        DOMUtils.longPressNode(popupContents.getContentViewCore(), "plain_text");
         assertWaitForSelectActionBarStatus(true, popupContents.getContentViewCore());
         assertTrue(runTestOnUiThreadAndGetResult(new Callable<Boolean>() {
             @Override
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
index d1dbf00..37fae153 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/VisualStateTest.java
@@ -310,8 +310,7 @@
                 awContentsClient.getOnPageFinishedHelper(), WAIT_FOR_JS_TEST_URL);
 
         assertTrue(readyToUpdateColor.await(AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        DOMUtils.clickNode(
-                VisualStateTest.this, contentViewCore, UPDATE_COLOR_CONTROL_ID);
+        DOMUtils.clickNode(contentViewCore, UPDATE_COLOR_CONTROL_ID);
         assertTrue(jsObserver.waitForEvent(WAIT_TIMEOUT_MS));
 
         runTestOnUiThread(new Runnable() {
@@ -382,7 +381,7 @@
 
         assertTrue(readyToEnterFullscreenSignal.await(
                 AwTestBase.WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        DOMUtils.clickNode(VisualStateTest.this, contentViewCore, ENTER_FULLSCREEN_CONTROL_ID);
+        DOMUtils.clickNode(contentViewCore, ENTER_FULLSCREEN_CONTROL_ID);
         assertTrue(jsObserver.waitForEvent(WAIT_TIMEOUT_MS));
 
         runTestOnUiThread(new Runnable() {
diff --git a/ash/ash_chromeos_strings.grdp b/ash/ash_chromeos_strings.grdp
index 2af26f2..bb1267c9 100644
--- a/ash/ash_chromeos_strings.grdp
+++ b/ash/ash_chromeos_strings.grdp
@@ -505,6 +505,9 @@
   <message name="IDS_ASH_STATUS_TRAY_NETWORK_WIFI" desc="The label used in the tray popup to separate Wi-Fi networks.">
     Wi-Fi
   </message>
+  <message name="IDS_ASH_STATUS_TRAY_NETWORK_TETHER" desc="The label used in the tray popup to separate Instant Tethering networks.">
+    Instant Tethering
+  </message>
   <message name="IDS_ASH_STATUS_TRAY_ADD_CONNECTION" desc="Title for control to add a new network connection." >
     Add connection
   </message>
diff --git a/ash/common/system/chromeos/network/network_info.h b/ash/common/system/chromeos/network/network_info.h
index 758ac857..c321a837 100644
--- a/ash/common/system/chromeos/network/network_info.h
+++ b/ash/common/system/chromeos/network/network_info.h
@@ -19,7 +19,7 @@
 // Includes information necessary about a network for displaying the appropriate
 // UI to the user.
 struct NetworkInfo {
-  enum class Type { UNKNOWN, WIFI, CELLULAR };
+  enum class Type { UNKNOWN, WIFI, TETHER, CELLULAR };
 
   NetworkInfo();
   NetworkInfo(const std::string& guid);
diff --git a/ash/common/system/chromeos/network/network_list_md.cc b/ash/common/system/chromeos/network/network_list_md.cc
index dd12aa1..140071e 100644
--- a/ash/common/system/chromeos/network/network_list_md.cc
+++ b/ash/common/system/chromeos/network/network_list_md.cc
@@ -182,6 +182,24 @@
   DISALLOW_COPY_AND_ASSIGN(CellularHeaderRowView);
 };
 
+class TetherHeaderRowView : public NetworkListViewMd::SectionHeaderRowView {
+ public:
+  TetherHeaderRowView()
+      : SectionHeaderRowView(IDS_ASH_STATUS_TRAY_NETWORK_TETHER) {}
+
+  ~TetherHeaderRowView() override {}
+
+  const char* GetClassName() const override { return "TetherHeaderRowView"; }
+
+ protected:
+  void OnToggleToggled(bool is_on) override {
+    // TODO (hansberry): Persist toggle to settings/preferences.
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TetherHeaderRowView);
+};
+
 class WifiHeaderRowView : public NetworkListViewMd::SectionHeaderRowView {
  public:
   explicit WifiHeaderRowView(NetworkListDelegate* network_list_delegate)
@@ -263,8 +281,10 @@
       no_wifi_networks_view_(nullptr),
       no_cellular_networks_view_(nullptr),
       cellular_header_view_(nullptr),
+      tether_header_view_(nullptr),
       wifi_header_view_(nullptr),
       cellular_separator_view_(nullptr),
+      tether_separator_view_(nullptr),
       wifi_separator_view_(nullptr) {
   CHECK(delegate_);
 }
@@ -275,10 +295,20 @@
 
 void NetworkListViewMd::Update() {
   CHECK(container());
-  NetworkStateHandler::NetworkStateList network_list;
+
   NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler();
+
+  NetworkStateHandler::NetworkStateList network_list;
   handler->GetVisibleNetworkList(&network_list);
   UpdateNetworks(network_list);
+
+  NetworkStateHandler::NetworkStateList tether_network_list;
+  handler->GetTetherNetworkList(0 /* no limit */, &tether_network_list);
+  for (const auto& tether_network : tether_network_list) {
+    network_list_.push_back(
+        base::MakeUnique<NetworkInfo>(tether_network->guid()));
+  }
+
   UpdateNetworkIcons();
   OrderNetworks();
   UpdateNetworkListInternal();
@@ -376,6 +406,8 @@
       info->type = NetworkInfo::Type::WIFI;
     else if (network->Matches(NetworkTypePattern::Cellular()))
       info->type = NetworkInfo::Type::CELLULAR;
+    else if (network->Matches(NetworkTypePattern::Tether()))
+      info->type = NetworkInfo::Type::TETHER;
     if (prohibited_by_policy) {
       info->tooltip =
           l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_NETWORK_PROHIBITED);
@@ -464,6 +496,25 @@
     new_guids->insert(new_cellular_guids->begin(), new_cellular_guids->end());
   }
 
+  // TODO (hansberry): Audit existing usage of NonVirtual and consider changing
+  // it to include Tether. See crbug.com/693647.
+  if (handler->IsTechnologyAvailable(NetworkTypePattern::Tether())) {
+    index = UpdateSectionHeaderRow(
+        NetworkTypePattern::Tether(),
+        handler->IsTechnologyEnabled(NetworkTypePattern::Tether()), index,
+        &tether_header_view_, &tether_separator_view_);
+
+    // TODO (hansberry): Should a message similar to
+    // IDS_ASH_STATUS_TRAY_NO_CELLULAR_NETWORKS be shown if Tether technology
+    // is enabled but no networks are around?
+
+    // Add Tether networks.
+    std::unique_ptr<std::set<std::string>> new_tether_guids =
+        UpdateNetworkChildren(NetworkInfo::Type::TETHER, index);
+    index += new_tether_guids->size();
+    new_guids->insert(new_tether_guids->begin(), new_tether_guids->end());
+  }
+
   if (pattern.MatchesPattern(NetworkTypePattern::WiFi())) {
     index = UpdateSectionHeaderRow(
         NetworkTypePattern::WiFi(),
@@ -570,6 +621,8 @@
   if (!*view) {
     if (pattern.Equals(NetworkTypePattern::Cellular()))
       *view = new CellularHeaderRowView();
+    else if (pattern.Equals(NetworkTypePattern::Tether()))
+      *view = new TetherHeaderRowView();
     else if (pattern.Equals(NetworkTypePattern::WiFi()))
       *view = new WifiHeaderRowView(delegate_);
     else
diff --git a/ash/common/system/chromeos/network/network_list_md.h b/ash/common/system/chromeos/network/network_list_md.h
index 9180381..fea2365 100644
--- a/ash/common/system/chromeos/network/network_list_md.h
+++ b/ash/common/system/chromeos/network/network_list_md.h
@@ -108,8 +108,10 @@
   views::Label* no_wifi_networks_view_;
   views::Label* no_cellular_networks_view_;
   SectionHeaderRowView* cellular_header_view_;
+  SectionHeaderRowView* tether_header_view_;
   SectionHeaderRowView* wifi_header_view_;
   views::Separator* cellular_separator_view_;
+  views::Separator* tether_separator_view_;
   views::Separator* wifi_separator_view_;
 
   // An owned list of network info.
diff --git a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
index 74040a8..5393679 100644
--- a/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
+++ b/ash/common/system/chromeos/virtual_keyboard/virtual_keyboard_tray.cc
@@ -7,19 +7,14 @@
 #include <algorithm>
 
 #include "ash/common/keyboard/keyboard_ui.h"
-#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/wm_shelf.h"
-#include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/system/tray/tray_constants.h"
-#include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/display/display.h"
 #include "ui/events/event.h"
 #include "ui/gfx/image/image_skia.h"
@@ -33,22 +28,13 @@
     : TrayBackgroundView(wm_shelf),
       icon_(new views::ImageView),
       wm_shelf_(wm_shelf) {
-  if (MaterialDesignController::IsShelfMaterial()) {
-    SetInkDropMode(InkDropMode::ON);
-    SetContentsBackground(false);
-    gfx::ImageSkia image_md =
-        CreateVectorIcon(kShelfKeyboardIcon, kShelfIconColor);
-    icon_->SetImage(image_md);
-  } else {
-    SetContentsBackground(true);
-    gfx::ImageSkia* image_non_md =
-        ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_AURA_UBER_TRAY_VIRTUAL_KEYBOARD);
-    icon_->SetImage(image_non_md);
-  }
+  SetInkDropMode(InkDropMode::ON);
+  SetContentsBackground(false);
 
+  icon_->SetImage(gfx::CreateVectorIcon(kShelfKeyboardIcon, kShelfIconColor));
   SetIconBorderForShelfAlignment();
   tray_container()->AddChildView(icon_);
+
   // The Shell may not exist in some unit tests.
   if (WmShell::HasInstance())
     WmShell::Get()->keyboard_ui()->AddObserver(this);
@@ -115,21 +101,9 @@
 void VirtualKeyboardTray::OnKeyboardClosed() {}
 
 void VirtualKeyboardTray::SetIconBorderForShelfAlignment() {
-  // Every time shelf alignment is updated, StatusAreaWidgetDelegate resets the
-  // border to a non-null border. So, we need to remove it.
-  if (!ash::MaterialDesignController::IsShelfMaterial())
-    tray_container()->SetBorder(views::NullBorder());
   const gfx::ImageSkia& image = icon_->GetImage();
-  const int size = GetTrayConstant(VIRTUAL_KEYBOARD_BUTTON_SIZE);
-  const int vertical_padding = (size - image.height()) / 2;
-  int horizontal_padding = (size - image.width()) / 2;
-  if (!ash::MaterialDesignController::IsShelfMaterial() &&
-      IsHorizontalAlignment(shelf_alignment())) {
-    // Square up the padding if horizontally aligned. Avoid extra padding when
-    // vertically aligned as the button would violate the width constraint on
-    // the shelf.
-    horizontal_padding += std::max(0, vertical_padding - horizontal_padding);
-  }
+  const int vertical_padding = (kTrayItemSize - image.height()) / 2;
+  const int horizontal_padding = (kTrayItemSize - image.width()) / 2;
   icon_->SetBorder(views::CreateEmptyBorder(
       gfx::Insets(vertical_padding, horizontal_padding)));
 }
diff --git a/ash/common/system/overview/overview_button_tray.cc b/ash/common/system/overview/overview_button_tray.cc
index c65942e..8bd5f85 100644
--- a/ash/common/system/overview/overview_button_tray.cc
+++ b/ash/common/system/overview/overview_button_tray.cc
@@ -4,55 +4,28 @@
 
 #include "ash/common/system/overview/overview_button_tray.h"
 
-#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_constants.h"
-#include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
-#include "ash/common/system/tray/tray_utils.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm/overview/window_selector_controller.h"
 #include "ash/common/wm_shell.h"
-#include "ash/public/cpp/shelf_types.h"
-#include "ash/resources/grit/ash_resources.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/image_view.h"
 
-namespace {
-
-// Predefined padding for the icon used in this tray. These are to be set to the
-// border of the icon, depending on the current shelf_alignment()
-const int kHorizontalShelfHorizontalPadding = 8;
-const int kHorizontalShelfVerticalPadding = 4;
-const int kVerticalShelfHorizontalPadding = 2;
-const int kVerticalShelfVerticalPadding = 5;
-
-}  // namespace
-
 namespace ash {
 
 OverviewButtonTray::OverviewButtonTray(WmShelf* wm_shelf)
-    : TrayBackgroundView(wm_shelf), icon_(nullptr) {
-  icon_ = new views::ImageView();
-  if (MaterialDesignController::IsShelfMaterial()) {
-    SetInkDropMode(InkDropMode::ON);
-    SetContentsBackground(false);
-    gfx::ImageSkia image_md =
-        CreateVectorIcon(kShelfOverviewIcon, kShelfIconColor);
-    icon_->SetImage(image_md);
-  } else {
-    SetContentsBackground(true);
-    gfx::ImageSkia* image_non_md =
-        ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_AURA_UBER_TRAY_OVERVIEW_MODE);
-    icon_->SetImage(image_non_md);
-  }
+    : TrayBackgroundView(wm_shelf), icon_(new views::ImageView()) {
+  SetInkDropMode(InkDropMode::ON);
+  SetContentsBackground(false);
+
+  icon_->SetImage(CreateVectorIcon(kShelfOverviewIcon, kShelfIconColor));
   SetIconBorderForShelfAlignment();
   tray_container()->AddChildView(icon_);
 
@@ -123,25 +96,16 @@
 }
 
 void OverviewButtonTray::SetIconBorderForShelfAlignment() {
-  gfx::Insets insets;
-  if (ash::MaterialDesignController::IsShelfMaterial()) {
-    // Pad button size to align with other controls in the system tray.
-    const gfx::ImageSkia image = icon_->GetImage();
-    const int vertical_padding = (kTrayItemSize - image.height()) / 2;
-    const int horizontal_padding = (kTrayItemSize - image.width()) / 2;
-    insets = gfx::Insets(vertical_padding, horizontal_padding);
-  } else {
-    insets = IsHorizontalAlignment(shelf_alignment())
-                 ? gfx::Insets(kHorizontalShelfVerticalPadding,
-                               kHorizontalShelfHorizontalPadding)
-                 : gfx::Insets(kVerticalShelfVerticalPadding,
-                               kVerticalShelfHorizontalPadding);
-  }
-  icon_->SetBorder(views::CreateEmptyBorder(insets));
+  // Pad button size to align with other controls in the system tray.
+  const gfx::ImageSkia& image = icon_->GetImage();
+  const int vertical_padding = (kTrayItemSize - image.height()) / 2;
+  const int horizontal_padding = (kTrayItemSize - image.width()) / 2;
+  icon_->SetBorder(views::CreateEmptyBorder(
+      gfx::Insets(vertical_padding, horizontal_padding)));
 }
 
 void OverviewButtonTray::UpdateIconVisibility() {
-  // The visibility of the OverviewButtonTray has diverge from
+  // The visibility of the OverviewButtonTray has diverged from
   // WindowSelectorController::CanSelect. The visibility of the button should
   // not change during transient times in which CanSelect is false. Such as when
   // a modal dialog is present.
diff --git a/ash/common/system/tray/tray_constants.cc b/ash/common/system/tray/tray_constants.cc
index 6bf56323..43f6a24 100644
--- a/ash/common/system/tray/tray_constants.cc
+++ b/ash/common/system/tray/tray_constants.cc
@@ -119,7 +119,6 @@
   const int kTrayPopupItemLeftInset[] = {0, 4, 4};
   const int kTrayPopupItemMinStartWidth[] = {46, 48, 48};
   const int kTrayPopupItemMinEndWidth[] = {40, 40, 40};
-  const int kVirtualKeyboardButtonSize[] = {39, kTrayItemSize, kTrayItemSize};
   const int kTrayImeMenuIcon[] = {40, kTrayItemSize, kTrayItemSize};
   const int kTrayImageItemPadding[] = {1, 3, 3};
 
@@ -147,8 +146,6 @@
       return kTrayPopupItemMinStartWidth[mode];
     case TRAY_POPUP_ITEM_MIN_END_WIDTH:
       return kTrayPopupItemMinEndWidth[mode];
-    case VIRTUAL_KEYBOARD_BUTTON_SIZE:
-      return kVirtualKeyboardButtonSize[mode];
     case TRAY_IME_MENU_ICON:
       return kTrayImeMenuIcon[mode];
     case TRAY_IMAGE_ITEM_PADDING:
diff --git a/ash/common/system/tray/tray_constants.h b/ash/common/system/tray/tray_constants.h
index 1da6f92b..e457f1df 100644
--- a/ash/common/system/tray/tray_constants.h
+++ b/ash/common/system/tray/tray_constants.h
@@ -171,12 +171,6 @@
   // The minimum default width for the right container of the system menu rows.
   TRAY_POPUP_ITEM_MIN_END_WIDTH,
 
-  // The width and height of the virtual keyboard button in the status tray
-  // area. For non-MD, adjustments are made to the button dimensions based on
-  // the shelf orientation, so this constant does not specify the true
-  // user-visible button bounds.
-  VIRTUAL_KEYBOARD_BUTTON_SIZE,
-
   // The icon size of opt-in IME menu tray.
   TRAY_IME_MENU_ICON,
 
diff --git a/ash/common/system/tray_accessibility.cc b/ash/common/system/tray_accessibility.cc
index 1c641eb..1e643544 100644
--- a/ash/common/system/tray_accessibility.cc
+++ b/ash/common/system/tray_accessibility.cc
@@ -6,7 +6,6 @@
 
 #include "ash/common/accessibility_delegate.h"
 #include "ash/common/accessibility_types.h"
-#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/system/tray/hover_highlight_view.h"
 #include "ash/common/system/tray/system_tray.h"
@@ -39,10 +38,6 @@
 namespace ash {
 namespace {
 
-bool UseMdMenu() {
-  return MaterialDesignController::IsSystemTrayMenuMaterial();
-}
-
 enum AccessibilityState {
   A11Y_NONE = 0,
   A11Y_SPOKEN_FEEDBACK = 1 << 0,
@@ -160,14 +155,8 @@
       virtual_keyboard_enabled_(false),
       login_(login) {
   Reset();
-
   AppendAccessibilityList();
-
-  if (!UseMdMenu())
-    AppendHelpEntries();
-
   CreateTitleRow(IDS_ASH_STATUS_TRAY_ACCESSIBILITY_TITLE);
-
   Layout();
 }
 
@@ -223,36 +212,30 @@
                         kSystemMenuKeyboardIcon);
 }
 
-void AccessibilityDetailedView::AppendHelpEntries() {
-  DCHECK(!UseMdMenu());
-}
-
 HoverHighlightView* AccessibilityDetailedView::AddScrollListItem(
     const base::string16& text,
     bool highlight,
     bool checked,
     const gfx::VectorIcon& icon) {
   HoverHighlightView* container = new HoverHighlightView(this);
-  if (UseMdMenu()) {
-    gfx::ImageSkia image = CreateVectorIcon(icon, kMenuIconColor);
-    const int padding = (kMenuButtonSize - image.width()) / 2;
-    container->AddIconAndLabelCustomSize(
-        image, text, highlight,
-        image.width() + kMenuSeparatorVerticalPadding * 2, padding, padding);
-    if (checked) {
-      gfx::ImageSkia check_mark = CreateVectorIcon(
-          gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700);
-      container->AddRightIcon(check_mark, check_mark.width());
-      container->SetRightViewVisible(true);
-      container->SetAccessiblityState(
-          HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX);
-    } else {
-      container->SetAccessiblityState(
-          HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
-    }
+  gfx::ImageSkia image = CreateVectorIcon(icon, kMenuIconColor);
+  const int padding = (kMenuButtonSize - image.width()) / 2;
+  container->AddIconAndLabelCustomSize(
+      image, text, highlight, image.width() + kMenuSeparatorVerticalPadding * 2,
+      padding, padding);
+
+  if (checked) {
+    gfx::ImageSkia check_mark =
+        CreateVectorIcon(gfx::VectorIconId::CHECK_CIRCLE, gfx::kGoogleGreen700);
+    container->AddRightIcon(check_mark, check_mark.width());
+    container->SetRightViewVisible(true);
+    container->SetAccessiblityState(
+        HoverHighlightView::AccessibilityState::CHECKED_CHECKBOX);
   } else {
-    container->AddCheckableLabel(text, highlight, checked);
+    container->SetAccessiblityState(
+        HoverHighlightView::AccessibilityState::UNCHECKED_CHECKBOX);
   }
+
   scroll_content()->AddChildView(container);
   return container;
 }
@@ -305,18 +288,16 @@
 }
 
 void AccessibilityDetailedView::CreateExtraTitleRowButtons() {
-  if (UseMdMenu()) {
-    DCHECK(!help_view_);
-    DCHECK(!settings_view_);
+  DCHECK(!help_view_);
+  DCHECK(!settings_view_);
 
-    tri_view()->SetContainerVisible(TriView::Container::END, true);
+  tri_view()->SetContainerVisible(TriView::Container::END, true);
 
-    help_view_ = CreateHelpButton(login_);
-    settings_view_ = CreateSettingsButton(
-        login_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS);
-    tri_view()->AddView(TriView::Container::END, help_view_);
-    tri_view()->AddView(TriView::Container::END, settings_view_);
-  }
+  help_view_ = CreateHelpButton(login_);
+  settings_view_ =
+      CreateSettingsButton(login_, IDS_ASH_STATUS_TRAY_ACCESSIBILITY_SETTINGS);
+  tri_view()->AddView(TriView::Container::END, help_view_);
+  tri_view()->AddView(TriView::Container::END, settings_view_);
 }
 
 void AccessibilityDetailedView::ShowSettings() {
diff --git a/ash/common/system/tray_accessibility.h b/ash/common/system/tray_accessibility.h
index 1b54962..79161797 100644
--- a/ash/common/system/tray_accessibility.h
+++ b/ash/common/system/tray_accessibility.h
@@ -75,11 +75,7 @@
   // Add the accessibility feature list.
   void AppendAccessibilityList();
 
-  // Add help entries. Only used for non-MD.
-  void AppendHelpEntries();
-
-  // Helper function to create entries in the detailed accessibility view. The
-  // |icon| parameter is used to create button icons for MD only.
+  // Helper function to create entries in the detailed accessibility view.
   HoverHighlightView* AddScrollListItem(const base::string16& text,
                                         bool highlight,
                                         bool checked,
diff --git a/ash/mus/non_client_frame_controller.cc b/ash/mus/non_client_frame_controller.cc
index c83c4ac..12b1639f 100644
--- a/ash/mus/non_client_frame_controller.cc
+++ b/ash/mus/non_client_frame_controller.cc
@@ -298,8 +298,6 @@
   widget_->Init(params);
   did_init_native_widget_ = true;
 
-  widget_->ShowInactive();
-
   WmWindow* wm_window = WmWindow::Get(window_);
   const gfx::Insets extended_hit_region =
       wm_window->ShouldUseExtendedHitRegion() ? GetExtendedHitRegion()
diff --git a/ash/mus/top_level_window_factory_unittest.cc b/ash/mus/top_level_window_factory_unittest.cc
index 2e016c1..2fb98002 100644
--- a/ash/mus/top_level_window_factory_unittest.cc
+++ b/ash/mus/top_level_window_factory_unittest.cc
@@ -2,10 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "ash/mus/top_level_window_factory.h"
+
+#include <stdint.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
 #include "ash/common/test/ash_test.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ash/mus/test/wm_test_base.h"
+#include "ash/mus/window_manager.h"
+#include "ash/mus/window_manager_application.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/test/ash_test_helper.h"
 #include "ui/aura/window.h"
 #include "ui/display/screen.h"
 
@@ -46,4 +58,15 @@
             GetDisplayId(window_secondary_display.get()));
 }
 
+using TopLevelWindowFactoryAshTest = test::AshTestBase;
+
+TEST_F(TopLevelWindowFactoryAshTest, TopLevelNotShownOnCreate) {
+  std::map<std::string, std::vector<uint8_t>> properties;
+  std::unique_ptr<aura::Window> window(mus::CreateAndParentTopLevelWindow(
+      ash_test_helper()->window_manager_app()->window_manager(),
+      ui::mojom::WindowType::WINDOW, &properties));
+  ASSERT_TRUE(window);
+  EXPECT_FALSE(window->IsVisible());
+}
+
 }  // namespace ash
diff --git a/ash/resources/ash_resources.grd b/ash/resources/ash_resources.grd
index b0882400..39588dd 100644
--- a/ash/resources/ash_resources.grd
+++ b/ash/resources/ash_resources.grd
@@ -86,7 +86,6 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NETWORK_NOTIFICATION_LTE" file="cros/network/notification_lte.png" />
 
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_MORE" file="cros/status/status_more.png" />
-      <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_OVERVIEW_MODE" file="cros/status/status_overview_mode.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SCREENSHARE" file="cros/status/status_screenshare.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SCREENSHARE_DARK" file="cros/status/status_screenshare_dark.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SHUTDOWN" file="cros/status/status_shutdown.png" />
@@ -123,7 +122,6 @@
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_RECORDING" file="cros/status/status_recording.png" />
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_RECORDING_RED" file="cros/status/status_recording_red.png" />
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_SETTINGS" file="cros/status/status_settings.png" />
-        <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_VIRTUAL_KEYBOARD" file="cros/status/status_virtual_keyboard.png" />
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_WIFI_DISABLED" file="cros/network/status_wifi_disabled.png" />
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_WIFI_DISABLED_HOVER" file="cros/network/status_wifi_disabled_hover.png" />
         <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_WIFI_ENABLED" file="cros/network/status_wifi_enabled.png" />
diff --git a/ash/resources/default_100_percent/cros/status/status_overview_mode.png b/ash/resources/default_100_percent/cros/status/status_overview_mode.png
deleted file mode 100644
index d145a94..0000000
--- a/ash/resources/default_100_percent/cros/status/status_overview_mode.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_100_percent/cros/status/status_virtual_keyboard.png b/ash/resources/default_100_percent/cros/status/status_virtual_keyboard.png
deleted file mode 100644
index 5cf6839..0000000
--- a/ash/resources/default_100_percent/cros/status/status_virtual_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_overview_mode.png b/ash/resources/default_200_percent/cros/status/status_overview_mode.png
deleted file mode 100644
index f684c7e..0000000
--- a/ash/resources/default_200_percent/cros/status/status_overview_mode.png
+++ /dev/null
Binary files differ
diff --git a/ash/resources/default_200_percent/cros/status/status_virtual_keyboard.png b/ash/resources/default_200_percent/cros/status/status_virtual_keyboard.png
deleted file mode 100644
index a882f85f..0000000
--- a/ash/resources/default_200_percent/cros/status/status_virtual_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 64e16eb3..0f0ba1e7 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -86,6 +86,11 @@
 
   display::Display GetSecondaryDisplay();
 
+  // Null in classic ash.
+  mus::WindowManagerApplication* window_manager_app() {
+    return window_manager_app_.get();
+  }
+
  private:
   // Called when running in mash to create the WindowManager.
   void CreateMashWindowManager();
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
index 94ff7d07..af4a6ef 100644
--- a/base/debug/stack_trace.cc
+++ b/base/debug/stack_trace.cc
@@ -20,6 +20,10 @@
 #include "base/threading/platform_thread.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include <pthread.h>
+#endif
+
 #if defined(OS_LINUX) && defined(__GLIBC__)
 extern "C" void* __libc_stack_end;
 #endif
@@ -42,56 +46,6 @@
 constexpr size_t kStackFrameAdjustment = 0;
 #endif
 
-// Returns end of the stack, or 0 if we couldn't get it.
-uintptr_t GetStackEnd() {
-#if defined(OS_ANDROID)
-  // Bionic reads proc/maps on every call to pthread_getattr_np() when called
-  // from the main thread. So we need to cache end of stack in that case to get
-  // acceptable performance.
-  // For all other threads pthread_getattr_np() is fast enough as it just reads
-  // values from its pthread_t argument.
-  static uintptr_t main_stack_end = 0;
-
-  bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId();
-  if (is_main_thread && main_stack_end) {
-    return main_stack_end;
-  }
-
-  uintptr_t stack_begin = 0;
-  size_t stack_size = 0;
-  pthread_attr_t attributes;
-  int error = pthread_getattr_np(pthread_self(), &attributes);
-  if (!error) {
-    error = pthread_attr_getstack(
-        &attributes,
-        reinterpret_cast<void**>(&stack_begin),
-        &stack_size);
-    pthread_attr_destroy(&attributes);
-  }
-  DCHECK(!error);
-
-  uintptr_t stack_end = stack_begin + stack_size;
-  if (is_main_thread) {
-    main_stack_end = stack_end;
-  }
-  return stack_end;  // 0 in case of error
-
-#elif defined(OS_LINUX) && defined(__GLIBC__)
-
-  if (GetCurrentProcId() == PlatformThread::CurrentId()) {
-    // For the main thread we have a shortcut.
-    return reinterpret_cast<uintptr_t>(__libc_stack_end);
-  }
-
-  // No easy way to get end of the stack for non-main threads,
-  // see crbug.com/617730.
-
-#endif
-
-  // Don't know how to get end of the stack.
-  return 0;
-}
-
 uintptr_t GetNextStackFrame(uintptr_t fp) {
   return reinterpret_cast<const uintptr_t*>(fp)[0] - kStackFrameAdjustment;
 }
@@ -192,6 +146,56 @@
 
 }  // namespace
 
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+uintptr_t GetStackEnd() {
+#if defined(OS_ANDROID)
+  // Bionic reads proc/maps on every call to pthread_getattr_np() when called
+  // from the main thread. So we need to cache end of stack in that case to get
+  // acceptable performance.
+  // For all other threads pthread_getattr_np() is fast enough as it just reads
+  // values from its pthread_t argument.
+  static uintptr_t main_stack_end = 0;
+
+  bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId();
+  if (is_main_thread && main_stack_end) {
+    return main_stack_end;
+  }
+
+  uintptr_t stack_begin = 0;
+  size_t stack_size = 0;
+  pthread_attr_t attributes;
+  int error = pthread_getattr_np(pthread_self(), &attributes);
+  if (!error) {
+    error = pthread_attr_getstack(
+        &attributes, reinterpret_cast<void**>(&stack_begin), &stack_size);
+    pthread_attr_destroy(&attributes);
+  }
+  DCHECK(!error);
+
+  uintptr_t stack_end = stack_begin + stack_size;
+  if (is_main_thread) {
+    main_stack_end = stack_end;
+  }
+  return stack_end;  // 0 in case of error
+
+#elif defined(OS_LINUX) && defined(__GLIBC__)
+
+  if (GetCurrentProcId() == PlatformThread::CurrentId()) {
+    // For the main thread we have a shortcut.
+    return reinterpret_cast<uintptr_t>(__libc_stack_end);
+  }
+
+// No easy way to get end of the stack for non-main threads,
+// see crbug.com/617730.
+#elif defined(OS_MACOSX)
+  return reinterpret_cast<uintptr_t>(pthread_get_stackaddr_np(pthread_self()));
+#endif
+
+  // Don't know how to get end of the stack.
+  return 0;
+}
+#endif  // HAVE_TRACE_STACK_FRAME_POINTERS
+
 StackTrace::StackTrace() : StackTrace(arraysize(trace_)) {}
 
 StackTrace::StackTrace(const void* const* trace, size_t count) {
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index ba1937fe..4c9b73e 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -45,6 +45,11 @@
 // done in official builds because it has security implications).
 BASE_EXPORT bool EnableInProcessStackDumping();
 
+// Returns end of the stack, or 0 if we couldn't get it.
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+BASE_EXPORT uintptr_t GetStackEnd();
+#endif
+
 // A stacktrace can be helpful in debugging. For example, you can include a
 // stacktrace member in a object (probably around #ifndef NDEBUG) so that you
 // can later see where the given object was created from.
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
index 0f1b5ac5..560dc1d 100644
--- a/base/debug/stack_trace_unittest.cc
+++ b/base/debug/stack_trace_unittest.cc
@@ -303,6 +303,16 @@
   ExpectStackFramePointers<kDepth>(frames, kDepth);
 }
 
+#if defined(OS_ANDROID) || defined(OS_MACOSX)
+#define MAYBE_StackEnd StackEnd
+#else
+#define MAYBE_StackEnd DISABLED_StackEnd
+#endif
+
+TEST_F(StackTraceTest, MAYBE_StackEnd) {
+  EXPECT_NE(0u, GetStackEnd());
+}
+
 #endif  // HAVE_TRACE_STACK_FRAME_POINTERS
 
 }  // namespace debug
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
index cc0a616..b468462 100644
--- a/base/files/important_file_writer.cc
+++ b/base/files/important_file_writer.cc
@@ -103,6 +103,7 @@
   File tmp_file(tmp_file_path, File::FLAG_OPEN | File::FLAG_WRITE);
   if (!tmp_file.IsValid()) {
     LogFailure(path, FAILED_OPENING, "could not open temporary file");
+    DeleteFile(tmp_file_path, false);
     return false;
   }
 
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
index 953a502..caa594dd 100644
--- a/base/ios/ios_util.h
+++ b/base/ios/ios_util.h
@@ -13,9 +13,6 @@
 namespace base {
 namespace ios {
 
-// Returns whether the operating system is iOS 9 or later.
-BASE_EXPORT bool IsRunningOnIOS9OrLater();
-
 // Returns whether the operating system is iOS 10 or later.
 BASE_EXPORT bool IsRunningOnIOS10OrLater();
 
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
index 4b702db..196d5ef 100644
--- a/base/ios/ios_util.mm
+++ b/base/ios/ios_util.mm
@@ -28,10 +28,6 @@
 namespace base {
 namespace ios {
 
-bool IsRunningOnIOS9OrLater() {
-  return IsRunningOnOrLater(9, 0, 0);
-}
-
 bool IsRunningOnIOS10OrLater() {
   return IsRunningOnOrLater(10, 0, 0);
 }
diff --git a/base/test/scoped_task_scheduler.cc b/base/test/scoped_task_scheduler.cc
index 7bcd88a..61ed2c7 100644
--- a/base/test/scoped_task_scheduler.cc
+++ b/base/test/scoped_task_scheduler.cc
@@ -70,6 +70,16 @@
   bool RunsTasksOnCurrentThread() const;
 
  private:
+  // Returns the TaskRunner to which this TaskScheduler forwards tasks. It may
+  // be |message_loop_->task_runner()| or a reference to it saved on entry to
+  // RunTask().
+  scoped_refptr<SingleThreadTaskRunner> MessageLoopTaskRunner() const {
+    if (saved_task_runner_)
+      return saved_task_runner_;
+    DCHECK(message_loop_->task_runner());
+    return message_loop_->task_runner();
+  }
+
   // |message_loop_owned_| will be non-null if this TestTaskScheduler owns the
   // MessageLoop (wasn't provided an external one at construction).
   // |message_loop_| will always be set and is used by this TestTaskScheduler to
@@ -77,6 +87,15 @@
   std::unique_ptr<MessageLoop> message_loop_owned_;
   MessageLoop* message_loop_;
 
+  // A reference to |message_loop_->task_runner()| saved on entry to RunTask().
+  // This is required because RunTask() overrides
+  // |message_loop_->task_runner()|.
+  //
+  // Note: |message_loop_->task_runner()| is accessed directly outside of
+  // RunTask() to guarantee that ScopedTaskScheduler always uses the latest
+  // TaskRunner set by external code.
+  scoped_refptr<SingleThreadTaskRunner> saved_task_runner_;
+
   // Handles shutdown behaviors and sets up the environment to run a task.
   internal::TaskTracker task_tracker_;
 
@@ -182,7 +201,7 @@
   if (!task_tracker_.WillPostTask(task.get()))
     return false;
   internal::Task* const task_ptr = task.get();
-  return message_loop_->task_runner()->PostDelayedTask(
+  return MessageLoopTaskRunner()->PostDelayedTask(
       task_ptr->posted_from, Bind(&TestTaskScheduler::RunTask, Unretained(this),
                                   Passed(&task), sequence_token),
       task_ptr->delay);
@@ -190,10 +209,11 @@
 
 void TestTaskScheduler::RunTask(std::unique_ptr<internal::Task> task,
                                 const SequenceToken& sequence_token) {
+  DCHECK(!saved_task_runner_);
+  saved_task_runner_ = MessageLoop::current()->task_runner();
+
   // Clear the MessageLoop TaskRunner to allow TaskTracker to register its own
   // Thread/SequencedTaskRunnerHandle as appropriate.
-  scoped_refptr<SingleThreadTaskRunner> saved_task_runner =
-      MessageLoop::current()->task_runner();
   MessageLoop::current()->ClearTaskRunnerForTesting();
 
   // Run the task.
@@ -201,12 +221,16 @@
                                              ? sequence_token
                                              : SequenceToken::Create());
 
+  // Make sure that any task runner that was registered was also cleaned up.
+  DCHECK(!MessageLoop::current()->task_runner());
+
   // Restore the MessageLoop TaskRunner.
-  MessageLoop::current()->SetTaskRunner(saved_task_runner);
+  MessageLoop::current()->SetTaskRunner(saved_task_runner_);
+  saved_task_runner_ = nullptr;
 }
 
 bool TestTaskScheduler::RunsTasksOnCurrentThread() const {
-  return message_loop_->task_runner()->RunsTasksOnCurrentThread();
+  return MessageLoopTaskRunner()->RunsTasksOnCurrentThread();
 }
 
 TestTaskSchedulerTaskRunner::TestTaskSchedulerTaskRunner(
diff --git a/base/test/scoped_task_scheduler_unittest.cc b/base/test/scoped_task_scheduler_unittest.cc
index cc0ffbb..f2037e1 100644
--- a/base/test/scoped_task_scheduler_unittest.cc
+++ b/base/test/scoped_task_scheduler_unittest.cc
@@ -297,5 +297,21 @@
   EXPECT_TRUE(second_task_ran);
 }
 
+// Verify that a task can be posted from a task running in ScopedTaskScheduler.
+TEST(ScopedTaskSchedulerTest, ReentrantTaskRunner) {
+  bool task_ran = false;
+  ScopedTaskScheduler scoped_task_scheduler;
+  PostTask(FROM_HERE, Bind(
+                          [](bool* task_ran) {
+                            PostTask(
+                                FROM_HERE,
+                                Bind([](bool* task_ran) { *task_ran = true; },
+                                     Unretained(task_ran)));
+                          },
+                          Unretained(&task_ran)));
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(task_ran);
+}
+
 }  // namespace test
 }  // namespace base
diff --git a/build/.gitignore b/build/.gitignore
new file mode 100644
index 0000000..103314c
--- /dev/null
+++ b/build/.gitignore
@@ -0,0 +1,20 @@
+# This file is needed for projects that has this directory as a separate Git
+# mirror in DEPS. Without it, a lot is wiped and re-downloaded for each sync.
+/android/bin
+/Debug
+/Debug_x64
+/goma
+/gomacc.lock
+/ipch/
+/Release
+/Release_x64
+/win_toolchain.json
+/util/LASTCHANGE*
+/util/support
+/x64/
+/linux/bin/eu-strip
+/linux/debian_*-sysroot/
+/linux/ubuntu_*-sysroot/
+/ios_files
+/mac_files
+
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index df5325f..0eacb3c 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -420,9 +420,12 @@
 
   java_files = _FilterJavaFiles(java_files, options.javac_includes)
 
-  javac_cmd = ['javac']
   if options.use_errorprone_path:
-    javac_cmd = [options.use_errorprone_path] + ERRORPRONE_OPTIONS
+    javac_path = options.use_errorprone_path
+    javac_cmd = [javac_path] + ERRORPRONE_OPTIONS
+  else:
+    javac_path = distutils.spawn.find_executable('javac')
+    javac_cmd = [javac_path]
 
   javac_cmd.extend((
       '-g',
@@ -473,8 +476,10 @@
         else:
           classpath_inputs.append(path)
 
-  # Compute the list of paths that when changed, we need to rebuild.
-  input_paths = classpath_inputs + options.java_srcjars + java_files
+  # GN already knows of java_files, so listing them just make things worse when
+  # they change.
+  depfile_deps = [javac_path] + classpath_inputs + options.java_srcjars
+  input_paths = depfile_deps + java_files
 
   output_paths = [
       options.jar_path,
@@ -493,6 +498,7 @@
       lambda changes: _OnStaleMd5(changes, options, javac_cmd, java_files,
                                   classpath_inputs),
       options,
+      depfile_deps=depfile_deps,
       input_paths=input_paths,
       input_strings=javac_cmd,
       output_paths=output_paths,
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index 0066fe24..33882a2 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -21,12 +21,14 @@
   Note: PRODUCT_DIR will be substituted at run-time with actual
   directory path (e.g. out/Debug)
 -->
+  <!-- AllowBackup defaults to true, and causes a lint warning if not explicitly set. -->
   <issue id="AllowBackup">
     <ignore path="AndroidManifest.xml"/>
   </issue>
+  <!-- We use asserts in Chromium. See https://chromium.googlesource.com/chromium/src/+/master/styleguide/java/java.md#Asserts -->
   <issue id="Assert" severity="ignore"/>
-  <!-- TODO(crbug.com/635567): Fix this properly. -->
   <issue id="BadHostnameVerifier" severity="Error">
+    <!-- Safe, used in test only. -->
     <ignore regexp="net/test/android/javatests/src/org/chromium/net/test/util/TestWebServer.java"/>
   </issue>
   <issue id="ButtonOrder" severity="Error">
@@ -73,12 +75,6 @@
   </issue>
   <issue id="HandlerLeak">
     <ignore regexp="android_webview/glue/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java" />
-    <!-- TODO(crbug.com/635567): Fix this properly. -->
-    <ignore regexp="chrome/android/java/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutHelper.java"/>
-    <!-- TODO(crbug.com/635567): Fix this properly. -->
-    <ignore regexp="chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java"/>
-    <!-- TODO(crbug.com/635567): Fix this properly. -->
-    <ignore regexp="chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java"/>
     <ignore regexp="chromecast/internal" />
     <ignore regexp="remoting/android/java/src/org/chromium/chromoting/TapGestureDetector.java" />
   </issue>
diff --git a/build/android/pylib/OWNERS b/build/android/pylib/OWNERS
index dbbbba7..f008c99 100644
--- a/build/android/pylib/OWNERS
+++ b/build/android/pylib/OWNERS
@@ -2,3 +2,5 @@
 klundberg@chromium.org
 navabi@chromium.org
 skyostil@chromium.org
+
+# COMPONENT: Test>Android
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3b31bd7..8f57120 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1602,7 +1602,12 @@
 # Full symbols.
 config("symbols") {
   if (is_win) {
-    cflags = [ "/Zi" ]  # Produce PDB file, no edit and continue.
+    if (use_goma) {
+      # Note that this requires is_win_fastlink, enforced elsewhere.
+      cflags = [ "/Z7" ]  # Debug information in the .obj files.
+    } else {
+      cflags = [ "/Zi" ]  # Produce PDB file, no edit and continue.
+    }
 
     if (is_win_fastlink) {
       # Tell VS 2015+ to create a PDB that references debug
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index b07a507..787990a 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -98,6 +98,8 @@
     # by visual studio (repeated in every .obj file) makes linker
     # memory consumption and link times unsustainable (crbug.com/630074).
     # Clang on windows does not have this issue.
+    # If you use is_win_fastlink = true then you can set symbol_level = 2 when
+    # using goma.
     symbol_level = 1
   } else if ((!is_nacl && !is_linux) || is_debug || is_official_build ||
              is_chromecast) {
@@ -111,6 +113,12 @@
   } else {
     symbol_level = 0
   }
+} else if (symbol_level == 2) {
+  if (is_win) {
+    # See crbug.com/630074
+    assert(is_win_fastlink || !use_goma,
+           "Goma builds that use symbol_level 2 must use is_win_fastlink.")
+  }
 }
 
 # Assert that the configuration isn't going to hit https://crbug.com/648948.
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index 67d7adf..32db1424 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -223,7 +223,12 @@
       fi
     fi
     ;;
-  *)
+  "precise")
+    arm_list="libc6-dev-armhf-cross
+              linux-libc-dev-armhf-cross
+              ${GPP_ARM_PACKAGE}"
+    ;;
+  "*")
     arm_list="binutils-aarch64-linux-gnu
               libc6-dev-armhf-cross
               linux-libc-dev-armhf-cross
diff --git a/cc/animation/animation_host_perftest.cc b/cc/animation/animation_host_perftest.cc
index a7c6e898..776a687 100644
--- a/cc/animation/animation_host_perftest.cc
+++ b/cc/animation/animation_host_perftest.cc
@@ -56,7 +56,7 @@
     return layer_tree_host_->host_impl()->animation_host();
   }
 
-  void CreatePlayers(const int num_players) {
+  void CreatePlayers(int num_players) {
     all_players_timeline_ =
         AnimationTimeline::Create(AnimationIdProvider::NextTimelineId());
     host()->AddAnimationTimeline(all_players_timeline_);
@@ -89,7 +89,7 @@
       EXPECT_TRUE(timeline_impl->GetPlayerById(i));
   }
 
-  void CreateTimelines(const int num_timelines) {
+  void CreateTimelines(int num_timelines) {
     first_timeline_id_ = AnimationIdProvider::NextTimelineId();
     last_timeline_id_ = first_timeline_id_;
 
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 044992c..19b72bad 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -70,7 +70,7 @@
  public:
   FixedInvalidationPictureLayerTilingClient(
       PictureLayerTilingClient* base_client,
-      const Region invalidation)
+      const Region& invalidation)
       : base_client_(base_client), invalidation_(invalidation) {}
 
   std::unique_ptr<Tile> CreateTile(const Tile::CreateInfo& info) override {
diff --git a/cc/input/page_scale_animation.h b/cc/input/page_scale_animation.h
index 4884098..b58f50b 100644
--- a/cc/input/page_scale_animation.h
+++ b/cc/input/page_scale_animation.h
@@ -20,15 +20,14 @@
 // Used in the CC to pass around a scale animation that hasn't yet been
 // initialized.
 struct PendingPageScaleAnimation {
-  PendingPageScaleAnimation(
-      const gfx::Vector2d _target_offset,
-      bool _use_anchor,
-      float _scale,
-      const base::TimeDelta& _duration)
-      : target_offset(_target_offset),
-        use_anchor(_use_anchor),
-        scale(_scale),
-        duration(_duration) {}
+  PendingPageScaleAnimation(const gfx::Vector2d& target_offset,
+                            bool use_anchor,
+                            float scale,
+                            const base::TimeDelta& duration)
+      : target_offset(target_offset),
+        use_anchor(use_anchor),
+        scale(scale),
+        duration(duration) {}
   gfx::Vector2d target_offset;
   bool use_anchor;
   float scale;
diff --git a/cc/input/scroll_state.h b/cc/input/scroll_state.h
index 6df0b74..384a934 100644
--- a/cc/input/scroll_state.h
+++ b/cc/input/scroll_state.h
@@ -61,10 +61,11 @@
     data_.is_direct_manipulation = is_direct_manipulation;
   }
 
-  void set_scroll_chain_and_layer_tree(std::list<ScrollNode*>* scroll_chain,
-                                       LayerTreeImpl* layer_tree_impl) {
+  void set_scroll_chain_and_layer_tree(
+      const std::list<ScrollNode*>& scroll_chain,
+      LayerTreeImpl* layer_tree_impl) {
     layer_tree_impl_ = layer_tree_impl;
-    scroll_chain_ = *scroll_chain;
+    scroll_chain_ = scroll_chain;
   }
 
   void set_current_native_scrolling_node(ScrollNode* scroll_node) {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index a454c4c..ce209fd 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -1030,7 +1030,7 @@
 
 class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
  public:
-  void TestResourceUpload(const float test_scale) {
+  void TestResourceUpload(float test_scale) {
     gfx::Point scrollbar_location(0, 185);
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
     scoped_refptr<Layer> content_layer = Layer::Create();
@@ -1099,7 +1099,7 @@
 
 class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
  public:
-  void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
+  void TestScale(const gfx::Rect& scrollbar_rect, float test_scale) {
     bool paint_during_update = true;
     bool has_thumb = false;
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 477a88a..60c09db 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -2603,12 +2603,7 @@
                   FlippedRootFramebuffer() ? flipped_y_pos_of_rect_bottom
                                            : swap_buffer_rect_.y(),
                   swap_buffer_rect_.width(), swap_buffer_rect_.height());
-  } else {
-    // Expand the swap rect to the full surface unless it's empty, and empty
-    // swap is allowed.
-    if (!swap_buffer_rect_.IsEmpty() || !allow_empty_swap_) {
-      swap_buffer_rect_ = gfx::Rect(surface_size);
-    }
+  } else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) {
     output_frame.sub_buffer_rect = swap_buffer_rect_;
   }
 
diff --git a/cc/output/output_surface_frame.h b/cc/output/output_surface_frame.h
index 2306f2e..331496f 100644
--- a/cc/output/output_surface_frame.h
+++ b/cc/output/output_surface_frame.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "cc/base/cc_export.h"
 #include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/rect.h"
@@ -26,7 +27,8 @@
   OutputSurfaceFrame& operator=(OutputSurfaceFrame&& other);
 
   gfx::Size size;
-  gfx::Rect sub_buffer_rect;
+  // Optional rect for partial or empty swap; if not provided, use regular swap.
+  base::Optional<gfx::Rect> sub_buffer_rect;
   std::vector<ui::LatencyInfo> latency_info;
 
  private:
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index cafd10b..07cd5b7 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -45,15 +45,6 @@
   last_sent_frame_.reset(new OutputSurfaceFrame(std::move(frame)));
   ++num_sent_frames_;
 
-  if (context_provider()) {
-    last_swap_rect_ = last_sent_frame_->sub_buffer_rect;
-    last_swap_rect_valid_ = true;
-  } else {
-    // Unknown for direct software frames.
-    last_swap_rect_ = gfx::Rect();
-    last_swap_rect_valid_ = false;
-  }
-
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&FakeOutputSurface::SwapBuffersAck,
                             weak_ptr_factory_.GetWeakPtr()));
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 4a83f8d..bf8ef86 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -93,11 +93,6 @@
     suspended_for_recycle_ = suspended;
   }
 
-  gfx::Rect last_swap_rect() const {
-    DCHECK(last_swap_rect_valid_);
-    return last_swap_rect_;
-  }
-
   const gfx::ColorSpace& last_reshape_color_space() {
     return last_reshape_color_space_;
   }
@@ -115,8 +110,6 @@
   GLint framebuffer_ = 0;
   GLenum framebuffer_format_ = 0;
   OverlayCandidateValidator* overlay_candidate_validator_ = nullptr;
-  bool last_swap_rect_valid_ = false;
-  gfx::Rect last_swap_rect_;
   gfx::ColorSpace last_reshape_color_space_;
 
  private:
diff --git a/cc/test/pixel_comparator.h b/cc/test/pixel_comparator.h
index 7228858..c711673 100644
--- a/cc/test/pixel_comparator.h
+++ b/cc/test/pixel_comparator.h
@@ -40,12 +40,12 @@
 // computes average and maximum absolute errors per color channel.
 class FuzzyPixelComparator : public PixelComparator {
  public:
-  FuzzyPixelComparator(const bool discard_alpha,
-                       const float error_pixels_percentage_limit,
-                       const float small_error_pixels_percentage_limit,
-                       const float avg_abs_error_limit,
-                       const int max_abs_error_limit,
-                       const int small_error_threshold);
+  FuzzyPixelComparator(bool discard_alpha,
+                       float error_pixels_percentage_limit,
+                       float small_error_pixels_percentage_limit,
+                       float avg_abs_error_limit,
+                       int max_abs_error_limit,
+                       int small_error_threshold);
   ~FuzzyPixelComparator() override {}
 
   // Computes error metrics and returns true if the errors don't exceed the
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 1dcc40c..d5b3148d4 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -614,14 +614,13 @@
       MemoryAllocatorDump* dump =
           image_data->decode.data()->CreateMemoryAllocatorDump(
               discardable_dump_name.c_str(), pmd);
-      // If our image is locked, dump the "locked_size" as an additional
-      // column.
+      // Dump the "locked_size" as an additional column.
       // This lets us see the amount of discardable which is contributing to
       // memory pressure.
-      if (image_data->decode.is_locked()) {
-        dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
-                        image_data->size);
-      }
+      size_t locked_size =
+          image_data->decode.is_locked() ? image_data->size : 0u;
+      dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
+                      locked_size);
     }
 
     // If we have an uploaded image (that is actually on the GPU, not just a
diff --git a/cc/tiles/image_controller.cc b/cc/tiles/image_controller.cc
index 5de6e348..6fb503aa 100644
--- a/cc/tiles/image_controller.cc
+++ b/cc/tiles/image_controller.cc
@@ -77,9 +77,10 @@
     ImageDecodeRequestId id = request_to_complete.first;
     ImageDecodeRequest& request = request_to_complete.second;
 
-    // The task (if one exists) would have run already, so we just need to
-    // complete it.
-    if (request.task)
+    // The task (if one exists) would have run already, we just need to make
+    // sure it was completed. Multiple requests for the same image use the same
+    // task so it could have already been completed.
+    if (request.task && !request.task->HasCompleted())
       request.task->DidComplete();
 
     // Issue the callback, and unref the image immediately. This is so that any
@@ -106,7 +107,9 @@
       // several different image deque requests for the same image.
       if (request.task->state().IsNew())
         request.task->state().DidCancel();
-      request.task->DidComplete();
+
+      if (!request.task->HasCompleted())
+        request.task->DidComplete();
     }
     // Run the callback and unref the image.
     request.callback.Run(id);
@@ -116,11 +119,14 @@
 }
 
 void ImageController::SetImageDecodeCache(ImageDecodeCache* cache) {
+  DCHECK(!cache_ || !cache);
+
   if (!cache) {
     SetPredecodeImages(std::vector<DrawImage>(),
                        ImageDecodeCache::TracingInfo());
     StopWorkerTasks();
   }
+
   cache_ = cache;
 }
 
diff --git a/cc/tiles/image_controller_unittest.cc b/cc/tiles/image_controller_unittest.cc
index ddd5376..cd34155 100644
--- a/cc/tiles/image_controller_unittest.cc
+++ b/cc/tiles/image_controller_unittest.cc
@@ -447,5 +447,31 @@
   EXPECT_EQ(0, cache()->number_of_refs());
 }
 
+TEST_F(ImageControllerTest, DispatchesDecodeCallbacksAfterCacheChanged) {
+  scoped_refptr<SimpleTask> task(new SimpleTask);
+  cache()->SetTaskToUse(task);
+
+  base::RunLoop run_loop1;
+  DecodeClient decode_client1;
+  base::RunLoop run_loop2;
+  DecodeClient decode_client2;
+
+  controller()->QueueImageDecode(
+      image(),
+      base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client1),
+                 run_loop1.QuitClosure()));
+  controller()->QueueImageDecode(
+      image(),
+      base::Bind(&DecodeClient::Callback, base::Unretained(&decode_client2),
+                 run_loop2.QuitClosure()));
+
+  // Now reset the image cache before decode completed callbacks are posted to
+  // the compositor thread. Ensure that the completion callbacks for the decode
+  // is still run.
+  controller()->SetImageDecodeCache(nullptr);
+  RunOrTimeout(&run_loop1);
+  RunOrTimeout(&run_loop2);
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/tiles/prioritized_tile.cc b/cc/tiles/prioritized_tile.cc
index 37da3a98..a76963d3 100644
--- a/cc/tiles/prioritized_tile.cc
+++ b/cc/tiles/prioritized_tile.cc
@@ -13,7 +13,7 @@
 
 PrioritizedTile::PrioritizedTile(Tile* tile,
                                  const PictureLayerTiling* source_tiling,
-                                 const TilePriority priority,
+                                 const TilePriority& priority,
                                  bool is_occluded,
                                  bool is_process_for_images_only)
     : tile_(tile),
diff --git a/cc/tiles/prioritized_tile.h b/cc/tiles/prioritized_tile.h
index 30159784..db7967e 100644
--- a/cc/tiles/prioritized_tile.h
+++ b/cc/tiles/prioritized_tile.h
@@ -22,7 +22,7 @@
   PrioritizedTile();
   PrioritizedTile(Tile* tile,
                   const PictureLayerTiling* source_tiling,
-                  const TilePriority priority,
+                  const TilePriority& priority,
                   bool is_occluded,
                   bool is_process_for_images_only);
   ~PrioritizedTile();
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 0169819..e5d3319c 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -97,7 +97,7 @@
   ImageDecodeTaskImpl(SoftwareImageDecodeCache* cache,
                       const SoftwareImageDecodeCache::ImageKey& image_key,
                       const DrawImage& image,
-                      const SoftwareImageDecodeCache::DecodeTaskType task_type,
+                      SoftwareImageDecodeCache::DecodeTaskType task_type,
                       const ImageDecodeCache::TracingInfo& tracing_info)
       : TileTask(true),
         cache_(cache),
@@ -864,15 +864,15 @@
         reinterpret_cast<uintptr_t>(this), cache_name,
         image_pair.second->tracing_id(), image_pair.first.image_id());
     // CreateMemoryAllocatorDump will automatically add tracking values for the
-    // total size. If locked, we also add a "locked_size" below.
+    // total size. We also add a "locked_size" below.
     MemoryAllocatorDump* dump =
         image_pair.second->memory()->CreateMemoryAllocatorDump(
             dump_name.c_str(), pmd);
     DCHECK(dump);
-    if (image_pair.second->is_locked()) {
-      dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
-                      image_pair.first.locked_bytes());
-    }
+    size_t locked_bytes =
+        image_pair.second->is_locked() ? image_pair.first.locked_bytes() : 0u;
+    dump->AddScalar("locked_size", MemoryAllocatorDump::kUnitsBytes,
+                    locked_bytes);
   }
 }
 
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 50b04fb..fc53daf9 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2568,7 +2568,7 @@
 
   // Walk up the hierarchy and look for a scrollable layer.
   ScrollTree& scroll_tree = active_tree_->property_trees()->scroll_tree;
-  LayerImpl* potentially_scrolling_layer_impl = nullptr;
+  ScrollNode* impl_scroll_node = nullptr;
   if (layer_impl) {
     ScrollNode* scroll_node = scroll_tree.Node(layer_impl->scroll_tree_index());
     for (; scroll_tree.parent(scroll_node);
@@ -2584,9 +2584,8 @@
       }
 
       if (status.thread == InputHandler::SCROLL_ON_IMPL_THREAD &&
-          !potentially_scrolling_layer_impl) {
-        potentially_scrolling_layer_impl =
-            active_tree_->LayerById(scroll_node->owning_layer_id);
+          !impl_scroll_node) {
+        impl_scroll_node = scroll_node;
       }
     }
   }
@@ -2594,25 +2593,34 @@
   // Falling back to the viewport layer ensures generation of root overscroll
   // notifications. We use the viewport's main scroll layer to represent the
   // viewport in scrolling code.
-  if (!potentially_scrolling_layer_impl ||
-      potentially_scrolling_layer_impl == OuterViewportScrollLayer() ||
-      potentially_scrolling_layer_impl == InnerViewportScrollLayer()) {
-    potentially_scrolling_layer_impl = viewport()->MainScrollLayer();
+  bool scrolls_inner_viewport =
+      impl_scroll_node && InnerViewportScrollLayer() &&
+      InnerViewportScrollLayer()->scroll_tree_index() == impl_scroll_node->id;
+  bool scrolls_outer_viewport =
+      impl_scroll_node && OuterViewportScrollLayer() &&
+      OuterViewportScrollLayer()->scroll_tree_index() == impl_scroll_node->id;
+  if (!impl_scroll_node || scrolls_inner_viewport || scrolls_outer_viewport) {
+    if (auto* mainScrollLayer = viewport()->MainScrollLayer())
+      impl_scroll_node = scroll_tree.Node(mainScrollLayer->scroll_tree_index());
+    else
+      impl_scroll_node = nullptr;
   }
 
-  if (potentially_scrolling_layer_impl) {
+  if (impl_scroll_node) {
     // Ensure that final layer scrolls on impl thread (crbug.com/625100)
-    ScrollNode* scroll_node =
-        scroll_tree.Node(potentially_scrolling_layer_impl->scroll_tree_index());
     ScrollStatus status =
-        TryScroll(device_viewport_point, type, scroll_tree, scroll_node);
-    if (IsMainThreadScrolling(status, scroll_node)) {
+        TryScroll(device_viewport_point, type, scroll_tree, impl_scroll_node);
+    if (IsMainThreadScrolling(status, impl_scroll_node)) {
       *scroll_on_main_thread = true;
       *main_thread_scrolling_reasons = status.main_thread_scrolling_reasons;
     }
   }
 
-  return potentially_scrolling_layer_impl;
+  // TODO(pdr): Refactor this function to directly return |impl_scroll_node|
+  // instead of using ScrollNode's owning_layer_id to return a LayerImpl.
+  if (!impl_scroll_node)
+    return nullptr;
+  return active_tree_->LayerById(impl_scroll_node->owning_layer_id);
 }
 
 static bool IsClosestScrollAncestor(LayerImpl* child,
@@ -2864,33 +2872,32 @@
   // that ScrollBy uses for non-animated wheel scrolls.
   scroll_status = ScrollBegin(&scroll_state, WHEEL);
   scroll_node = scroll_tree.CurrentlyScrollingNode();
-  if (scroll_status.thread == SCROLL_ON_IMPL_THREAD) {
+  if (scroll_status.thread == SCROLL_ON_IMPL_THREAD && scroll_node) {
     gfx::Vector2dF pending_delta = scroll_delta;
-    if (scroll_node) {
-      for (; scroll_tree.parent(scroll_node);
-           scroll_node = scroll_tree.parent(scroll_node)) {
-        if (!scroll_node->scrollable)
-          continue;
+    for (; scroll_tree.parent(scroll_node);
+         scroll_node = scroll_tree.parent(scroll_node)) {
+      if (!scroll_node->scrollable)
+        continue;
 
-        if (viewport()->MainScrollLayer() &&
-            scroll_node->owning_layer_id ==
-                viewport()->MainScrollLayer()->id()) {
-          gfx::Vector2dF scrolled =
-              viewport()->ScrollAnimated(pending_delta, delayed_by);
-          // Viewport::ScrollAnimated returns pending_delta as long as it
-          // starts an animation.
-          if (scrolled == pending_delta)
-            return scroll_status;
-          break;
-        }
-
-        gfx::Vector2dF scroll_delta =
-            ComputeScrollDelta(scroll_node, pending_delta);
-        if (ScrollAnimationCreate(scroll_node, scroll_delta, delayed_by))
+      bool scrolls_main_viewport_scroll_layer =
+          viewport()->MainScrollLayer() &&
+          viewport()->MainScrollLayer()->scroll_tree_index() == scroll_node->id;
+      if (scrolls_main_viewport_scroll_layer) {
+        gfx::Vector2dF scrolled =
+            viewport()->ScrollAnimated(pending_delta, delayed_by);
+        // Viewport::ScrollAnimated returns pending_delta as long as it starts
+        // an animation.
+        if (scrolled == pending_delta)
           return scroll_status;
-
-        pending_delta -= scroll_delta;
+        break;
       }
+
+      gfx::Vector2dF scroll_delta =
+          ComputeScrollDelta(scroll_node, pending_delta);
+      if (ScrollAnimationCreate(scroll_node, scroll_delta, delayed_by))
+        return scroll_status;
+
+      pending_delta -= scroll_delta;
     }
   }
   scroll_state.set_is_ending(true);
@@ -3020,23 +3027,23 @@
   // details.
   const float kEpsilon = 0.1f;
 
-  bool is_viewport_scroll_layer =
+  bool scrolls_main_viewport_scroll_layer =
       viewport()->MainScrollLayer() &&
-      scroll_node->owning_layer_id == viewport()->MainScrollLayer()->id();
+      viewport()->MainScrollLayer()->scroll_tree_index() == scroll_node->id;
 
   // This is needed if the scroll chains up to the viewport without going
-  // through the outer viewport scroll layer. This can happen if we scroll an
+  // through the outer viewport scroll node. This can happen if we scroll an
   // element that's not a descendant of the document.rootScroller. In that case
   // we want to scroll the inner viewport -- to allow panning while zoomed --
   // but also move browser controls if needed.
-  bool is_inner_viewport_scroll_layer =
+  bool scrolls_inner_viewport_layer =
       InnerViewportScrollLayer() &&
-      scroll_node->owning_layer_id == InnerViewportScrollLayer()->id();
+      InnerViewportScrollLayer()->scroll_tree_index() == scroll_node->id;
 
-  if (is_viewport_scroll_layer || is_inner_viewport_scroll_layer) {
+  if (scrolls_main_viewport_scroll_layer || scrolls_inner_viewport_layer) {
     Viewport::ScrollResult result = viewport()->ScrollBy(
         delta, viewport_point, scroll_state->is_direct_manipulation(),
-        !wheel_scrolling_, is_viewport_scroll_layer);
+        !wheel_scrolling_, scrolls_main_viewport_scroll_layer);
 
     applied_delta = result.consumed_delta;
     delta_applied_to_content = result.content_scrolled_delta;
@@ -3054,12 +3061,12 @@
     // TODO(bokan): This preserves existing behavior by not allowing tiny
     // scrolls to produce overscroll but is inconsistent in how delta gets
     // chained up. We need to clean this up.
-    if (is_viewport_scroll_layer)
+    if (scrolls_main_viewport_scroll_layer)
       scroll_state->ConsumeDelta(applied_delta.x(), applied_delta.y());
     return;
   }
 
-  if (!is_viewport_scroll_layer && !is_inner_viewport_scroll_layer) {
+  if (!scrolls_main_viewport_scroll_layer && !scrolls_inner_viewport_layer) {
     // If the applied delta is within 45 degrees of the input
     // delta, bail out to make it easier to scroll just one layer
     // in one direction without affecting any of its parents.
@@ -3115,7 +3122,7 @@
       current_scroll_chain.push_front(scroll_node);
     }
   }
-  scroll_state->set_scroll_chain_and_layer_tree(&current_scroll_chain,
+  scroll_state->set_scroll_chain_and_layer_tree(current_scroll_chain,
                                                 active_tree());
   scroll_state->DistributeToScrollChainDescendant();
 }
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 8cb13e9..9f545a5 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -1865,7 +1865,7 @@
     PostSetNeedsCommitToMainThread();
   }
 
-  void BindInputHandler(const base::WeakPtr<InputHandler> input_handler) {
+  void BindInputHandler(base::WeakPtr<InputHandler> input_handler) {
     DCHECK(task_runner_provider()->IsImplThread());
     input_handler->BindToClient(&input_handler_client_);
     scroll_elasticity_helper_ = input_handler->CreateScrollElasticityHelper();
diff --git a/chrome/android/java/res/menu/chrome_context_menu.xml b/chrome/android/java/res/menu/chrome_context_menu.xml
index 4591cdce..fd64b75 100644
--- a/chrome/android/java/res/menu/chrome_context_menu.xml
+++ b/chrome/android/java/res/menu/chrome_context_menu.xml
@@ -4,6 +4,14 @@
      found in the LICENSE file. -->
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <group android:id="@+id/contextmenu_group_tab_cct">
+        <item android:id="@+id/contextmenu_open_in_new_chrome_tab"
+	    android:title="@string/contextmenu_open_in_new_chrome_tab"/>
+        <item android:id="@+id/contextmenu_open_in_chrome_incognito_tab"
+	    android:title="@string/contextmenu_open_in_chrome_incognito_tab"/>
+        <item android:id="@+id/contextmenu_open_in_browser_id"
+            android:title=""/>
+    </group>
     <group android:id="@+id/contextmenu_group_anchor">
         <item android:id="@+id/contextmenu_load_images"
             android:title="@string/contextmenu_load_images"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index ada13e5..a186f87 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -151,7 +151,9 @@
 import org.chromium.ui.base.WindowAndroid;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import javax.annotation.Nullable;
@@ -254,7 +256,7 @@
 
     // A set of views obscuring all tabs. When this set is nonempty,
     // all tab content will be hidden from the accessibility tree.
-    private List<View> mViewsObscuringAllTabs = new ArrayList<>();
+    private Set<View> mViewsObscuringAllTabs = new HashSet<>();
 
     // See enableHardwareAcceleration()
     private boolean mSetWindowHWA;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
new file mode 100644
index 0000000..16f7b1ed
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -0,0 +1,104 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+
+import java.util.ArrayList;
+import java.util.concurrent.ExecutionException;
+
+/**
+ * A utility class for querying information about the default browser setting.
+ */
+public class DefaultBrowserInfo {
+    private static final String SAMPLE_URL = "http://www.madeupdomainforcheck123.com/";
+
+    /** A lock to synchronize background tasks to retrieve browser information. */
+    private static final Object sDirCreationLock = new Object();
+
+    private static AsyncTask<Void, Void, ArrayList<String>> sDefaultBrowserFetcher;
+
+    /**
+     * Initialize an AsyncTask for getting menu title of opening a link in default browser.
+     */
+    public static void initBrowserFetcher() {
+        synchronized (sDirCreationLock) {
+            if (sDefaultBrowserFetcher == null) {
+                sDefaultBrowserFetcher = new AsyncTask<Void, Void, ArrayList<String>>() {
+                    @Override
+                    protected ArrayList<String> doInBackground(Void... params) {
+                        Context context = ContextUtils.getApplicationContext();
+                        ArrayList<String> menuTitles = new ArrayList<String>(2);
+                        // Store the package label of current application.
+                        menuTitles.add(BuildInfo.getPackageLabel(context));
+
+                        PackageManager pm = context.getPackageManager();
+                        ResolveInfo info = getResolveInfoForViewIntent(pm);
+
+                        // Caches whether Chrome is set as a default browser on the device.
+                        boolean isDefault = (info != null && info.match != 0
+                                && context.getPackageName().equals(info.activityInfo.packageName));
+                        ChromePreferenceManager.getInstance().setCachedChromeDefaultBrowser(
+                                isDefault);
+
+                        // Check if there is a default handler for the Intent.  If so, store its
+                        // label.
+                        String packageLabel = null;
+                        if (info != null && info.match != 0 && info.loadLabel(pm) != null) {
+                            packageLabel = info.loadLabel(pm).toString();
+                        }
+                        if (packageLabel == null) {
+                            menuTitles.add(
+                                    context.getString(R.string.menu_open_in_product_default));
+                        } else {
+                            menuTitles.add(
+                                    context.getString(R.string.menu_open_in_product, packageLabel));
+                        }
+                        return menuTitles;
+                    }
+                };
+                sDefaultBrowserFetcher.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+            }
+        }
+    }
+
+    /**
+     * @return Default ResolveInfo to handle a VIEW intent for a url.
+     * @param pm The PackageManager of current context.
+     */
+    public static ResolveInfo getResolveInfoForViewIntent(PackageManager pm) {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(SAMPLE_URL));
+        return pm.resolveActivity(intent, 0);
+    }
+
+    /**
+     * @return Title of the menu item for opening a link in the default browser.
+     * @param forceChromeAsDefault Whether the Custom Tab is created by Chrome.
+     */
+    public static String getTitleOpenInDefaultBrowser(final boolean forceChromeAsDefault) {
+        if (sDefaultBrowserFetcher == null) {
+            initBrowserFetcher();
+        }
+        try {
+            // If the Custom Tab was created by Chrome, Chrome should handle the action for the
+            // overflow menu.
+            return forceChromeAsDefault ? sDefaultBrowserFetcher.get().get(0)
+                                        : sDefaultBrowserFetcher.get().get(1);
+        } catch (InterruptedException | ExecutionException e) {
+            return ContextUtils.getApplicationContext().getString(
+                    R.string.menu_open_in_product_default);
+        }
+    }
+}
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 e713649..d6ea4b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -5,10 +5,7 @@
 package org.chromium.chrome.browser;
 
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Looper;
 import android.os.MessageQueue;
@@ -176,6 +173,8 @@
                 // Punt all tasks that may block on disk off onto a background thread.
                 initAsyncDiskTask();
 
+                DefaultBrowserInfo.initBrowserFetcher();
+
                 AfterStartupTaskUtils.setStartupComplete();
 
                 PartnerBrowserCustomizations.setOnInitializeAsyncFinished(new Runnable() {
@@ -283,8 +282,6 @@
 
                     removeSnapshotDatabase();
 
-                    cacheIsChromeDefaultBrowser();
-
                     // Warm up all web app shared prefs. This must be run after the WebappRegistry
                     // instance is initialized.
                     WebappRegistry.warmUpSharedPrefs();
@@ -320,20 +317,6 @@
     }
 
     /**
-     * Caches whether Chrome is set as a default browser on the device.
-     */
-    @WorkerThread
-    private void cacheIsChromeDefaultBrowser() {
-        // Retrieve whether Chrome is default in background to avoid strict mode checks.
-        Intent intent = new Intent(Intent.ACTION_VIEW,
-                Uri.parse("http://www.madeupdomainforcheck123.com/"));
-        ResolveInfo info = mAppContext.getPackageManager().resolveActivity(intent, 0);
-        boolean isDefault = (info != null && info.match != 0
-                && mAppContext.getPackageName().equals(info.activityInfo.packageName));
-        ChromePreferenceManager.getInstance().setCachedChromeDefaultBrowser(isDefault);
-    }
-
-    /**
      * Deletes the snapshot database which is no longer used because the feature has been removed
      * in Chrome M41.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
index dac0669..769b930 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -587,15 +587,17 @@
     @CalledByNative
     public static String getScopeFromUrl(String url) {
         // Scope URL is generated by:
-        // - Removing last component of the URL.
+        // - Removing last component of the URL if it does not end with a slash.
         // - Clearing the URL's query and fragment.
 
         Uri uri = Uri.parse(url);
         List<String> path = uri.getPathSegments();
         int endIndex = path.size();
 
-        // If there is at least one path element, remove the last one.
-        if (endIndex > 0) {
+        // Remove the last path element if there is at least one path element, *and* the path does
+        // not end with a slash. This means that URLs to specific files have the file component
+        // removed, but URLs to directories retain the directory.
+        if (endIndex > 0 && !uri.getPath().endsWith("/")) {
             endIndex -= 1;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
index bf752e3ea..78d80e75 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ChromeContextMenuPopulator.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.preferences.datareduction.DataReductionProxyUma;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 import org.chromium.chrome.browser.util.UrlUtilities;
@@ -76,8 +77,9 @@
 
     // Additional items for custom tabs mode.
     private static final int[] CUSTOM_TAB_MODE_WHITELIST = {
-            R.id.contextmenu_open_image,
-            R.id.contextmenu_search_by_image
+            R.id.contextmenu_open_image, R.id.contextmenu_search_by_image,
+            R.id.contextmenu_open_in_new_chrome_tab, R.id.contextmenu_open_in_chrome_incognito_tab,
+            R.id.contextmenu_open_in_browser_id,
     };
 
     // Additional items for fullscreen tabs mode.
@@ -319,6 +321,14 @@
             removeUnsupportedItems(menu, FULLSCREEN_TAB_MODE_WHITELIST);
         } else if (mMode == CUSTOM_TAB_MODE) {
             removeUnsupportedItems(menu, CUSTOM_TAB_MODE_WHITELIST);
+            MenuItem defaultOpenMenuItem = menu.findItem(R.id.contextmenu_open_in_browser_id);
+            if (ChromePreferenceManager.getInstance().getCachedChromeDefaultBrowser()) {
+                defaultOpenMenuItem.setVisible(false);
+            } else {
+                menu.findItem(R.id.contextmenu_open_in_new_chrome_tab).setVisible(false);
+                menu.findItem(R.id.contextmenu_open_in_chrome_incognito_tab).setVisible(false);
+                defaultOpenMenuItem.setTitle(mDelegate.getTitleForOpenTabInExternalApp());
+            }
         } else {
             removeUnsupportedItems(menu, NORMAL_MODE_WHITELIST);
         }
@@ -427,6 +437,12 @@
             helper.shareImage();
         } else if (itemId == R.id.menu_id_open_in_chrome) {
             mDelegate.onOpenInChrome(params.getLinkUrl(), params.getPageUrl());
+        } else if (itemId == R.id.contextmenu_open_in_new_chrome_tab) {
+            mDelegate.onOpenInNewChromeTabFromCCT(params.getLinkUrl(), false);
+        } else if (itemId == R.id.contextmenu_open_in_chrome_incognito_tab) {
+            mDelegate.onOpenInNewChromeTabFromCCT(params.getLinkUrl(), true);
+        } else if (itemId == R.id.contextmenu_open_in_browser_id) {
+            mDelegate.onOpenInDefaultBrowser(params.getLinkUrl());
         } else {
             assert false;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
index 1e622413..8832c6f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextmenu/ContextMenuItemDelegate.java
@@ -153,4 +153,22 @@
      * @param pageUrl URL of the current page.
      */
     void onOpenInChrome(String linkUrl, String pageUrl);
+
+    /**
+     * Called when the {@code url} should be opened in a new Chrome tab from CCT.
+     * @param url The URL to open.
+     * @param isIncognito true if the {@code url} should be opened in a new incognito tab.
+     */
+    void onOpenInNewChromeTabFromCCT(String linkUrl, boolean isIncognito);
+
+    /**
+     * @return title of the context menu to open a page in external apps.
+     */
+    String getTitleForOpenTabInExternalApp();
+
+    /**
+     * Called when the current Chrome app is not the default to handle a View Intent.
+     * @param url The URL to open.
+     */
+    void onOpenInDefaultBrowser(String url);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
index e55fee0..d4c720db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -4,18 +4,13 @@
 
 package org.chromium.chrome.browser.customtabs;
 
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.os.AsyncTask;
 import android.view.Menu;
 import android.view.MenuItem;
 
-import org.chromium.base.BuildInfo;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.DefaultBrowserInfo;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.banners.AppBannerManager;
@@ -27,7 +22,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ExecutionException;
 
 /**
  * App menu properties delegate for {@link CustomTabActivity}.
@@ -39,10 +33,10 @@
     private final boolean mIsMediaViewer;
     private final boolean mShowStar;
     private final boolean mShowDownload;
+    private final boolean mIsOpenedByChrome;
 
     private final List<String> mMenuEntries;
     private final Map<MenuItem, Integer> mItemToIndexMap = new HashMap<MenuItem, Integer>();
-    private final AsyncTask<Void, Void, String> mDefaultBrowserFetcher;
 
     private boolean mIsCustomEntryAdded;
 
@@ -58,29 +52,7 @@
         mIsMediaViewer = isMediaViewer;
         mShowStar = showStar;
         mShowDownload = showDownload;
-
-        mDefaultBrowserFetcher = new AsyncTask<Void, Void, String>() {
-            @Override
-            protected String doInBackground(Void... params) {
-                String packageLabel = null;
-                if (isOpenedByChrome) {
-                    // If the Custom Tab was created by Chrome, Chrome should open it.
-                    packageLabel = BuildInfo.getPackageLabel(activity);
-                } else {
-                    // Check if there is a default handler for the Intent.  If so, grab its label.
-                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(SAMPLE_URL));
-                    PackageManager pm = activity.getPackageManager();
-                    ResolveInfo info = pm.resolveActivity(intent, 0);
-                    if (info != null && info.match != 0) {
-                        packageLabel = info.loadLabel(pm).toString();
-                    }
-                }
-
-                return packageLabel == null
-                        ? activity.getString(R.string.menu_open_in_product_default)
-                        : activity.getString(R.string.menu_open_in_product, packageLabel);
-            }
-        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        mIsOpenedByChrome = isOpenedByChrome;
     }
 
     @Override
@@ -122,13 +94,8 @@
                 menu.findItem(R.id.request_desktop_site_id).setVisible(false);
                 addToHomeScreenItem.setVisible(false);
             } else {
-                try {
-                    openInChromeItem.setTitle(mDefaultBrowserFetcher.get());
-                } catch (InterruptedException | ExecutionException e) {
-                    openInChromeItem.setTitle(
-                            mActivity.getString(R.string.menu_open_in_product_default));
-                }
-                updateBookmarkMenuItem(bookmarkItem, currentTab);
+                openInChromeItem.setTitle(
+                        DefaultBrowserInfo.getTitleOpenInDefaultBrowser(mIsOpenedByChrome));
             }
             bookmarkItem.setVisible(mShowStar);
             downloadItem.setVisible(mShowDownload);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListener.java b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListener.java
index 12bc7c1..cfec713 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListener.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListener.java
@@ -16,6 +16,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 
 /**
@@ -32,11 +33,13 @@
 public class GSAAccountChangeListener {
     // These are GSA constants.
     private static final String GSA_PACKAGE_NAME = "com.google.android.googlequicksearchbox";
-    private static final String ACCOUNT_UPDATE_BROADCAST_INTENT =
+    @VisibleForTesting
+    static final String ACCOUNT_UPDATE_BROADCAST_INTENT =
             "com.google.android.apps.now.account_update_broadcast";
     private static final String KEY_SSB_BROADCASTS_ACCOUNT_CHANGE_TO_CHROME =
             "ssb_service:ssb_broadcasts_account_change_to_chrome";
-    private static final String BROADCAST_INTENT_ACCOUNT_NAME_EXTRA = "account_name";
+    @VisibleForTesting
+    static final String BROADCAST_INTENT_ACCOUNT_NAME_EXTRA = "account_name";
     public static final String ACCOUNT_UPDATE_BROADCAST_PERMISSION =
             "com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS";
 
@@ -48,6 +51,19 @@
 
     private boolean mAlreadyReportedHistogram;
 
+    @VisibleForTesting
+    static class AccountChangeBroadcastReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!ACCOUNT_UPDATE_BROADCAST_INTENT.equals(intent.getAction())) return;
+            String accountName = intent.getStringExtra(BROADCAST_INTENT_ACCOUNT_NAME_EXTRA);
+            RecordHistogram.recordEnumeratedHistogram(GSAServiceClient.ACCOUNT_CHANGE_HISTOGRAM,
+                    GSAServiceClient.ACCOUNT_CHANGE_SOURCE_BROADCAST,
+                    GSAServiceClient.ACCOUNT_CHANGE_SOURCE_COUNT);
+            GSAState.getInstance(context.getApplicationContext()).setGsaAccount(accountName);
+        }
+    }
+
     /** @return the instance of GSAAccountChangeListener. */
     public static GSAAccountChangeListener getInstance() {
         if (sInstance == null) {
@@ -70,18 +86,7 @@
 
     private GSAAccountChangeListener(Context context) {
         Context applicationContext = context.getApplicationContext();
-        BroadcastReceiver accountChangeReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (!ACCOUNT_UPDATE_BROADCAST_INTENT.equals(intent.getAction())) return;
-                String accountName = intent.getStringExtra(BROADCAST_INTENT_ACCOUNT_NAME_EXTRA);
-                RecordHistogram.recordEnumeratedHistogram(GSAServiceClient.ACCOUNT_CHANGE_HISTOGRAM,
-                        GSAServiceClient.ACCOUNT_CHANGE_SOURCE_BROADCAST,
-                        GSAServiceClient.ACCOUNT_CHANGE_SOURCE_COUNT);
-                GSAState.getInstance(context.getApplicationContext()).setGsaAccount(accountName);
-            }
-        };
-        applicationContext.registerReceiver(accountChangeReceiver,
+        applicationContext.registerReceiver(new AccountChangeBroadcastReceiver(),
                 new IntentFilter(ACCOUNT_UPDATE_BROADCAST_INTENT),
                 ACCOUNT_UPDATE_BROADCAST_PERMISSION, null);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
index d74996a..80fcc158 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/InvalidationController.java
@@ -14,7 +14,9 @@
 
 import org.chromium.base.ApplicationState;
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BuildInfo;
 import org.chromium.base.FieldTrialList;
+import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.sync.ProfileSyncService;
@@ -31,6 +33,8 @@
  * client library used by Sync.
  */
 public class InvalidationController implements ApplicationStatus.ApplicationStateListener {
+    private static final String TAG = "cr_invalidation";
+
     /**
      * Timer which can be paused. When the timer is paused, the execution of its scheduled task is
      * delayed till the timer is resumed.
@@ -194,6 +198,11 @@
                 typesToRegister);
         registerIntent.setClass(
                 mContext, InvalidationClientService.getRegisteredClass());
+
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to register types");
+            return;
+        }
         mContext.startService(registerIntent);
     }
 
@@ -221,6 +230,11 @@
      * Starts the invalidation client without updating the registered invalidation types.
      */
     private void start() {
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to start invalidation client");
+            return;
+        }
+
         mStarted = true;
         mEnableSessionInvalidationsTimer.resume();
         Intent intent = new Intent(
@@ -232,6 +246,11 @@
      * Stops the invalidation client.
      */
     public void stop() {
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to stop invalidation client");
+            return;
+        }
+
         mStarted = false;
         mEnableSessionInvalidationsTimer.pause();
         Intent intent = new Intent(
@@ -339,6 +358,11 @@
         ApplicationStatus.registerApplicationStateListener(this);
     }
 
+    private boolean shouldRestrictBackgroundServices() {
+        // Restricts the use of background services when not in foreground. See crbug.com/680812.
+        return BuildInfo.isGreaterThanN() && !ApplicationStatus.hasVisibleActivities();
+    }
+
     @Override
     public void onApplicationStateChange(int newState) {
         // The isSyncEnabled() check is used to check whether the InvalidationController would be
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
index c42cc3a..775d3d6b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBar.java
@@ -171,4 +171,12 @@
      */
     void setDefaultTextEditActionModeCallback(ToolbarActionModeCallback callback);
 
+    /**
+     * Returns whether the {@link UrlBar} must be queried for its location on screen when
+     * suggestions are being laid out by {@link SuggestionView}.
+     * TODO(dfalcantara): Revisit this after M58.
+     *
+     * @return Whether or not the {@link UrlBar} has to be explicitly checked for its location.
+     */
+    boolean mustQueryUrlBarLocationForSuggestions();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 7dd644a..5dd73e0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -1989,7 +1989,8 @@
         }
     }
 
-    private void backKeyPressed() {
+    // TODO(dfalcantara): Make private again after M58.
+    protected void backKeyPressed() {
         hideSuggestions();
         UiUtils.hideKeyboard(mUrlBar);
         // Revert the URL to match the current page.
@@ -2462,4 +2463,9 @@
 
     @Override
     public void setShowTitle(boolean showTitle) { }
+
+    @Override
+    public boolean mustQueryUrlBarLocationForSuggestions() {
+        return DeviceFormFactor.isTablet(getContext());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
index c5253338..531a761 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/SuggestionView.java
@@ -861,7 +861,7 @@
         }
 
         private int getUrlBarLeftOffset() {
-            if (DeviceFormFactor.isTablet(getContext())) {
+            if (mLocationBar.mustQueryUrlBarLocationForSuggestions()) {
                 mUrlBar.getLocationInWindow(mViewPositionHolder);
                 return mViewPositionHolder[0];
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
index 9dbaa3f..3490476c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabContextMenuItemDelegate.java
@@ -8,12 +8,15 @@
 import android.content.Intent;
 import android.net.MailTo;
 import android.net.Uri;
+import android.provider.Browser;
 import android.provider.ContactsContract;
 
 import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.browser.DefaultBrowserInfo;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.contextmenu.ContextMenuItemDelegate;
+import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
@@ -232,6 +235,33 @@
         }
     }
 
+    @Override
+    public void onOpenInNewChromeTabFromCCT(String linkUrl, boolean isIncognito) {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(linkUrl));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setPackage(mTab.getApplicationContext().getPackageName());
+        intent.putExtra(ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, false);
+        if (isIncognito) {
+            intent.putExtra(IntentHandler.EXTRA_OPEN_NEW_INCOGNITO_TAB, true);
+            intent.putExtra(
+                    Browser.EXTRA_APPLICATION_ID, mTab.getApplicationContext().getPackageName());
+            IntentHandler.addTrustedIntentExtras(intent);
+        }
+        IntentUtils.safeStartActivity(mTab.getActivity(), intent);
+    }
+
+    @Override
+    public String getTitleForOpenTabInExternalApp() {
+        return DefaultBrowserInfo.getTitleOpenInDefaultBrowser(false);
+    }
+
+    @Override
+    public void onOpenInDefaultBrowser(String url) {
+        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        IntentUtils.safeStartActivity(mTab.getActivity(), intent);
+    }
+
     /**
      * Checks if spdy proxy is enabled for input url.
      * @param url Input url to check for spdy setting.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
index 40a13bf..1716d7c2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarPhone.java
@@ -10,16 +10,22 @@
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.widget.BottomSheet;
+import org.chromium.chrome.browser.widget.BottomSheetObserver;
 
 /**
  * Phone specific toolbar that exists at the bottom of the screen.
  */
-public class BottomToolbarPhone extends ToolbarPhone {
-
+public class BottomToolbarPhone extends ToolbarPhone implements BottomSheetObserver {
     /** A handle to the bottom sheet. */
     private BottomSheet mBottomSheet;
 
     /**
+     * Whether the end toolbar buttons should be hidden regardless of whether the URL bar is
+     * focused.
+     */
+    private boolean mShouldHideEndToolbarButtons;
+
+    /**
      * Constructs a BottomToolbarPhone object.
      * @param context The Context in which this View object is created.
      * @param attrs The AttributeSet that was specified with this View.
@@ -46,8 +52,11 @@
 
     @Override
     public void setBottomSheet(BottomSheet sheet) {
+        assert mBottomSheet == null;
+
         mBottomSheet = sheet;
         getLocationBar().setBottomSheet(mBottomSheet);
+        mBottomSheet.addObserver(this);
     }
 
     @Override
@@ -65,4 +74,34 @@
         coordinator.addView(mProgressBar);
         mProgressBar.setProgressBarContainer(coordinator);
     }
+
+    @Override
+    protected boolean shouldHideEndToolbarButtons() {
+        return mShouldHideEndToolbarButtons;
+    }
+
+    @Override
+    public void onSheetOpened() {}
+
+    @Override
+    public void onSheetClosed() {}
+
+    @Override
+    public void onLoadUrl(String url) {}
+
+    @Override
+    public void onTransitionPeekToHalf(float transitionFraction) {
+        // TODO(twellington): animate end toolbar button appearance/disappearance.
+        if (transitionFraction >= 0.5 && !mShouldHideEndToolbarButtons) {
+            mShouldHideEndToolbarButtons = true;
+            updateUrlExpansionAnimation();
+        } else if (transitionFraction < 0.5 && mShouldHideEndToolbarButtons) {
+            mShouldHideEndToolbarButtons = false;
+            updateUrlExpansionAnimation();
+        }
+
+        boolean buttonsClickable = transitionFraction == 0.f;
+        mToggleTabStackButton.setClickable(buttonsClickable);
+        mMenuButton.setClickable(buttonsClickable);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index ae93dacf..e06bba2d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -759,4 +759,9 @@
         // This class has no menu button wrapper, so return the menu button instead.
         return mMenuButton;
     }
+
+    @Override
+    public boolean mustQueryUrlBarLocationForSuggestions() {
+        return false;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/OWNERS
index f47a3405..8efec3b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/OWNERS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/OWNERS
@@ -1,2 +1,4 @@
 tedchoc@chromium.org
 yusufo@chromium.org
+
+per-file BottomToolbarPhone.java=mdjones@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index d9a93b58..f3cac87 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -114,7 +114,7 @@
     private LocationBarPhone mLocationBar;
 
     private ViewGroup mToolbarButtonsContainer;
-    private ImageView mToggleTabStackButton;
+    protected ImageView mToggleTabStackButton;
     private NewTabButton mNewTabButton;
     private TintedImageButton mHomeButton;
     private TextView mUrlBar;
@@ -625,8 +625,9 @@
         if (visualState == VisualState.NEW_TAB_NORMAL) {
             return 0;
         } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
-            return Math.max(
-                    mToolbarSidePadding, mToolbarButtonsContainer.getMeasuredWidth());
+            return Math.max(mToolbarSidePadding,
+                    shouldHideEndToolbarButtons() ? 0
+                                                  : mToolbarButtonsContainer.getMeasuredWidth());
         } else {
             return getBoundsAfterAccountingForLeftButton();
         }
@@ -646,8 +647,9 @@
         } else if (ApiCompatibilityUtils.isLayoutRtl(this)) {
             return getMeasuredWidth() - getBoundsAfterAccountingForLeftButton();
         } else {
-            int margin = Math.max(
-                    mToolbarSidePadding, mToolbarButtonsContainer.getMeasuredWidth());
+            int margin = Math.max(mToolbarSidePadding,
+                    shouldHideEndToolbarButtons() ? 0
+                                                  : mToolbarButtonsContainer.getMeasuredWidth());
             return getMeasuredWidth() - margin;
         }
     }
@@ -781,7 +783,7 @@
      * Updates the parameters relating to expanding the location bar, as the result of either a
      * focus change or scrolling the New Tab Page.
      */
-    private void updateUrlExpansionAnimation() {
+    protected void updateUrlExpansionAnimation() {
         if (mTabSwitcherState != STATIC_TAB) {
             mToolbarButtonsContainer.setVisibility(VISIBLE);
             return;
@@ -844,6 +846,24 @@
         } else {
             urlActionsTranslationX += mLocationBarNtpOffsetRight - mLocationBarNtpOffsetLeft;
         }
+
+        if (shouldHideEndToolbarButtons()) {
+            // When the end toolbar buttons are not hidden, url actions are shown and hidden due to
+            // a change in location bar's width. When the end toolbar buttons are hidden, the
+            // location bar's width does not change by as much, causing the end location for the url
+            // actions to be immediately visible. Translate the url action container so that their
+            // appearance is animated.
+            // TODO(twellington): polish the url action button animation when end toolbar buttons
+            //                    are hidden.
+            float urlActionsTranslationXOffset =
+                    mUrlActionContainer.getWidth() * (1 - mUrlExpansionPercent);
+            if (isLocationBarRtl) {
+                urlActionsTranslationX -= urlActionsTranslationXOffset;
+            } else {
+                urlActionsTranslationX += urlActionsTranslationXOffset;
+            }
+        }
+
         mUrlActionContainer.setTranslationX(urlActionsTranslationX);
 
         mLocationBar.setUrlFocusChangePercent(mUrlExpansionPercent);
@@ -851,7 +871,8 @@
         // Ensure the buttons are invisible after focusing the omnibox to prevent them from
         // accepting click events.
         int toolbarButtonVisibility = mUrlExpansionPercent == 1f ? INVISIBLE : VISIBLE;
-        mToolbarButtonsContainer.setVisibility(toolbarButtonVisibility);
+        mToolbarButtonsContainer.setVisibility(
+                shouldHideEndToolbarButtons() ? INVISIBLE : toolbarButtonVisibility);
         if (mHomeButton.getVisibility() != GONE) {
             mHomeButton.setVisibility(toolbarButtonVisibility);
         }
@@ -1336,6 +1357,15 @@
         }
     }
 
+    /**
+     * @return Whether the end toolbar buttons (tab switcher and menu) are currently hidden
+     *         regardless of URL bar focus. Sub-classes that hide these buttons should override
+     *         this method.
+     */
+    protected boolean shouldHideEndToolbarButtons() {
+        return false;
+    }
+
     private ObjectAnimator createEnterTabSwitcherModeAnimation() {
         ObjectAnimator enterAnimation =
                 ObjectAnimator.ofFloat(this, mTabSwitcherModePercentProperty, 1.f);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
index 9135e60..3a65612 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/FadingBackgroundView.java
@@ -82,10 +82,31 @@
         super.setAlpha(alpha);
 
         int newVisibility = alpha <= 0f ? View.GONE : View.VISIBLE;
-
         setVisibility(newVisibility);
-        for (FadingViewObserver o : mObservers) {
-            o.onFadingViewVisibilityChanged(newVisibility == View.VISIBLE);
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (getAlpha() <= 0f && visibility == View.VISIBLE) return;
+        super.setVisibility(visibility);
+    }
+
+    @Override
+    protected void dispatchVisibilityChanged(View view, int visibility) {
+        if (getAlpha() <= 0f && visibility == View.VISIBLE) return;
+        super.dispatchVisibilityChanged(view, visibility);
+    }
+
+    @Override
+    public void onVisibilityChanged(View view, int visibility) {
+        super.onVisibilityChanged(view, visibility);
+
+        // This check is added for the exclusive purpose of testing on Android K. Later versions
+        // of Android do not run into the problem of the observer list being null.
+        if (mObservers != null) {
+            for (FadingViewObserver o : mObservers) {
+                o.onFadingViewVisibilityChanged(visibility == View.VISIBLE);
+            }
         }
     }
 
@@ -107,15 +128,13 @@
      * Triggers a fade out of the omnibox results background creating a new animation if necessary.
      */
     public void hideFadingOverlay(boolean fadeOut) {
-        // If the overlay is already invisible, do nothing.
-        if (getVisibility() != VISIBLE) return;
-
         if (mOverlayFadeOutAnimator == null) {
             mOverlayFadeOutAnimator = ObjectAnimator.ofFloat(this, ALPHA, 0f);
             mOverlayFadeOutAnimator.setDuration(FADE_DURATION_MS);
             mOverlayFadeOutAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
         }
 
+        mOverlayFadeOutAnimator.setFloatValues(getAlpha(), 0f);
         runFadeOverlayAnimation(mOverlayFadeOutAnimator);
         if (!fadeOut) mOverlayFadeOutAnimator.end();
     }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index cd1dbd04..3d2e897a 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1512,7 +1512,12 @@
       <message name="IDS_CONTEXTMENU_SAVE_VIDEO" desc="Context sensitive menu item for saving the selected video. [CHAR-LIMIT=30]">
         Download video
       </message>
-
+      <message name="IDS_CONTEXTMENU_OPEN_IN_NEW_CHROME_TAB" desc="Context sensitive menu item to open the selected link in a new Chrome tab from Chrome Custom Tab. [CHAR-LIMIT=30]">
+        Open in new Chrome tab
+      </message>
+      <message name="IDS_CONTEXTMENU_OPEN_IN_CHROME_INCOGNITO_TAB" desc="Context sensitive menu item to open the selected link in a Chrome incognito tab from Chrome Custom Tab. [CHAR-LIMIT=30]">
+        Open in Chrome incognito tab
+      </message>
       <!-- Swipe refresh -->
       <message name="IDS_ACCESSIBILITY_SWIPE_REFRESH" desc="Content description for the swipe refresh action.">
         Refreshing page
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 83abfcf..d42512ff 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -30,6 +30,7 @@
   "java/src/org/chromium/chrome/browser/ChromeTabbedActivity2.java",
   "java/src/org/chromium/chrome/browser/ChromeVersionInfo.java",
   "java/src/org/chromium/chrome/browser/ChromeWindow.java",
+  "java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java",
   "java/src/org/chromium/chrome/browser/DeferredStartupHandler.java",
   "java/src/org/chromium/chrome/browser/DevToolsServer.java",
   "java/src/org/chromium/chrome/browser/FileProviderHelper.java",
@@ -1293,6 +1294,7 @@
   "javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java",
   "javatests/src/org/chromium/chrome/browser/gcore/MockConnectedTask.java",
   "javatests/src/org/chromium/chrome/browser/gcore/MockConnectedTaskTest.java",
+  "javatests/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListenerTest.java",
   "javatests/src/org/chromium/chrome/browser/gsa/GSAServiceClientTest.java",
   "javatests/src/org/chromium/chrome/browser/hardware_acceleration/ChromeTabbedActivityHWATest.java",
   "javatests/src/org/chromium/chrome/browser/hardware_acceleration/CustomTabActivityHWATest.java",
diff --git a/chrome/android/javatests/OWNERS b/chrome/android/javatests/OWNERS
index a1e57466..8391a687 100644
--- a/chrome/android/javatests/OWNERS
+++ b/chrome/android/javatests/OWNERS
@@ -5,3 +5,5 @@
 skyostil@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
+
+# COMPONENT: Test>Android
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
index ddb35a0..2465227c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/AudioTest.java
@@ -51,7 +51,7 @@
         assertEquals("ready_to_play", tab.getTitle());
 
         titleObserver = new TabTitleObserver(tab, "ended");
-        DOMUtils.clickNode(this, tab.getContentViewCore(), "button1");
+        DOMUtils.clickNode(tab.getContentViewCore(), "button1");
 
         // Make sure that the audio playback "ended" and title is changed.
         titleObserver.waitForTitleUpdate(15);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
index 82e1604..faa46e0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/FocusedEditableTextFieldZoomTest.java
@@ -81,7 +81,7 @@
         final ContentViewCore contentViewCore = tab.getContentViewCore();
         float initialZoomLevel = contentViewCore.getScale();
 
-        DOMUtils.clickNode(this, contentViewCore, TEXTFIELD_DOM_ID);
+        DOMUtils.clickNode(contentViewCore, TEXTFIELD_DOM_ID);
 
         // Wait for the zoom in to complete.
         waitForZoomIn(contentViewCore, initialZoomLevel);
@@ -98,7 +98,7 @@
         final float initialZoomLevel = contentViewCore.getScale();
 
         // This should focus the text field and initiate a zoom in.
-        DOMUtils.clickNode(this, contentViewCore, TEXTFIELD_DOM_ID);
+        DOMUtils.clickNode(contentViewCore, TEXTFIELD_DOM_ID);
 
         // Wait for the zoom in to complete.
         waitForZoomIn(contentViewCore, initialZoomLevel);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
index 2b1cce4..a7f403a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -218,7 +218,7 @@
 
         Tab tab = getActivity().getActivityTab();
 
-        DOMUtils.clickNode(this, tab.getContentViewCore(), "aboutLink");
+        DOMUtils.clickNode(tab.getContentViewCore(), "aboutLink");
         ChromeTabUtils.waitForTabPageLoaded(tab, url2);
         assertEquals("Desired Link not open", url2, getActivity().getActivityTab().getUrl());
     }
@@ -246,7 +246,7 @@
         };
         Tab tab = getActivity().getActivityTab();
         tab.addObserver(onPageLoadStartedObserver);
-        DOMUtils.clickNode(this, tab.getContentViewCore(), "aboutLink");
+        DOMUtils.clickNode(tab.getContentViewCore(), "aboutLink");
         ChromeTabUtils.waitForTabPageLoaded(tab, url2);
         assertEquals("Desired Link not open", url2, getActivity().getActivityTab().getUrl());
     }
@@ -417,7 +417,7 @@
             assertWaitForPageScaleFactorMatch(0.5f);
 
             // Click the page, which triggers the URL load.
-            DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "body");
+            DOMUtils.clickNode(getActivity().getCurrentContentViewCore(), "body");
 
             // Wait for the proper URL to be served.
             assertTrue(urlServedSemaphore.tryAcquire(5, TimeUnit.SECONDS));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/OSKOverscrollTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/OSKOverscrollTest.java
index 77977d02f..5192e81 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/OSKOverscrollTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/OSKOverscrollTest.java
@@ -136,7 +136,7 @@
 
         // Click on the unfocused input element for the first time to focus on it. This brings up
         // the OSK.
-        DOMUtils.clickNode(this, viewCoreRef.get(), "fn");
+        DOMUtils.clickNode(viewCoreRef.get(), "fn");
 
         waitForKeyboard();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
index add8ecc..ac8125f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/SelectFileDialogTest.java
@@ -108,7 +108,7 @@
     @RetryOnFailure
     public void testSelectFileAndCancelRequest() throws Throwable {
         {
-            DOMUtils.clickNode(this, mContentViewCore, "input_file");
+            DOMUtils.clickNode(mContentViewCore, "input_file");
             CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
             assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
@@ -121,7 +121,7 @@
         }
 
         {
-            DOMUtils.clickNode(this, mContentViewCore, "input_text");
+            DOMUtils.clickNode(mContentViewCore, "input_text");
             CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
             assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
@@ -134,7 +134,7 @@
         }
 
         {
-            DOMUtils.clickNode(this, mContentViewCore, "input_any");
+            DOMUtils.clickNode(mContentViewCore, "input_any");
             CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
             assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
@@ -147,7 +147,7 @@
         }
 
         {
-            DOMUtils.clickNode(this, mContentViewCore, "input_file_multiple");
+            DOMUtils.clickNode(mContentViewCore, "input_file_multiple");
             CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
             assertEquals(
                     Intent.ACTION_CHOOSER, mActivityWindowAndroidForTest.lastIntent.getAction());
@@ -162,13 +162,13 @@
             resetActivityWindowAndroidForTest();
         }
 
-        DOMUtils.clickNode(this, mContentViewCore, "input_image");
+        DOMUtils.clickNode(mContentViewCore, "input_image");
         CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
         assertEquals(MediaStore.ACTION_IMAGE_CAPTURE,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
         resetActivityWindowAndroidForTest();
 
-        DOMUtils.clickNode(this, mContentViewCore, "input_audio");
+        DOMUtils.clickNode(mContentViewCore, "input_audio");
         CriteriaHelper.pollInstrumentationThread(new IntentSentCriteria());
         assertEquals(MediaStore.Audio.Media.RECORD_SOUND_ACTION,
                 mActivityWindowAndroidForTest.lastIntent.getAction());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 9448ee1..390137ea 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -305,7 +305,7 @@
                 getInstrumentation(), getActivity(), mTestServer.getURL(TEST_FILE_PATH), false);
         assertEquals("Failed to click node.", true,
                 DOMUtils.clickNode(
-                        this, getActivity().getActivityTab().getContentViewCore(), "input_text"));
+                        getActivity().getActivityTab().getContentViewCore(), "input_text"));
         assertWaitForKeyboardStatus(true);
 
         // Open a new tab(the 2nd tab).
@@ -314,7 +314,7 @@
         assertWaitForKeyboardStatus(false);
 
         // Click node in the 2nd tab.
-        DOMUtils.clickNode(this, getActivity().getActivityTab().getContentViewCore(), "input_text");
+        DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "input_text");
         assertWaitForKeyboardStatus(true);
 
         // Switch to the 1st tab.
@@ -322,7 +322,7 @@
         assertWaitForKeyboardStatus(false);
 
         // Click node in the 1st tab.
-        DOMUtils.clickNode(this, getActivity().getActivityTab().getContentViewCore(), "input_text");
+        DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "input_text");
         assertWaitForKeyboardStatus(true);
 
         // Close current tab(the 1st tab).
@@ -343,13 +343,12 @@
                 getInstrumentation(), getActivity(), mTestServer.getURL(TEST_FILE_PATH), false);
         assertEquals("Failed to click textarea.", true,
                 DOMUtils.clickNode(
-                        this, getActivity().getActivityTab().getContentViewCore(), "textarea"));
+                        getActivity().getActivityTab().getContentViewCore(), "textarea"));
         assertWaitForKeyboardStatus(true);
 
         // Click the button to open a new window.
         assertEquals("Failed to click button.", true,
-                DOMUtils.clickNode(
-                        this, getActivity().getActivityTab().getContentViewCore(), "button"));
+                DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "button"));
         assertWaitForKeyboardStatus(false);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
index eb38ed0..be60094 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryTest.java
@@ -125,7 +125,7 @@
     public void testTapInputFieldShowsKeyboardAccessory() throws ExecutionException,
              InterruptedException, TimeoutException {
         loadTestPage(false);
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
+        DOMUtils.clickNode(mViewCoreRef.get(), "fn");
         CriteriaHelper.pollUiThread(new Criteria("Keyboard should be showing.") {
             @Override
             public boolean isSatisfied() {
@@ -152,7 +152,7 @@
     public void testSwitchFieldsRescrollsKeyboardAccessory() throws ExecutionException,
              InterruptedException, TimeoutException {
         loadTestPage(false);
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
+        DOMUtils.clickNode(mViewCoreRef.get(), "fn");
         CriteriaHelper.pollUiThread(new Criteria("Keyboard should be showing.") {
             @Override
             public boolean isSatisfied() {
@@ -179,7 +179,7 @@
                         }
                     }
                 });
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "ln");
+        DOMUtils.clickNode(mViewCoreRef.get(), "ln");
         CriteriaHelper.pollUiThread(
                 new Criteria("First suggestion should be on the screen after switching fields.") {
                     @Override
@@ -203,7 +203,7 @@
     public void testSwitchFieldsRescrollsKeyboardAccessoryRtl() throws ExecutionException,
              InterruptedException, TimeoutException {
         loadTestPage(true);
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
+        DOMUtils.clickNode(mViewCoreRef.get(), "fn");
         CriteriaHelper.pollUiThread(new Criteria("Keyboard should be showing.") {
             @Override
             public boolean isSatisfied() {
@@ -230,7 +230,7 @@
                         }
                     }
                 });
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "ln");
+        DOMUtils.clickNode(mViewCoreRef.get(), "ln");
         CriteriaHelper.pollUiThread(
                 new Criteria("Last suggestion should be off the screen after switching fields.") {
                     @Override
@@ -256,7 +256,7 @@
     public void testSelectSuggestionHidesKeyboardAccessory() throws ExecutionException,
              InterruptedException, TimeoutException {
         loadTestPage(false);
-        DOMUtils.clickNode(this, mViewCoreRef.get(), "fn");
+        DOMUtils.clickNode(mViewCoreRef.get(), "fn");
         CriteriaHelper.pollUiThread(new Criteria("Keyboard should be showing.") {
             @Override
             public boolean isSatisfied() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index fc92e88..6f193c5 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -172,7 +172,7 @@
 
         // Click the input field for the first name.
         DOMUtils.waitForNonZeroNodeBounds(webContents, "fn");
-        DOMUtils.clickNode(this, viewCore, "fn");
+        DOMUtils.clickNode(viewCore, "fn");
 
         waitForKeyboardShowRequest(immw, 1);
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
index f8f8abd..3d29ccf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
@@ -89,7 +89,7 @@
         // Click on the unfocused input element for the first time to focus on it. This brings up
         // the autofill popup and shows the keyboard at the same time. Showing the keyboard should
         // not hide the autofill popup.
-        DOMUtils.clickNode(this, viewCoreRef.get(), "fn");
+        DOMUtils.clickNode(viewCoreRef.get(), "fn");
 
         // Wait until the keyboard is showing.
         CriteriaHelper.pollUiThread(new Criteria("Keyboard was never shown.") {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
index 58dd3863..8fd60aa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/overlays/strip/TabStripTest.java
@@ -746,7 +746,7 @@
     public void testSwitchingTabsHidesKeyboard() throws Throwable {
         loadUrl("data:text/html;charset=utf-8,<html><head></head><body><form>"
                 + "<input type='text' id='input0'></form></body></html>");
-        DOMUtils.clickNode(this, getActivity().getActivityTab().getContentViewCore(), "input0");
+        DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "input0");
         assertWaitForKeyboardStatus(true);
 
         getInstrumentation().waitForIdleSync();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
index 2cd9ec8e..be2cf7e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -203,7 +203,7 @@
     @RetryOnFailure
     public void testDismissContextMenuOnBack() throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
-        ContextMenu menu = ContextMenuUtils.openContextMenu(this, tab, "testImage");
+        ContextMenu menu = ContextMenuUtils.openContextMenu(tab, "testImage");
         assertNotNull("Context menu was not properly created", menu);
         CriteriaHelper.pollUiThread(new Criteria("Context menu did not have window focus") {
             @Override
@@ -226,7 +226,7 @@
     @RetryOnFailure
     public void testDismissContextMenuOnClick() throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
-        ContextMenu menu = ContextMenuUtils.openContextMenu(this, tab, "testImage");
+        ContextMenu menu = ContextMenuUtils.openContextMenu(tab, "testImage");
         assertNotNull("Context menu was not properly created", menu);
         CriteriaHelper.pollUiThread(new Criteria("Context menu did not have window focus") {
             @Override
@@ -291,7 +291,7 @@
     public void testSaveVideo()
             throws InterruptedException, TimeoutException, SecurityException, IOException {
         // Click the video to enable playback
-        DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "videoDOMElement");
+        DOMUtils.clickNode(getActivity().getCurrentContentViewCore(), "videoDOMElement");
         saveMediaFromContextMenu("videoDOMElement", R.id.contextmenu_save_video, FILENAME_WEBM);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 4733aa1..096b76b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -201,7 +201,7 @@
     public void longPressNodeWithoutWaiting(String nodeId)
             throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
-        DOMUtils.longPressNode(this, tab.getContentViewCore(), nodeId);
+        DOMUtils.longPressNode(tab.getContentViewCore(), nodeId);
     }
 
     /**
@@ -219,7 +219,7 @@
      */
     public void clickNode(String nodeId) throws InterruptedException, TimeoutException {
         Tab tab = getActivity().getActivityTab();
-        DOMUtils.clickNode(this, tab.getContentViewCore(), nodeId);
+        DOMUtils.clickNode(tab.getContentViewCore(), nodeId);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 69286cae..4c239b6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -306,7 +306,7 @@
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 12;
-        Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "logo");
+        Menu menu = ContextMenuUtils.openContextMenu(getActivity().getActivityTab(), "logo");
         assertEquals(expectedMenuSize, menu.size());
 
         assertNotNull(menu.findItem(R.id.contextmenu_copy_link_address));
@@ -347,8 +347,7 @@
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 12;
-        Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(),
-                "aboutLink");
+        Menu menu = ContextMenuUtils.openContextMenu(getActivity().getActivityTab(), "aboutLink");
         assertEquals(expectedMenuSize, menu.size());
 
         assertNotNull(menu.findItem(R.id.contextmenu_copy_link_address));
@@ -388,7 +387,7 @@
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 12;
-        Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "email");
+        Menu menu = ContextMenuUtils.openContextMenu(getActivity().getActivityTab(), "email");
         assertEquals(expectedMenuSize, menu.size());
 
         assertNotNull(menu.findItem(R.id.contextmenu_copy_link_address));
@@ -428,7 +427,7 @@
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
 
         final int expectedMenuSize = 12;
-        Menu menu = ContextMenuUtils.openContextMenu(this, getActivity().getActivityTab(), "tel");
+        Menu menu = ContextMenuUtils.openContextMenu(getActivity().getActivityTab(), "tel");
         assertEquals(expectedMenuSize, menu.size());
 
         assertNotNull(menu.findItem(R.id.contextmenu_copy_link_address));
@@ -672,8 +671,7 @@
             }
         });
         try {
-            DOMUtils.clickNode(CustomTabActivityTest.this,
-                    getActivity().getActivityTab().getContentViewCore(), "select");
+            DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "select");
         } catch (TimeoutException e) {
             fail();
         }
@@ -903,7 +901,7 @@
                 });
             }
         });
-        DOMUtils.clickNode(this, getActivity().getActivityTab().getContentViewCore(), "new_window");
+        DOMUtils.clickNode(getActivity().getActivityTab().getContentViewCore(), "new_window");
 
         openTabHelper.waitForCallback(0, 1);
         assertEquals("A new tab should have been created.", 2,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListenerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListenerTest.java
new file mode 100644
index 0000000..9e9aad4
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/gsa/GSAAccountChangeListenerTest.java
@@ -0,0 +1,78 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.gsa;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.filters.SmallTest;
+import android.test.InstrumentationTestCase;
+
+import junit.framework.AssertionFailedError;
+
+import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+
+/** Tests for GSAAccountChangeListener. */
+public class GSAAccountChangeListenerTest extends InstrumentationTestCase {
+    private static final String ACCOUNT_NAME = "me@gmail.com";
+    private static final String ACCOUNT_NAME2 = "you@gmail.com";
+    private static final String PERMISSION = "permission.you.dont.have";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        RecordHistogram.setDisabledForTests(true);
+    }
+
+    @SmallTest
+    public void testReceivesBroadcastIntents() throws Exception {
+        final Context context = getInstrumentation().getTargetContext();
+        BroadcastReceiver receiver = new GSAAccountChangeListener.AccountChangeBroadcastReceiver();
+        context.registerReceiver(receiver,
+                new IntentFilter(GSAAccountChangeListener.ACCOUNT_UPDATE_BROADCAST_INTENT));
+
+        // Send a broadcast without the permission, should be received.
+        Intent intent = new Intent();
+        intent.setPackage(context.getPackageName());
+        intent.setAction(GSAAccountChangeListener.ACCOUNT_UPDATE_BROADCAST_INTENT);
+        intent.putExtra(GSAAccountChangeListener.BROADCAST_INTENT_ACCOUNT_NAME_EXTRA, ACCOUNT_NAME);
+        context.sendBroadcast(intent);
+
+        CriteriaHelper.pollUiThread(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                String currentAccount =
+                        GSAState.getInstance(context.getApplicationContext()).getGsaAccount();
+                return ACCOUNT_NAME.equals(currentAccount);
+            }
+        });
+
+        // A broadcast with a permission that Chrome doesn't hold should not be received.
+        context.registerReceiver(receiver,
+                new IntentFilter(GSAAccountChangeListener.ACCOUNT_UPDATE_BROADCAST_INTENT),
+                PERMISSION, null);
+        intent.putExtra(
+                GSAAccountChangeListener.BROADCAST_INTENT_ACCOUNT_NAME_EXTRA, ACCOUNT_NAME2);
+        context.sendBroadcast(intent, "permission.you.dont.have");
+
+        // This is ugly, but so is checking that some asynchronous call was never received.
+        try {
+            CriteriaHelper.pollUiThread(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    String currentAccount =
+                            GSAState.getInstance(context.getApplicationContext()).getGsaAccount();
+                    return ACCOUNT_NAME2.equals(currentAccount);
+                }
+            }, 1000, 100);
+        } catch (AssertionFailedError e) {
+            return;
+        }
+        fail("The broadcast was received.");
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 32415fab..3bb348c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -78,7 +78,7 @@
         final ContentViewCore viewCore = getActivity().getCurrentContentViewCore();
 
         // Once clicked, the popup should show up.
-        DOMUtils.clickNode(this, viewCore, "select");
+        DOMUtils.clickNode(viewCore, "select");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
 
         // Now create and destroy a different ContentView.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java
index 1833ea7..9f67628 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java
@@ -174,7 +174,7 @@
         waitUntilVideoReady(videoElement, webContents);
 
         // Need to click on the video first to overcome the user gesture requirement.
-        DOMUtils.clickNode(this, tab.getContentViewCore(), videoElement);
+        DOMUtils.clickNode(tab.getContentViewCore(), videoElement);
         DOMUtils.playMedia(webContents, videoElement);
         DOMUtils.waitForMediaPlay(webContents, videoElement);
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
index 9ad1f91c..9c3bbac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -183,7 +183,7 @@
     protected void clickNodeAndWait(String nodeId, CallbackHelper helper)
             throws InterruptedException, ExecutionException, TimeoutException {
         int callCount = helper.getCallCount();
-        DOMUtils.clickNode(this, mViewCoreRef.get(), nodeId);
+        DOMUtils.clickNode(mViewCoreRef.get(), nodeId);
         helper.waitForCallback(callCount);
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtilsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtilsTest.java
index 8923d213..e24fb8a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtilsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtilsTest.java
@@ -10,6 +10,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.AdvancedMockContext;
+import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
@@ -40,8 +41,11 @@
      */
     @UiThreadTest
     @SmallTest
+    @CommandLineFlags.Add("force-fieldtrials=DataCompressionProxyPromoVisibility/Enabled")
     @Feature({"DataReduction"})
     public void testCanShowPromos() {
+        if (DataReductionProxySettings.getInstance().isDataReductionProxyManaged()) return;
+        assertFalse(DataReductionProxySettings.getInstance().isDataReductionProxyEnabled());
         assertTrue(DataReductionPromoUtils.canShowPromos());
         DataReductionProxySettings.getInstance().setDataReductionProxyEnabled(mContext, true);
         assertFalse(DataReductionPromoUtils.canShowPromos());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
index 7a7791d..e4ac29c6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
@@ -133,7 +133,7 @@
         loadUrl(mTestServer.getURL(NAVIGATION_FROM_USER_GESTURE_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(2, DEFAULT_MAX_TIME_TO_WAIT_IN_MS);
         assertTrue(mNavParamHistory.get(1).hasUserGesture);
         assertFalse(mNavParamHistory.get(1).hasUserGestureCarryover);
@@ -144,7 +144,7 @@
         loadUrl(mTestServer.getURL(NAVIGATION_FROM_XHR_CALLBACK_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(2, DEFAULT_MAX_TIME_TO_WAIT_IN_MS);
         assertFalse(mNavParamHistory.get(1).hasUserGesture);
         assertTrue(mNavParamHistory.get(1).hasUserGestureCarryover);
@@ -156,7 +156,7 @@
         loadUrl(mTestServer.getURL(NAVIGATION_FROM_XHR_CALLBACK_AND_SHORT_TIMEOUT_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(2, DEFAULT_MAX_TIME_TO_WAIT_IN_MS);
         assertFalse(mNavParamHistory.get(1).hasUserGesture);
         assertTrue(mNavParamHistory.get(1).hasUserGestureCarryover);
@@ -169,7 +169,7 @@
                 mTestServer.getURL(NAVIGATION_FROM_XHR_CALLBACK_AND_LONG_TIMEOUT_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(2, LONG_MAX_TIME_TO_WAIT_IN_MS);
         assertFalse(mNavParamHistory.get(1).hasUserGesture);
         assertFalse(mNavParamHistory.get(1).hasUserGestureCarryover);
@@ -180,7 +180,7 @@
         loadUrl(mTestServer.getURL(NAVIGATION_FROM_IMAGE_ONLOAD_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(2, DEFAULT_MAX_TIME_TO_WAIT_IN_MS);
         assertFalse(mNavParamHistory.get(1).hasUserGesture);
         assertTrue(mNavParamHistory.get(1).hasUserGestureCarryover);
@@ -191,7 +191,7 @@
         loadUrl(mTestServer.getURL(NAVIGATION_FROM_USER_GESTURE_IFRAME_PAGE));
         assertEquals(1, mNavParamHistory.size());
 
-        DOMUtils.clickNode(this, mActivity.getActivityTab().getContentViewCore(), "first");
+        DOMUtils.clickNode(mActivity.getActivityTab().getContentViewCore(), "first");
         waitTillExpectedCallsComplete(3, DEFAULT_MAX_TIME_TO_WAIT_IN_MS);
         assertEquals(3, mExternalNavParamHistory.size());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
index 974832d..1a36cf1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/UndoIntegrationTest.java
@@ -64,7 +64,7 @@
         final Tab tab = TabModelUtils.getCurrentTab(model);
 
         // Clock on the link that will trigger a delayed window popup.
-        DOMUtils.clickNode(this, tab.getContentViewCore(), "link");
+        DOMUtils.clickNode(tab.getContentViewCore(), "link");
 
         // Attempt to close the tab, which will delay closing until the undo timeout goes away.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
index 336ae01..75169f3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/video/VideoTest.java
@@ -42,7 +42,7 @@
             assertEquals("ready_to_play", tab.getTitle());
 
             titleObserver = new TabTitleObserver(tab, "ended");
-            DOMUtils.clickNode(this, tab.getContentViewCore(), "button1");
+            DOMUtils.clickNode(tab.getContentViewCore(), "button1");
             // Now the video will play for 5 secs.
             // Makes sure that the video ends and title was changed.
             titleObserver.waitForTitleUpdate(15);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java
index 5cb75ee..aaec6160 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ShortcutHelperTest.java
@@ -6,11 +6,12 @@
 
 import static org.junit.Assert.assertEquals;
 
-import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.annotation.Config;
 
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+
 /**
  * Unit tests for {@link org.chromium.chrome.browser.ShortcutHelper}.
  */
@@ -25,7 +26,7 @@
     public void testGetScopeFromUrl() {
         String url1 = "https://www.google.com";
         String url2 = "https://www.google.com/";
-        String url3 = "https://www.google.com/maps";
+        String url3 = "https://www.google.com/maps.htm";
         String url4 = "https://www.google.com/maps/";
         String url5 = "https://www.google.com/index.html";
         String url6 = "https://www.google.com/index.html?q=maps";
@@ -35,22 +36,28 @@
         String url10 = "https://www.google.com/maps/au/north/";
         String url11 = "https://www.google.com/maps/au/index.html?q=maps#fragment/";
         String url12 = "http://www.google.com:8000/maps/au/index.html?q=maps#fragment/";
+        String url13 = "https://www.google.com/maps/au/north/?q=maps#fragment";
+        String url14 = "https://www.google.com/maps/au/north?q=maps#fragment";
 
         String url2_scope = "https://www.google.com/";
+        String url4_scope = "https://www.google.com/maps/";
         String url8_scope = "https://www.google.com/maps/au/";
+        String url10_scope = "https://www.google.com/maps/au/north/";
         String url12_scope = "http://www.google.com:8000/maps/au/";
 
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url1));
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url2));
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url3));
-        assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url4));
+        assertEquals(url4_scope, ShortcutHelper.getScopeFromUrl(url4));
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url5));
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url6));
         assertEquals(url2_scope, ShortcutHelper.getScopeFromUrl(url7));
         assertEquals(url8_scope, ShortcutHelper.getScopeFromUrl(url8));
         assertEquals(url8_scope, ShortcutHelper.getScopeFromUrl(url9));
-        assertEquals(url8_scope, ShortcutHelper.getScopeFromUrl(url10));
+        assertEquals(url10_scope, ShortcutHelper.getScopeFromUrl(url10));
         assertEquals(url8_scope, ShortcutHelper.getScopeFromUrl(url11));
         assertEquals(url12_scope, ShortcutHelper.getScopeFromUrl(url12));
+        assertEquals(url10_scope, ShortcutHelper.getScopeFromUrl(url13));
+        assertEquals(url8_scope, ShortcutHelper.getScopeFromUrl(url14));
     }
 }
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index b8d8e78..4cf02c7 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -48,7 +48,6 @@
 constexpr char kGPUPixelShaderVersion[] = "gpu-psver";
 constexpr char kGPUVertexShaderVersion[] = "gpu-vsver";
 
-constexpr char kHungAudioThreadDetails[] = "hung-audio-thread-details";
 constexpr char kHungRendererOutstandingAckCount[] = "hung-outstanding-acks";
 constexpr char kHungRendererOutstandingEventType[] =
     "hung-outstanding-event-type";
@@ -127,7 +126,6 @@
       {kInputEventFilterSendFailure, kSmallSize},
 
       // media/:
-      {kHungAudioThreadDetails, kSmallSize},
       {kZeroEncodeDetails, kSmallSize},
 
       // gin/:
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 4f24834..84165c5d9 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -799,7 +799,7 @@
         // downloads page if the user chooses to wait.
         Browser* browser = chrome::FindBrowserWithProfile(profiles[i]);
         if (!browser) {
-          browser = new Browser(Browser::CreateParams(profiles[i]));
+          browser = new Browser(Browser::CreateParams(profiles[i], true));
           browser->window()->Show();
         }
         DCHECK(browser);
@@ -1282,7 +1282,7 @@
   Browser* browser = chrome::GetLastActiveBrowser();
   // if no browser window exists then create one with no tabs to be filled in
   if (!browser) {
-    browser = new Browser(Browser::CreateParams([self lastProfile]));
+    browser = new Browser(Browser::CreateParams([self lastProfile], true));
     browser->window()->Show();
   }
 
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 57b22bd..74f4586 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -2673,7 +2673,8 @@
 // the background one.
 // Disabled:  http://crbug.com/134357
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, DISABLED_TwoWindows) {
-  Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile()));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   // Navigate the new browser window so it'll be shown and we can pick the
   // active window.
   ui_test_utils::NavigateToURL(browser2, GURL(url::kAboutBlankURL));
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 46883134..7681210 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -141,6 +141,7 @@
 #include "components/version_info/version_info.h"
 #include "components/wallpaper/wallpaper_manager_base.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/media_capture_devices.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
@@ -429,6 +430,9 @@
   CrasAudioHandler::Initialize(
       new AudioDevicesPrefHandlerImpl(g_browser_process->local_state()));
 
+  content::MediaCaptureDevices::GetInstance()->AddVideoCaptureObserver(
+      CrasAudioHandler::Get());
+
   quirks::QuirksManager::Initialize(
       std::unique_ptr<quirks::QuirksManager::Delegate>(
           new quirks::QuirksManagerDelegateImpl()),
@@ -930,6 +934,8 @@
   // Stops all in-flight OAuth2 token fetchers before the IO thread stops.
   DeviceOAuth2TokenServiceFactory::Shutdown();
 
+  content::MediaCaptureDevices::GetInstance()->RemoveAllVideoCaptureObservers();
+
   // Shutdown after PostMainMessageLoopRun() which should destroy all observers.
   CrasAudioHandler::Shutdown();
 
diff --git a/chrome/browser/chromeos/extensions/default_app_order.cc b/chrome/browser/chromeos/extensions/default_app_order.cc
index 5d692b4d..8c6aa89 100644
--- a/chrome/browser/chromeos/extensions/default_app_order.cc
+++ b/chrome/browser/chromeos/extensions/default_app_order.cc
@@ -13,13 +13,13 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/macros.h"
 #include "base/path_service.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/genius_app/app_id.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chromeos/chromeos_paths.h"
-#include "content/public/browser/browser_thread.h"
 #include "extensions/common/constants.h"
 
 namespace chromeos {
@@ -132,7 +132,9 @@
   loader_instance = this;
 
   if (async) {
-    content::BrowserThread::PostBlockingPoolTask(FROM_HERE,
+    base::PostTaskWithTraits(
+        FROM_HERE, base::TaskTraits().MayBlock().WithPriority(
+                       base::TaskPriority::USER_VISIBLE),
         base::Bind(&ExternalLoader::Load, base::Unretained(this)));
   } else {
     Load();
diff --git a/chrome/browser/chromeos/extensions/info_private_api.cc b/chrome/browser/chromeos/extensions/info_private_api.cc
index 3eb609e..c023ece9a 100644
--- a/chrome/browser/chromeos/extensions/info_private_api.cc
+++ b/chrome/browser/chromeos/extensions/info_private_api.cc
@@ -135,6 +135,15 @@
 // JS.
 const char kPlayStoreStatusEnabled[] = "enabled";
 
+// Key which corresponds to the managedDeviceStatus property in JS.
+const char kPropertyManagedDeviceStatus[] = "managedDeviceStatus";
+
+// Value to which managedDeviceStatus property is set for unmanaged devices.
+const char kManagedDeviceStatusNotManaged[] = "not managed";
+
+// Value to which managedDeviceStatus property is set for managed devices.
+const char kManagedDeviceStatusManaged[] = "managed";
+
 const struct {
   const char* api_name;
   const char* preference_name;
@@ -268,6 +277,15 @@
     return new base::StringValue(kPlayStoreStatusNotAvailable);
   }
 
+  if (property_name == kPropertyManagedDeviceStatus) {
+    policy::BrowserPolicyConnectorChromeOS* connector =
+        g_browser_process->platform_part()->browser_policy_connector_chromeos();
+    if (connector->IsEnterpriseManaged()) {
+      return new base::StringValue(kManagedDeviceStatusManaged);
+    }
+    return new base::StringValue(kManagedDeviceStatusNotManaged);
+  }
+
   if (property_name == kPropertyClientId) {
     return new base::StringValue(GetClientId());
   }
diff --git a/chrome/browser/chromeos/extensions/info_private_apitest.cc b/chrome/browser/chromeos/extensions/info_private_apitest.cc
index 10fc352..7036c32 100644
--- a/chrome/browser/chromeos/extensions/info_private_apitest.cc
+++ b/chrome/browser/chromeos/extensions/info_private_apitest.cc
@@ -4,7 +4,9 @@
 
 #include "base/values.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/settings/stub_install_attributes.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
@@ -112,3 +114,29 @@
                                         "arc available"))
       << message_;
 }
+
+class ChromeOSManagedDeviceInfoPrivateTest : public ChromeOSInfoPrivateTest {
+ public:
+  ChromeOSManagedDeviceInfoPrivateTest() = default;
+  ~ChromeOSManagedDeviceInfoPrivateTest() override = default;
+
+ protected:
+  void SetUpInProcessBrowserTestFixture() override {
+    // Set up fake install attributes.
+    std::unique_ptr<chromeos::StubInstallAttributes> attributes =
+        base::MakeUnique<chromeos::StubInstallAttributes>();
+    attributes->SetEnterprise("fake-domain", "fake-id");
+    policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
+        attributes.release());
+    ChromeOSInfoPrivateTest::SetUpInProcessBrowserTestFixture();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChromeOSManagedDeviceInfoPrivateTest);
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeOSManagedDeviceInfoPrivateTest, Managed) {
+  ASSERT_TRUE(
+      RunPlatformAppTestWithArg("chromeos_info_private/extended", "managed"))
+      << message_;
+}
diff --git a/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc b/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc
index cf849b1..e19be6e 100644
--- a/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc
+++ b/chrome/browser/chromeos/first_run/goodies_displayer_browsertest.cc
@@ -33,7 +33,7 @@
     // Create a new browser and wait for completion.
     ui_test_utils::BrowserAddedObserver browser_added_observer;
     Browser* browser = new Browser(
-        Browser::CreateParams(ProfileManager::GetActiveUserProfile()));
+        Browser::CreateParams(ProfileManager::GetActiveUserProfile(), true));
     browser_added_observer.WaitForSingleNewBrowser();
 
     // Set up Goodies Displayer and set fake age of device.
@@ -124,8 +124,8 @@
   ASSERT_EQ(1u, chrome::GetTotalBrowserCount());
 
   // Shouldn't show Goodies tab in incognito mode.
-  Browser* incognito_browser = new Browser(
-      Browser::CreateParams(browser->profile()->GetOffTheRecordProfile()));
+  Browser* incognito_browser = new Browser(Browser::CreateParams(
+      browser->profile()->GetOffTheRecordProfile(), true));
   ASSERT_EQ(2u, chrome::GetTotalBrowserCount());
   AddBlankTabAndShow(incognito_browser);
   ExpectTabCounts(incognito_browser, 1, 0);
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc
index d3b7cc16..c4750353 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_storage.h"
 #include "chrome/browser/chromeos/login/quick_unlock/pin_storage_factory.h"
+#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,22 +25,15 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/strings/grit/ui_strings.h"
 
-namespace {
-
-const char kDelegateId[] = "quickunlock_delegate";
-const char kNotificationId[] = "quickunlock_notification";
-const char kChromeAuthenticationSettingsURL[] =
-    "chrome://md-settings/quickUnlock/authenticate";
-
-void UpdatePreferenceForProfile(Profile* profile) {
-  PrefService* pref_service = profile->GetPrefs();
-  pref_service->SetBoolean(prefs::kQuickUnlockFeatureNotificationShown, true);
-}
-
-}  // namespace
-
 namespace chromeos {
 namespace quick_unlock {
+namespace {
+
+constexpr char kPinDelegateId[] = "pinunlock_delegate";
+constexpr char kPinNotificationId[] = "pinunlock_notification";
+constexpr char kPinSetupUrl[] = "chrome://md-settings/lockScreen";
+
+}  // namespace
 
 QuickUnlockNotificationController::QuickUnlockNotificationController(
     Profile* profile)
@@ -53,9 +47,34 @@
 }
 
 // static
-// TODO(http://crbug.com/291747): Add check for a policy that might disable
-// quick unlock.
-bool QuickUnlockNotificationController::ShouldShow(Profile* profile) {
+QuickUnlockNotificationController*
+QuickUnlockNotificationController::CreateForPin(Profile* profile) {
+  QuickUnlockNotificationController* controller =
+      new QuickUnlockNotificationController(profile);
+
+  // Set the PIN notification parameters.
+  controller->params_.delegate_id = kPinDelegateId;
+  controller->params_.title_message_id =
+      IDS_ASH_QUICK_UNLOCK_NOTIFICATION_TITLE;
+  controller->params_.body_message_id = IDS_ASH_QUICK_UNLOCK_NOTIFICATION_BODY;
+  controller->params_.icon_id = IDR_SCREENSHOT_NOTIFICATION_ICON;
+  controller->params_.notifier = ash::system_notifier::kNotifierQuickUnlock;
+  controller->params_.feature_name_id =
+      IDS_MESSAGE_CENTER_NOTIFIER_QUICK_UNLOCK_FEATURE_NAME;
+  controller->params_.notification_id = kPinNotificationId;
+  controller->params_.url = GURL(kPinSetupUrl);
+  controller->params_.was_shown_pref_id =
+      prefs::kQuickUnlockFeatureNotificationShown;
+
+  controller->should_show_notification_callback_ =
+      base::Bind(&QuickUnlockNotificationController::ShouldShowPinNotification);
+
+  return controller;
+}
+
+// static
+bool QuickUnlockNotificationController::ShouldShowPinNotification(
+    Profile* profile) {
   // Do not show notification if this is a guest session.
   if (profile->IsGuestSession())
     return false;
@@ -66,6 +85,11 @@
     return false;
   }
 
+  // Do not show notification if policy does not allow PIN, or if user is
+  // supervised.
+  if (!IsPinEnabled(profile->GetPrefs()))
+    return false;
+
   // Do not show the notification if the pin is already set.
   PinStorage* pin_storage = PinStorageFactory::GetForProfile(profile);
   if (pin_storage->IsPinSet())
@@ -77,7 +101,7 @@
 
 // NotificationDelegate override:
 std::string QuickUnlockNotificationController::id() const {
-  return kDelegateId;
+  return params_.delegate_id;
 }
 
 void QuickUnlockNotificationController::Observe(
@@ -98,38 +122,42 @@
 
   // The user may have enabled the quick unlock feature during the current
   // session and after the notificaiton controller has already been initialized.
-  if (!ShouldShow(profile_)) {
-    UpdatePreferenceForProfile(profile_);
+  DCHECK(!should_show_notification_callback_.is_null());
+  if (should_show_notification_callback_.Run(profile_)) {
+    SetNotificationPreferenceWasShown();
     return;
   }
 
-  // Create and add notification to notification manager.
-  std::unique_ptr<Notification> notification(CreateNotification());
+  std::unique_ptr<Notification> notification = CreateNotification();
   g_browser_process->notification_ui_manager()->Add(*notification, profile_);
 }
 
 // message_center::NotificationDelegate override:
 void QuickUnlockNotificationController::Close(bool by_user) {
   if (by_user)
-    UpdatePreferenceForProfile(profile_);
+    SetNotificationPreferenceWasShown();
 }
 
 // message_center::NotificationDelegate override:
 void QuickUnlockNotificationController::Click() {
-  chrome::NavigateParams params(profile_,
-                                GURL(kChromeAuthenticationSettingsURL),
+  chrome::NavigateParams params(profile_, params_.url,
                                 ui::PAGE_TRANSITION_LINK);
   params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
   chrome::Navigate(&params);
 
-  UpdatePreferenceForProfile(profile_);
+  SetNotificationPreferenceWasShown();
 
   // Remove the notification from tray.
   g_browser_process->notification_ui_manager()->CancelById(
       id(), NotificationUIManager::GetProfileID(profile_));
 }
 
+void QuickUnlockNotificationController::SetNotificationPreferenceWasShown() {
+  PrefService* pref_service = profile_->GetPrefs();
+  pref_service->SetBoolean(params_.was_shown_pref_id, true);
+}
+
 void QuickUnlockNotificationController::UnregisterObserver() {
   if (registrar_.IsRegistered(this,
                               chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
@@ -139,21 +167,24 @@
   }
 }
 
-Notification* QuickUnlockNotificationController::CreateNotification() {
-  return new Notification(
+std::unique_ptr<Notification>
+QuickUnlockNotificationController::CreateNotification() {
+  return base::MakeUnique<Notification>(
       message_center::NOTIFICATION_TYPE_SIMPLE,
-      l10n_util::GetStringUTF16(IDS_ASH_QUICK_UNLOCK_NOTIFICATION_TITLE),
-      l10n_util::GetStringUTF16(IDS_ASH_QUICK_UNLOCK_NOTIFICATION_BODY),
+      l10n_util::GetStringUTF16(params_.title_message_id),
+      l10n_util::GetStringUTF16(params_.body_message_id),
       // TODO(http://crbug.com/291747): Change this to actual icon for
       // quick unlock feature notification.
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-          IDR_SCREENSHOT_NOTIFICATION_ICON),
+      ui::ResourceBundle::GetSharedInstance().GetImageNamed(params_.icon_id),
       message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
-                                 ash::system_notifier::kNotifierQuickUnlock),
-      l10n_util::GetStringUTF16(
-          IDS_MESSAGE_CENTER_NOTIFIER_QUICK_UNLOCK_FEATURE_NAME),
-      GURL(), kNotificationId, message_center::RichNotificationData(), this);
+                                 params_.notifier),
+      l10n_util::GetStringUTF16(params_.feature_name_id), GURL(),
+      params_.notification_id, message_center::RichNotificationData(), this);
 }
 
-}  // namespace quick_unlock
+QuickUnlockNotificationController::NotificationParams::NotificationParams() {}
+
+QuickUnlockNotificationController::NotificationParams::~NotificationParams() {}
+
+}  // quick_unlock
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.h b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.h
index d72eaa1..eb93f6b 100644
--- a/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.h
+++ b/chrome/browser/chromeos/login/quick_unlock/quick_unlock_notification_controller.h
@@ -10,9 +10,10 @@
 #include "chrome/browser/notifications/notification_delegate.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "url/gurl.h"
 
-class Profile;
 class Notification;
+class Profile;
 
 namespace chromeos {
 namespace quick_unlock {
@@ -22,30 +23,54 @@
 class QuickUnlockNotificationController : public NotificationDelegate,
                                           public content::NotificationObserver {
  public:
-  explicit QuickUnlockNotificationController(Profile* profile);
+  static QuickUnlockNotificationController* CreateForPin(Profile* profile);
 
   // Returns true if the notification needs to be displayed for the given
   // |profile|.
-  static bool ShouldShow(Profile* profile);
+  static bool ShouldShowPinNotification(Profile* profile);
 
-  // content::NotificationObserver implementation.
+  // content::NotificationObserver:
   void Observe(int type,
                const content::NotificationSource& source,
                const content::NotificationDetails& details) override;
 
  private:
+  // Parameters that differ between two quick unlock notifications.
+  struct NotificationParams {
+    NotificationParams();
+    ~NotificationParams();
+
+    std::string delegate_id;
+    int title_message_id;
+    int body_message_id;
+    int icon_id;
+    std::string notifier;
+    int feature_name_id;
+    std::string notification_id;
+    GURL url;
+    std::string was_shown_pref_id;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(NotificationParams);
+  };
+
+  explicit QuickUnlockNotificationController(Profile* profile);
   ~QuickUnlockNotificationController() override;
 
-  // NotificationDelegate overrides:
+  // NotificationDelegate:
   void Close(bool by_user) override;
   void Click() override;
   std::string id() const override;
 
-  Notification* CreateNotification();
+  std::unique_ptr<Notification> CreateNotification();
+  void SetNotificationPreferenceWasShown();
   void UnregisterObserver();
 
   Profile* profile_;
   content::NotificationRegistrar registrar_;
+  NotificationParams params_;
+  // Function that determines whether this notification should be shown or not.
+  base::Callback<bool(Profile*)> should_show_notification_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(QuickUnlockNotificationController);
 };
diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
index 630b1d2..8b7336e9a 100644
--- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc
+++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc
@@ -41,6 +41,8 @@
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/media/webrtc/media_permission.h"
 #include "chrome/browser/policy/test/local_policy_test_server.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/signin/signin_utils.h"
@@ -61,6 +63,8 @@
 #include "chromeos/dbus/shill_manager_client.h"
 #include "chromeos/login/auth/key.h"
 #include "chromeos/settings/cros_settings_names.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/guest_view/browser/test_guest_view_manager.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
@@ -960,6 +964,7 @@
   void SetSAMLOfflineSigninTimeLimitPolicy(int limit);
   void EnableTransferSAMLCookiesPolicy();
   void SetLoginBehaviorPolicyToSAMLInterstitial();
+  void SetLoginVideoCaptureAllowedUrls(const std::vector<GURL>& allowed);
 
   void ShowGAIALoginForm();
   void ShowSAMLInterstitial();
@@ -1095,6 +1100,23 @@
   run_loop.Run();
 }
 
+void SAMLPolicyTest::SetLoginVideoCaptureAllowedUrls(
+    const std::vector<GURL>& allowed) {
+  em::ChromeDeviceSettingsProto& proto(device_policy_->payload());
+  for (const GURL& url : allowed)
+    proto.mutable_login_video_capture_allowed_urls()->add_urls(url.spec());
+
+  base::RunLoop run_loop;
+  std::unique_ptr<CrosSettings::ObserverSubscription> observer =
+      CrosSettings::Get()->AddSettingsObserver(kLoginVideoCaptureAllowedUrls,
+                                               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();
+}
+
 void SAMLPolicyTest::ShowGAIALoginForm() {
   login_screen_load_observer_->Wait();
   ASSERT_TRUE(content::ExecuteScript(
@@ -1406,4 +1428,61 @@
   session_start_waiter.Wait();
 }
 
+// Ensure that the permission status of getUserMedia requests from SAML login
+// pages is controlled by the kLoginVideoCaptureAllowedUrls pref rather than the
+// underlying user content setting.
+IN_PROC_BROWSER_TEST_F(SAMLPolicyTest, TestLoginMediaPermission) {
+  fake_saml_idp()->SetLoginHTMLTemplate("saml_login.html");
+
+  const GURL url1("https://google.com");
+  const GURL url2("https://example.com");
+  const GURL url3("https://not-allowed.com");
+  SetLoginVideoCaptureAllowedUrls({url1, url2});
+  WaitForSigninScreen();
+
+  content::WebContents* web_contents = GetLoginUI()->GetWebContents();
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents->GetBrowserContext());
+  content::MediaStreamRequestResult reason;
+
+  // Mic should always be blocked.
+  {
+    MediaPermission permission(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, url1,
+                               url1, profile, web_contents);
+    EXPECT_EQ(CONTENT_SETTING_BLOCK, permission.GetPermissionStatus(&reason));
+  }
+
+  // Camera should be allowed if allowed by the whitelist, otherwise blocked.
+  {
+    MediaPermission permission(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, url1,
+                               url1, profile, web_contents);
+    EXPECT_EQ(CONTENT_SETTING_ALLOW, permission.GetPermissionStatus(&reason));
+  }
+
+  {
+    MediaPermission permission(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, url2,
+                               url2, profile, web_contents);
+    EXPECT_EQ(CONTENT_SETTING_ALLOW, permission.GetPermissionStatus(&reason));
+  }
+
+  {
+    MediaPermission permission(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, url3,
+                               url3, profile, web_contents);
+    EXPECT_EQ(CONTENT_SETTING_BLOCK, permission.GetPermissionStatus(&reason));
+  }
+
+  // Camera should be blocked in the login screen, even if it's allowed via
+  // content setting.
+  {
+    HostContentSettingsMapFactory::GetForProfile(profile)
+        ->SetContentSettingDefaultScope(
+            url3, url3, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(),
+            CONTENT_SETTING_ALLOW);
+
+    MediaPermission permission(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, url3,
+                               url3, profile, web_contents);
+    EXPECT_EQ(CONTENT_SETTING_BLOCK, permission.GetPermissionStatus(&reason));
+  }
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 2a78309..b304a280 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1775,11 +1775,12 @@
   if (HatsNotificationController::ShouldShowSurveyToProfile(profile))
     hats_notification_controller_ = new HatsNotificationController(profile);
 
-  if (quick_unlock::QuickUnlockNotificationController::ShouldShow(profile) &&
+  if (quick_unlock::QuickUnlockNotificationController::
+          ShouldShowPinNotification(profile) &&
       quick_unlock_notification_handler_.find(profile) ==
           quick_unlock_notification_handler_.end()) {
     auto* qu_feature_notification_controller =
-        new quick_unlock::QuickUnlockNotificationController(profile);
+        quick_unlock::QuickUnlockNotificationController::CreateForPin(profile);
     quick_unlock_notification_handler_.insert(
         std::make_pair(profile, qu_feature_notification_controller));
   }
diff --git a/chrome/browser/chromeos/login/ui/webui_login_view.cc b/chrome/browser/chromeos/login/ui/webui_login_view.cc
index 83d3f302..dd302079 100644
--- a/chrome/browser/chromeos/login/ui/webui_login_view.cc
+++ b/chrome/browser/chromeos/login/ui/webui_login_view.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/chromeos/login/ui/web_contents_set_background_color.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
@@ -42,7 +41,6 @@
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/network/network_state.h"
 #include "chromeos/network/network_state_handler.h"
-#include "chromeos/settings/cros_settings_names.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
@@ -478,46 +476,9 @@
     WebContents* web_contents,
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback) {
+  // Note: This is only needed for SAML logins.
   MediaStreamDevicesController controller(web_contents, request, callback);
-  if (!controller.IsAskingForAudio() && !controller.IsAskingForVideo())
-    return;
-
-  if (controller.IsAskingForAudio()) {
-    controller.PermissionDenied();
-    return;
-  }
-
-  const CrosSettings* const settings = CrosSettings::Get();
-  if (!settings) {
-    controller.PermissionDenied();
-    return;
-  }
-
-  const base::Value* const raw_list_value =
-      settings->GetPref(kLoginVideoCaptureAllowedUrls);
-  if (!raw_list_value) {
-    controller.PermissionDenied();
-    return;
-  }
-
-  const base::ListValue* list_value;
-  CHECK(raw_list_value->GetAsList(&list_value));
-  for (const auto& base_value : *list_value) {
-    std::string value;
-    if (base_value->GetAsString(&value)) {
-      ContentSettingsPattern pattern =
-          ContentSettingsPattern::FromString(value);
-      if (pattern == ContentSettingsPattern::Wildcard()) {
-        LOG(WARNING) << "Ignoring wildcard URL pattern: " << value;
-        continue;
-      }
-      if (pattern.IsValid() && pattern.Matches(request.security_origin)) {
-        controller.PermissionGranted();
-        return;
-      }
-    }
-  }
-  controller.PermissionDenied();
+  DCHECK(!controller.IsAskingForAudio() && !controller.IsAskingForVideo());
 }
 
 bool WebUILoginView::CheckMediaAccessPermission(
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index 875592b..468adc4 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -120,33 +120,14 @@
     DCHECK(document);
     CreatePrintJob(base::UTF16ToUTF8(document->settings().device_name()),
                    base::UTF16ToUTF8(document->settings().title()),
-                   document->page_count());
+                   job_details->job_id(), document->page_count());
   }
 }
 
 bool CupsPrintJobManagerImpl::CreatePrintJob(const std::string& printer_name,
                                              const std::string& title,
+                                             int job_id,
                                              int total_page_number) {
-  // Of the current jobs, find the new one for the printer.
-  ::printing::CupsJob* new_job = nullptr;
-  std::vector<::printing::CupsJob> cups_jobs = cups_connection_.GetJobs();
-  for (auto& job : cups_jobs) {
-    if (printer_name == job.printer_id &&
-        !JobFinished(ConvertState(job.state)) &&
-        !base::ContainsKey(jobs_,
-                           CupsPrintJob::GetUniqueId(printer_name, job.id))) {
-      // We found an untracked job.  It should be ours.
-      new_job = &job;
-      break;
-    }
-  }
-
-  // The started job cannot be found in the queue.
-  if (!new_job) {
-    LOG(WARNING) << "Could not track print job.";
-    return false;
-  }
-
   auto printer =
       chromeos::PrintersManagerFactory::GetForBrowserContext(profile_)
           ->GetPrinter(printer_name);
@@ -157,25 +138,35 @@
   }
 
   // Create a new print job.
-  auto cpj = base::MakeUnique<CupsPrintJob>(*printer, new_job->id, title,
+  auto cpj = base::MakeUnique<CupsPrintJob>(*printer, job_id, title,
                                             total_page_number);
   std::string key = cpj->GetUniqueId();
   jobs_[key] = std::move(cpj);
-  NotifyJobCreated(jobs_[key].get());
+  CupsPrintJob* job = jobs_[key].get();
+  NotifyJobCreated(job);
 
-  JobStateUpdated(jobs_[key].get(), ConvertState(new_job->state));
+  // Always start jobs in the waiting state.
+  job->set_state(CupsPrintJob::State::STATE_WAITING);
+  NotifyJobUpdated(job);
 
-  ScheduleQuery();
+  ScheduleQuery(base::TimeDelta());
 
   return true;
 }
 
 void CupsPrintJobManagerImpl::ScheduleQuery() {
-  content::BrowserThread::PostDelayedTask(
-      content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
-      base::Bind(&CupsPrintJobManagerImpl::QueryCups,
-                 weak_ptr_factory_.GetWeakPtr()),
-      base::TimeDelta::FromMilliseconds(kPollRate));
+  ScheduleQuery(base::TimeDelta::FromMilliseconds(kPollRate));
+}
+
+void CupsPrintJobManagerImpl::ScheduleQuery(const base::TimeDelta& delay) {
+  if (!in_query_) {
+    in_query_ = true;
+    content::BrowserThread::PostDelayedTask(
+        content::BrowserThread::FILE_USER_BLOCKING, FROM_HERE,
+        base::Bind(&CupsPrintJobManagerImpl::QueryCups,
+                   weak_ptr_factory_.GetWeakPtr()),
+        base::TimeDelta::FromMilliseconds(kPollRate));
+  }
 }
 
 // Query CUPS asynchronously.  Post results back to UI thread.
@@ -193,6 +184,9 @@
 // after they are completed.
 void CupsPrintJobManagerImpl::UpdateJobs(
     const std::vector<::printing::CupsJob>& jobs) {
+  in_query_ = false;
+
+  std::vector<std::string> active_jobs;
   for (auto& job : jobs) {
     std::string key = CupsPrintJob::GetUniqueId(job.printer_id, job.id);
     const auto& entry = jobs_.find(key);
@@ -205,13 +199,26 @@
       // Cleanup completed jobs.
       if (JobFinished(print_job->state())) {
         jobs_.erase(entry);
+      } else {
+        active_jobs.push_back(key);
       }
     }
   }
 
   // Keep polling until all jobs complete or error.
-  if (!jobs_.empty())
+  if (!active_jobs.empty()) {
     ScheduleQuery();
+  } else if (!jobs_.empty()) {
+    // We're tracking jobs that we didn't receive an update for.  Something bad
+    // has happened.
+    LOG(ERROR) << "Lost track of (" << jobs_.size() << ") jobs";
+    for (const auto& entry : jobs_) {
+      // Declare all lost jobs errors.
+      JobStateUpdated(entry.second.get(), CupsPrintJob::State::STATE_ERROR);
+    }
+
+    jobs_.clear();
+  }
 }
 
 void CupsPrintJobManagerImpl::JobStateUpdated(CupsPrintJob* job,
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
index 04f0cdb..afd64c9 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.h
@@ -44,10 +44,13 @@
   // |title| with the pages |total_page_number|.
   bool CreatePrintJob(const std::string& printer_name,
                       const std::string& title,
+                      int job_id,
                       int total_page_number);
 
-  // Schedule a query of CUPS for print job status.
+  // Schedule a query of CUPS for print job status with the default delay.
   void ScheduleQuery();
+  // Schedule a query of CUPS for print job status with a delay of |delay|.
+  void ScheduleQuery(const base::TimeDelta& delay);
 
   // Query CUPS for print job status.
   void QueryCups();
@@ -61,6 +64,9 @@
   // Ongoing print jobs.
   std::map<std::string, std::unique_ptr<CupsPrintJob>> jobs_;
 
+  // Prevents multiple queries from being scheduled simultaneously.
+  bool in_query_ = false;
+
   ::printing::CupsConnection cups_connection_;
   content::NotificationRegistrar registrar_;
   base::WeakPtrFactory<CupsPrintJobManagerImpl> weak_ptr_factory_;
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 2e4b828..f0e0d5f 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -1262,6 +1262,14 @@
     if (extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
             .is_empty())
       continue;
+
+    // Each devtools extension will need to be able to run in the devtools
+    // process. Grant each specific extension's origin permission to load
+    // documents.
+    content::ChildProcessSecurityPolicy::GetInstance()->GrantOrigin(
+        web_contents_->GetMainFrame()->GetProcess()->GetID(),
+        url::Origin(extension->url()));
+
     std::unique_ptr<base::DictionaryValue> extension_info(
         new base::DictionaryValue());
     extension_info->Set(
@@ -1275,14 +1283,6 @@
                                 extensions::APIPermission::kExperimental)));
     results.Append(std::move(extension_info));
   }
-  if (!results.empty()) {
-    // At least one devtools extension exists; it will need to run in the
-    // devtools process. Grant it permission to load documents with
-    // chrome-extension:// origins.
-    content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme(
-        web_contents_->GetMainFrame()->GetProcess()->GetID(),
-        extensions::kExtensionScheme);
-  }
 
   CallClientFunction("DevToolsAPI.addExtensions",
                      &results, NULL, NULL);
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 98193c9..a8f8f84 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -3425,9 +3425,7 @@
       sb_service->download_protection_service();
   download_protection_service->feedback_service()->MaybeStorePingsForDownload(
       safe_browsing::DownloadProtectionService::UNCOMMON,
-      downloads[0],
-      ping_request,
-      ping_response);
+      true /* upload_requested */, downloads[0], ping_request, ping_response);
   ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
       *(downloads[0])));
 
@@ -3478,8 +3476,8 @@
   safe_browsing::DownloadProtectionService* download_protection_service =
       sb_service->download_protection_service();
   download_protection_service->feedback_service()->MaybeStorePingsForDownload(
-      safe_browsing::DownloadProtectionService::UNCOMMON, downloads[0],
-      ping_request, ping_response);
+      safe_browsing::DownloadProtectionService::UNCOMMON,
+      true /* upload_requested */, downloads[0], ping_request, ping_response);
   ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
       *(downloads[0])));
 
diff --git a/chrome/browser/download/download_crx_util.cc b/chrome/browser/download/download_crx_util.cc
index a7fa2a7..c2fcb83 100644
--- a/chrome/browser/download/download_crx_util.cc
+++ b/chrome/browser/download/download_crx_util.cc
@@ -49,9 +49,10 @@
     content::WebContents* web_contents = download_item.GetWebContents();
     if (!web_contents) {
       Browser* browser = chrome::FindLastActiveWithProfile(profile);
-      if (!browser)
-        browser =
-            new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+      if (!browser) {
+        browser = new Browser(
+            Browser::CreateParams(Browser::TYPE_TABBED, profile, true));
+      }
       web_contents = browser->tab_strip_model()->GetActiveWebContents();
     }
     return std::unique_ptr<ExtensionInstallPrompt>(
diff --git a/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
index dc02e19..aebbb40 100644
--- a/chrome/browser/extensions/api/autofill_private/autofill_util.cc
+++ b/chrome/browser/extensions/api/autofill_private/autofill_util.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include <utility>
+#include <vector>
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_split.h"
@@ -14,12 +15,12 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/settings_private/prefs_util.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/autofill/country_combobox_model.h"
 #include "chrome/common/extensions/api/autofill_private.h"
 #include "chrome/common/pref_names.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/prefs/pref_service.h"
@@ -190,7 +191,8 @@
 CountryEntryList GenerateCountryList(
     const autofill::PersonalDataManager& personal_data) {
   autofill::CountryComboboxModel model;
-  model.SetCountries(personal_data, base::Callback<bool(const std::string&)>());
+  model.SetCountries(personal_data, base::Callback<bool(const std::string&)>(),
+                     g_browser_process->GetApplicationLocale());
   const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries =
       model.countries();
 
diff --git a/chrome/browser/extensions/api/browser/browser_api.cc b/chrome/browser/extensions/api/browser/browser_api.cc
index 205d583..f9f133b 100644
--- a/chrome/browser/extensions/api/browser/browser_api.cc
+++ b/chrome/browser/extensions/api/browser/browser_api.cc
@@ -24,7 +24,7 @@
 
   std::string error;
   std::unique_ptr<base::DictionaryValue> result(
-      ExtensionTabUtil::OpenTab(this, options, &error));
+      ExtensionTabUtil::OpenTab(this, options, user_gesture(), &error));
   if (!result)
     return RespondNow(Error(error));
 
diff --git a/chrome/browser/extensions/api/debugger/debugger_apitest.cc b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
index acf5b62..b2447222 100644
--- a/chrome/browser/extensions/api/debugger/debugger_apitest.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_apitest.cc
@@ -195,7 +195,8 @@
   scoped_refptr<DebuggerAttachFunction> attach_function;
   scoped_refptr<DebuggerDetachFunction> detach_function;
 
-  Browser* another_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* another_browser =
+      new Browser(Browser::CreateParams(profile(), true));
   AddBlankTabAndShow(another_browser);
   AddBlankTabAndShow(another_browser);
   int tab_id2 = SessionTabHelper::IdForTab(
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 a03451c..5e70782d 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
@@ -304,7 +304,7 @@
   InitializeExtensionService(init_params);
 
   browser_window_.reset(new TestBrowserWindow());
-  Browser::CreateParams params(profile());
+  Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_TABBED;
   params.window = browser_window_.get();
   browser_.reset(new Browser(params));
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
index 876abcc..2d57dda 100644
--- a/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
+++ b/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc
@@ -542,7 +542,7 @@
   Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
   base::RunLoop().RunUntilIdle();  // Wait for profile initialization.
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile));
+      new Browser(Browser::CreateParams(incognito_profile, true));
 
   ASSERT_EQ(0,
             BrowserActionTestUtil(incognito_browser).NumberOfBrowserActions());
@@ -576,7 +576,7 @@
   // Open an incognito window.
   Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile));
+      new Browser(Browser::CreateParams(incognito_profile, true));
   base::RunLoop().RunUntilIdle();  // Wait for profile initialization.
   // Navigate just to have a tab in this window, otherwise wonky things happen.
   OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_apitest.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_apitest.cc
index 52a6820..d948ac1e 100644
--- a/chrome/browser/extensions/api/gcd_private/gcd_private_apitest.cc
+++ b/chrome/browser/extensions/api/gcd_private/gcd_private_apitest.cc
@@ -90,6 +90,7 @@
     command_line->AppendSwitchASCII(
         extensions::switches::kWhitelistedExtensionID,
         "ddchlicdkolnonkihahngkmmmjnjlkkf");
+    command_line->AppendSwitch(switches::kDisableDeviceDiscoveryNotifications);
   }
 
   std::unique_ptr<net::FakeURLFetcher> CreateFakeURLFetcher(
@@ -142,8 +143,7 @@
       test_service_discovery_client_;
 };
 
-// Flaky on Linux(dbg). https://crbug.com/689305
-IN_PROC_BROWSER_TEST_F(GcdPrivateWithMdnsAPITest, DISABLED_DeviceInfo) {
+IN_PROC_BROWSER_TEST_F(GcdPrivateWithMdnsAPITest, DeviceInfo) {
   test_service_discovery_client_->SimulateReceive(kAnnouncePacket,
                                                   sizeof(kAnnouncePacket));
   url_fetcher_factory_.SetFakeResponse(GURL("http://1.2.3.4:8888/privet/info"),
diff --git a/chrome/browser/extensions/api/log_private/log_private_apitest_chromeos.cc b/chrome/browser/extensions/api/log_private/log_private_apitest_chromeos.cc
index 6a9d490..245cff89 100644
--- a/chrome/browser/extensions/api/log_private/log_private_apitest_chromeos.cc
+++ b/chrome/browser/extensions/api/log_private/log_private_apitest_chromeos.cc
@@ -7,11 +7,11 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/fake_debug_daemon_client.h"
-#include "content/public/browser/browser_thread.h"
 #include "extensions/common/extension_builder.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
@@ -36,9 +36,10 @@
                      const GetDebugLogsCallback& callback) override {
     // dup() is needed as the file descriptor will be closed on the client side.
     base::File* file_param = new base::File(dup(file_descriptor));
-    content::BrowserThread::PostBlockingPoolTaskAndReply(
-        FROM_HERE, base::Bind(&GenerateTestLogDumpFile, test_file_,
-                              base::Owned(file_param)),
+    base::PostTaskWithTraitsAndReply(
+        FROM_HERE, base::TaskTraits().MayBlock(),
+        base::Bind(&GenerateTestLogDumpFile, test_file_,
+                   base::Owned(file_param)),
         base::Bind(callback, true));
   }
 
diff --git a/chrome/browser/extensions/api/management/management_api_unittest.cc b/chrome/browser/extensions/api/management/management_api_unittest.cc
index 26b4f6a..59d0593 100644
--- a/chrome/browser/extensions/api/management/management_api_unittest.cc
+++ b/chrome/browser/extensions/api/management/management_api_unittest.cc
@@ -93,7 +93,7 @@
                                                        &BuildEventRouter);
 
   browser_window_.reset(new TestBrowserWindow());
-  Browser::CreateParams params(profile());
+  Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_TABBED;
   params.window = browser_window_.get();
   browser_.reset(new Browser(params));
diff --git a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
index caa46e7..28b9010 100644
--- a/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
+++ b/chrome/browser/extensions/api/permissions/permissions_api_unittest.cc
@@ -74,7 +74,7 @@
     ExtensionServiceTestWithInstall::SetUp();
     InitializeEmptyExtensionService();
     browser_window_.reset(new TestBrowserWindow());
-    Browser::CreateParams params(profile());
+    Browser::CreateParams params(profile(), true);
     params.type = Browser::TYPE_TABBED;
     params.window = browser_window_.get();
     browser_.reset(new Browser(params));
diff --git a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
index 1f9948c2..54395bd 100644
--- a/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
+++ b/chrome/browser/extensions/api/runtime/chrome_runtime_api_delegate.cc
@@ -258,7 +258,7 @@
   Profile* profile = Profile::FromBrowserContext(browser_context_);
   Browser* browser = chrome::FindLastActiveWithProfile(profile);
   if (!browser)
-    browser = new Browser(Browser::CreateParams(profile));
+    browser = new Browser(Browser::CreateParams(profile, false));
 
   chrome::NavigateParams params(
       browser, uninstall_url, ui::PAGE_TRANSITION_CLIENT_REDIRECT);
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 9abe2ef..a0e02b7 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -235,7 +235,7 @@
   EXPECT_CALL(*service, AddObserver(testing::_)).Times(testing::AnyNumber());
   EXPECT_CALL(*service, RemoveObserver(testing::_)).Times(testing::AnyNumber());
 
-  browser_ = new Browser(Browser::CreateParams(profile));
+  browser_ = new Browser(Browser::CreateParams(profile, true));
 
   service->Initialize();
 }
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 325a624..0f50871 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -589,13 +589,15 @@
 #endif  // defined(USE_ASH)
 
   // Create a new BrowserWindow.
-  Browser::CreateParams create_params(window_type, window_profile);
+  Browser::CreateParams create_params(window_type, window_profile,
+                                      user_gesture());
   if (extension_id.empty()) {
     create_params.initial_bounds = window_bounds;
   } else {
     create_params = Browser::CreateParams::CreateForApp(
         web_app::GenerateApplicationNameFromExtensionId(extension_id),
-        false /* trusted_source */, window_bounds, window_profile);
+        false /* trusted_source */, window_bounds, window_profile,
+        user_gesture());
   }
   create_params.initial_show_state = ui::SHOW_STATE_NORMAL;
   if (create_data && create_data->state) {
@@ -1004,7 +1006,7 @@
 
   std::string error;
   std::unique_ptr<base::DictionaryValue> result(
-      ExtensionTabUtil::OpenTab(this, options, &error));
+      ExtensionTabUtil::OpenTab(this, options, user_gesture(), &error));
   if (!result)
     return RespondNow(Error(error));
 
diff --git a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
index 1128010..26a3e9c 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api_unittest.cc
@@ -68,7 +68,7 @@
     content::BrowserSideNavigationSetUp();
 
   browser_window_.reset(new TestBrowserWindow());
-  Browser::CreateParams params(profile());
+  Browser::CreateParams params(profile(), true);
   params.type = Browser::TYPE_TABBED;
   params.window = browser_window_.get();
   browser_.reset(new Browser(params));
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 5df6a2a4..c519fd0 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -173,7 +173,7 @@
 
   // Popup.
   Browser* popup_browser = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   function = new WindowsGetFunction();
   function->set_extension(extension.get());
   result.reset(utils::ToDictionary(
@@ -644,7 +644,7 @@
   // a new tab in it. Tab should not be opened in the popup window, but in a
   // tabbed browser window.
   Browser* popup_browser = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   int window_id = ExtensionTabUtil::GetWindowId(popup_browser);
   chrome::CloseWindow(popup_browser);
 
@@ -868,9 +868,10 @@
   Browser* new_browser;
   if (as_popup)
     new_browser = new Browser(
-        Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+        Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   else
-    new_browser = new Browser(Browser::CreateParams(browser()->profile()));
+    new_browser =
+        new Browser(Browser::CreateParams(browser()->profile(), true));
   AddBlankTabAndShow(new_browser);
   return new_browser;
 }
@@ -1255,7 +1256,7 @@
       " \"maxWidth\": 400, \"maxHeight\": 400}}");
 
   Browser* browser_window =
-      new Browser(Browser::CreateParams(browser()->profile()));
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   AddBlankTabAndShow(browser_window);
 
   DevToolsWindow* devtools_window =
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
index 3feaa460..2616a756 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc
@@ -383,7 +383,8 @@
     const GURL& url,
     const content::Referrer& referrer,
     WindowOpenDisposition disposition,
-    ui::PageTransition transition) {
+    ui::PageTransition transition,
+    bool started_from_context_menu) {
   if (!navigation_state_.CanSendEvents(source_render_frame_host))
     return;
 
diff --git a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
index c663e68..e467d996 100644
--- a/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
+++ b/chrome/browser/extensions/api/web_navigation/web_navigation_api.h
@@ -68,7 +68,8 @@
                            const GURL& url,
                            const content::Referrer& referrer,
                            WindowOpenDisposition disposition,
-                           ui::PageTransition transition) override;
+                           ui::PageTransition transition,
+                           bool started_from_context_menu) override;
   void WebContentsDestroyed() override;
 
   // This method dispatches the already created onBeforeNavigate event.
diff --git a/chrome/browser/extensions/extension_context_menu_model_unittest.cc b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
index fe073222..93b27ce 100644
--- a/chrome/browser/extensions/extension_context_menu_model_unittest.cc
+++ b/chrome/browser/extensions/extension_context_menu_model_unittest.cc
@@ -183,7 +183,7 @@
 
 Browser* ExtensionContextMenuModelTest::GetBrowser() {
   if (!browser_) {
-    Browser::CreateParams params(profile());
+    Browser::CreateParams params(profile(), true);
     test_window_.reset(new TestBrowserWindow());
     params.window = test_window_.get();
     browser_.reset(new Browser(params));
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 9e28e8c..602c473 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -95,8 +95,11 @@
   return NULL;
 }
 
-Browser* CreateBrowser(Profile* profile, int window_id, std::string* error) {
-  Browser::CreateParams params(Browser::TYPE_TABBED, profile);
+Browser* CreateBrowser(Profile* profile,
+                       int window_id,
+                       bool user_gesture,
+                       std::string* error) {
+  Browser::CreateParams params(Browser::TYPE_TABBED, profile, user_gesture);
   Browser* browser = new Browser(params);
   browser->window()->Show();
   return browser;
@@ -126,6 +129,7 @@
 base::DictionaryValue* ExtensionTabUtil::OpenTab(
     UIThreadExtensionFunction* function,
     const OpenTabParams& params,
+    bool user_gesture,
     std::string* error) {
   ChromeExtensionFunctionDetails chrome_details(function);
   Profile* profile = chrome_details.GetProfile();
@@ -139,7 +143,7 @@
     if (!params.create_browser_if_needed) {
       return NULL;
     }
-    browser = CreateBrowser(profile, window_id, error);
+    browser = CreateBrowser(profile, window_id, user_gesture, error);
     if (!browser)
       return NULL;
   }
@@ -215,8 +219,9 @@
 
     browser = chrome::FindTabbedBrowser(profile, false);
     if (!browser) {
-      browser =
-          new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+      Browser::CreateParams params =
+          Browser::CreateParams(Browser::TYPE_TABBED, profile, user_gesture);
+      browser = new Browser(params);
       browser->window()->Show();
     }
   }
@@ -583,8 +588,10 @@
       Profile::FromBrowserContext(web_contents->GetBrowserContext());
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   const bool browser_created = !browser;
-  if (!browser)
-    browser = new Browser(Browser::CreateParams(profile));
+  if (!browser) {
+    Browser::CreateParams params = Browser::CreateParams(profile, user_gesture);
+    browser = new Browser(params);
+  }
   chrome::NavigateParams params(browser, web_contents);
 
   // The extension_app_id parameter ends up as app_name in the Browser
@@ -636,7 +643,7 @@
   DCHECK(!profile->IsOffTheRecord() || IncognitoInfo::IsSplitMode(extension));
   Browser* browser = chrome::FindBrowserWithProfile(profile);
   if (!browser)
-    browser = new Browser(Browser::CreateParams(profile));
+    browser = new Browser(Browser::CreateParams(profile, true));
   return extensions::ExtensionTabUtil::OpenOptionsPage(extension, browser);
 }
 
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h
index 06dac73a..40107b3 100644
--- a/chrome/browser/extensions/extension_tab_util.h
+++ b/chrome/browser/extensions/extension_tab_util.h
@@ -58,6 +58,7 @@
   // optionally sets |error| if an error occurs.
   static base::DictionaryValue* OpenTab(UIThreadExtensionFunction* function,
                                         const OpenTabParams& params,
+                                        bool user_gesture,
                                         std::string* error);
 
   static int GetWindowId(const Browser* browser);
diff --git a/chrome/browser/icon_loader_chromeos.cc b/chrome/browser/icon_loader_chromeos.cc
index 52ae44d7..30f0005 100644
--- a/chrome/browser/icon_loader_chromeos.cc
+++ b/chrome/browser/icon_loader_chromeos.cc
@@ -192,7 +192,9 @@
 
 // static
 content::BrowserThread::ID IconLoader::ReadIconThreadID() {
-  return content::BrowserThread::FILE;
+  // ReadIcon touches non thread safe ResourceBundle images, so it must be on
+  // the UI thread.
+  return content::BrowserThread::UI;
 }
 
 void IconLoader::ReadIcon() {
diff --git a/chrome/browser/media/webrtc/media_permission.cc b/chrome/browser/media/webrtc/media_permission.cc
index 278f7ed..064d4ae 100644
--- a/chrome/browser/media/webrtc/media_permission.cc
+++ b/chrome/browser/media/webrtc/media_permission.cc
@@ -11,18 +11,32 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/permission_manager.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/common/constants.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/chromeos/login/ui/webui_login_view.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chromeos/settings/cros_settings_names.h"
+#endif
+
 MediaPermission::MediaPermission(ContentSettingsType content_type,
                                  const GURL& requesting_origin,
                                  const GURL& embedding_origin,
-                                 Profile* profile)
+                                 Profile* profile,
+                                 content::WebContents* web_contents)
     : content_type_(content_type),
       requesting_origin_(requesting_origin),
       embedding_origin_(embedding_origin),
-      profile_(profile) {}
+      profile_(profile),
+      web_contents_(web_contents) {
+  // Currently |web_contents_| is only used on ChromeOS but it's not worth
+  // #ifdef'ing out all its usage, so just mark it used here.
+  (void)web_contents_;
+}
 
 ContentSetting MediaPermission::GetPermissionStatus(
     content::MediaStreamRequestResult* denial_reason) const {
@@ -41,6 +55,56 @@
     return CONTENT_SETTING_BLOCK;
   }
 
+#if defined(OS_CHROMEOS)
+  // Special permissions if the request is coming from a ChromeOS login page.
+  chromeos::LoginDisplayHost* login_display_host =
+      chromeos::LoginDisplayHost::default_host();
+  chromeos::WebUILoginView* webui_login_view =
+      login_display_host ? login_display_host->GetWebUILoginView() : nullptr;
+  content::WebContents* login_web_contents =
+      webui_login_view ? webui_login_view->GetWebContents() : nullptr;
+  if (web_contents_ == login_web_contents) {
+    if (content_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
+      *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+      return CONTENT_SETTING_BLOCK;
+    }
+
+    const chromeos::CrosSettings* const settings =
+        chromeos::CrosSettings::Get();
+    if (!settings) {
+      *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+      return CONTENT_SETTING_BLOCK;
+    }
+
+    const base::Value* const raw_list_value =
+        settings->GetPref(chromeos::kLoginVideoCaptureAllowedUrls);
+    if (!raw_list_value) {
+      *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+      return CONTENT_SETTING_BLOCK;
+    }
+
+    const base::ListValue* list_value;
+    const bool is_list = raw_list_value->GetAsList(&list_value);
+    DCHECK(is_list);
+    for (const auto& base_value : *list_value) {
+      std::string value;
+      if (base_value->GetAsString(&value)) {
+        const ContentSettingsPattern pattern =
+            ContentSettingsPattern::FromString(value);
+        if (pattern == ContentSettingsPattern::Wildcard()) {
+          LOG(WARNING) << "Ignoring wildcard URL pattern: " << value;
+          continue;
+        }
+        if (pattern.IsValid() && pattern.Matches(requesting_origin_))
+          return CONTENT_SETTING_ALLOW;
+      }
+    }
+
+    *denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
+    return CONTENT_SETTING_BLOCK;
+  }
+#endif  // defined(OS_CHROMEOS)
+
   // Check policy and content settings.
   blink::mojom::PermissionStatus status =
       permission_manager->GetPermissionStatus(
diff --git a/chrome/browser/media/webrtc/media_permission.h b/chrome/browser/media/webrtc/media_permission.h
index 708ae39..1ab5471 100644
--- a/chrome/browser/media/webrtc/media_permission.h
+++ b/chrome/browser/media/webrtc/media_permission.h
@@ -15,13 +15,18 @@
 
 class Profile;
 
+namespace content {
+class WebContents;
+}
+
 // Represents a permission for microphone/camera access.
 class MediaPermission {
  public:
   MediaPermission(ContentSettingsType content_type,
                   const GURL& requesting_origin,
                   const GURL& embedding_origin,
-                  Profile* profile);
+                  Profile* profile,
+                  content::WebContents* web_contents);
 
   // Returns the status of the permission. If the setting is
   // CONTENT_SETTING_BLOCK, |denial_reason| will output the reason for it being
@@ -43,6 +48,7 @@
   const GURL embedding_origin_;
   const std::string device_id_;
   Profile* const profile_;
+  content::WebContents* const web_contents_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaPermission);
 };
diff --git a/chrome/browser/media/webrtc/media_stream_devices_controller.cc b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
index cccf4f8..bd1228f 100644
--- a/chrome/browser/media/webrtc/media_stream_devices_controller.cc
+++ b/chrome/browser/media/webrtc/media_stream_devices_controller.cc
@@ -546,7 +546,8 @@
     DCHECK(content::IsOriginSecure(request_.security_origin) ||
            request_.request_type == content::MEDIA_OPEN_DEVICE_PEPPER_ONLY);
     MediaPermission permission(content_type, request.security_origin,
-        web_contents_->GetLastCommittedURL().GetOrigin(), profile_);
+                               web_contents_->GetLastCommittedURL().GetOrigin(),
+                               profile_, web_contents_);
     return permission.GetPermissionStatusWithDeviceRequired(requested_device_id,
                                                             denial_reason);
   }
diff --git a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
index 0f68772..6911a3a3 100644
--- a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
@@ -104,7 +104,7 @@
 
   MediaPermission permission(content_settings_type, security_origin,
                              web_contents->GetLastCommittedURL().GetOrigin(),
-                             profile);
+                             profile, web_contents);
   content::MediaStreamRequestResult unused;
   return permission.GetPermissionStatus(&unused) == CONTENT_SETTING_ALLOW;
 }
diff --git a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
index 5f5d501e..3ad2de00 100644
--- a/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/webrtc/tab_desktop_media_list_unittest.cc
@@ -171,7 +171,7 @@
     ASSERT_TRUE(profile_);
 
     // Create browser.
-    Browser::CreateParams profile_params(profile_);
+    Browser::CreateParams profile_params(profile_, true);
     browser_ = chrome::CreateBrowserWithTestWindowForParams(&profile_params);
     ASSERT_TRUE(browser_);
     for (int i = 0; i < kDefaultSourceCount; i++) {
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
index cc07c690..f7bf8fb 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -23,6 +23,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "chrome/browser/media_galleries/chromeos/mtp_device_task_helper_map_service.h"
 #include "chrome/browser/media_galleries/chromeos/snapshot_file_details.h"
 #include "net/base/io_buffer.h"
@@ -349,9 +350,11 @@
 
 // Deletes a temporary file |file_path|.
 void DeleteTemporaryFile(const base::FilePath& file_path) {
-  content::BrowserThread::PostBlockingPoolTask(
-      FROM_HERE, base::Bind(base::IgnoreResult(base::DeleteFile), file_path,
-                            false /* not recursive*/));
+  base::PostTaskWithTraits(FROM_HERE,
+                           base::TaskTraits().MayBlock().WithPriority(
+                               base::TaskPriority::BACKGROUND),
+                           base::Bind(base::IgnoreResult(base::DeleteFile),
+                                      file_path, false /* not recursive*/));
 }
 
 // A fake callback to be passed as CopyFileProgressCallback.
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc
index a51ede4..c371d73 100644
--- a/chrome/browser/metrics/metrics_service_browsertest.cc
+++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -58,6 +58,15 @@
 }  // namespace
 #endif  // OS_MACOSX || OS_LINUX
 
+// This test class verifies that metrics reporting works correctly for various
+// renderer behaviors such as page loads, recording crashed tabs, and browser
+// starts. It also verifies that if a renderer process crashes, the correct exit
+// code is recorded.
+//
+// TODO(isherman): We should also verify that
+// metrics::prefs::kStabilityExitedCleanly is set correctly after each of these
+// tests, but this preference isn't set until the browser exits... it's not
+// clear to me how to test that.
 class MetricsServiceBrowserTest : public InProcessBrowserTest {
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
@@ -65,8 +74,39 @@
     command_line->AppendSwitch(switches::kMetricsRecordingOnly);
   }
 
+  // Open three tabs then navigate to |crashy_url| and wait for the renderer to
+  // crash.
+  void OpenTabsAndNavigateToCrashyUrl(const std::string& crashy_url) {
+    // Opens three tabs.
+    OpenThreeTabs();
+
+    // Kill the process for one of the tabs by navigating to |crashy_url|.
+    content::RenderProcessHostWatcher observer(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+    // Opens one tab.
+    ui_test_utils::NavigateToURL(browser(), GURL(crashy_url));
+    observer.Wait();
+
+    // The MetricsService listens for the same notification, so the |observer|
+    // might finish waiting before the MetricsService has a chance to process
+    // the notification.  To avoid racing here, we repeatedly run the message
+    // loop until the MetricsService catches up.  This should happen "real soon
+    // now", since the notification is posted to all observers essentially
+    // simultaneously... so busy waiting here shouldn't be too bad.
+    const PrefService* prefs = g_browser_process->local_state();
+    while (!prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount)) {
+      content::RunAllPendingInMessageLoop();
+    }
+  }
+
   // Open a couple of tabs of random content.
-  void OpenTabs() {
+  //
+  // Calling this method causes three page load events:
+  // 1. title2.html
+  // 2. iframe.html
+  // 3. title1.html (iframed by iframe.html)
+  void OpenThreeTabs() {
     const int kBrowserTestFlags =
         ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
         ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION;
@@ -87,17 +127,13 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, CloseRenderersNormally) {
-  OpenTabs();
+  OpenThreeTabs();
 
   // Verify that the expected stability metrics were recorded.
   const PrefService* prefs = g_browser_process->local_state();
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
   EXPECT_EQ(3, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
   EXPECT_EQ(0, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
-  // TODO(isherman): We should also verify that
-  // metrics::prefs::kStabilityExitedCleanly
-  // is set to true, but this preference isn't set until the browser
-  // exits... it's not clear to me how to test that.
 }
 
 // Flaky on Linux. See http://crbug.com/131094
@@ -105,44 +141,23 @@
 // crbug.com/368525).
 #if defined(OS_LINUX) || defined(ADDRESS_SANITIZER)
 #define MAYBE_CrashRenderers DISABLED_CrashRenderers
+#define MAYBE_CheckCrashRenderers DISABLED_CheckCrashRenderers
 #else
 #define MAYBE_CrashRenderers CrashRenderers
+#define MAYBE_CheckCrashRenderers CheckCrashRenderers
 #endif
+
 IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CrashRenderers) {
   base::HistogramTester histogram_tester;
-  OpenTabs();
 
-  // Kill the process for one of the tabs.
-  content::RenderProcessHostWatcher observer(
-      browser()->tab_strip_model()->GetActiveWebContents(),
-      content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  ui_test_utils::NavigateToURL(browser(), GURL(content::kChromeUICrashURL));
-  observer.Wait();
-
-  // The MetricsService listens for the same notification, so the |observer|
-  // might finish waiting before the MetricsService has a chance to process the
-  // notification.  To avoid racing here, we repeatedly run the message loop
-  // until the MetricsService catches up.  This should happen "real soon now",
-  // since the notification is posted to all observers essentially
-  // simultaneously... so busy waiting here shouldn't be too bad.
-  const PrefService* prefs = g_browser_process->local_state();
-  while (!prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount)) {
-    content::RunAllPendingInMessageLoop();
-  }
+  OpenTabsAndNavigateToCrashyUrl(content::kChromeUICrashURL);
 
   // Verify that the expected stability metrics were recorded.
+  const PrefService* prefs = g_browser_process->local_state();
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
-  // Expect four page loads:
-  // 1. title2.html
-  // 2. iframe.html
-  // 3. title1.html (iframed by iframe.html)
-  // 4. chrome://crash
+  // The three tabs from OpenTabs() and the one tab to open chrome://crash/.
   EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
-  // TODO(isherman): We should also verify that
-  // metrics::prefs::kStabilityExitedCleanly
-  // is set to true, but this preference isn't set until the browser
-  // exits... it's not clear to me how to test that.
 
 #if defined(OS_WIN)
   histogram_tester.ExpectUniqueSample(
@@ -154,33 +169,41 @@
   histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1);
 }
 
+IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, MAYBE_CheckCrashRenderers) {
+  base::HistogramTester histogram_tester;
+
+  OpenTabsAndNavigateToCrashyUrl(content::kChromeUICheckCrashURL);
+
+  // Verify that the expected stability metrics were recorded.
+  const PrefService* prefs = g_browser_process->local_state();
+  EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
+  // The three tabs from OpenTabs() and the one tab to open
+  // chrome://checkcrash/.
+  EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
+  EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
+
+#if defined(OS_WIN)
+  histogram_tester.ExpectUniqueSample(
+      "CrashExitCodes.Renderer",
+      std::abs(static_cast<int32_t>(STATUS_BREAKPOINT)), 1);
+#elif defined(OS_MACOSX) || defined(OS_LINUX)
+  VerifyRendererExitCodeIsSignal(histogram_tester, SIGTRAP);
+#endif
+  histogram_tester.ExpectUniqueSample("Tabs.SadTab.CrashCreated", 1, 1);
+}
+
 // OOM code only works on Windows.
 #if defined(OS_WIN) && !defined(ADDRESS_SANITIZER)
 IN_PROC_BROWSER_TEST_F(MetricsServiceBrowserTest, OOMRenderers) {
   base::HistogramTester histogram_tester;
-  OpenTabs();
 
-  // Kill the process for one of the tabs.
-  content::RenderProcessHostWatcher observer(
-      browser()->tab_strip_model()->GetActiveWebContents(),
-      content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
-  ui_test_utils::NavigateToURL(browser(),
-                               GURL(content::kChromeUIMemoryExhaustURL));
-  observer.Wait();
-
-  // The MetricsService listens for the same notification, so the |observer|
-  // might finish waiting before the MetricsService has a chance to process the
-  // notification.  To avoid racing here, we repeatedly run the message loop
-  // until the MetricsService catches up.  This should happen "real soon now",
-  // since the notification is posted to all observers essentially
-  // simultaneously... so busy waiting here shouldn't be too bad.
-  const PrefService* prefs = g_browser_process->local_state();
-  while (!prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount)) {
-    content::RunAllPendingInMessageLoop();
-  }
+  OpenTabsAndNavigateToCrashyUrl(content::kChromeUIMemoryExhaustURL);
 
   // Verify that the expected stability metrics were recorded.
+  const PrefService* prefs = g_browser_process->local_state();
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityLaunchCount));
+  // The three tabs from OpenTabs() and the one tab to open
+  // chrome://memory-exhaust/.
   EXPECT_EQ(4, prefs->GetInteger(metrics::prefs::kStabilityPageLoadCount));
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
 
diff --git a/chrome/browser/net/sdch_browsertest.cc b/chrome/browser/net/sdch_browsertest.cc
index 257f7a78..74ad70d 100644
--- a/chrome/browser/net/sdch_browsertest.cc
+++ b/chrome/browser/net/sdch_browsertest.cc
@@ -441,7 +441,7 @@
         second_profile_data_dir_.GetPath());
     if (!second_profile_) return false;
 
-    second_browser_ = new Browser(Browser::CreateParams(second_profile_));
+    second_browser_ = new Browser(Browser::CreateParams(second_profile_, true));
     if (!second_browser_) return false;
 
     chrome::AddSelectedTabWithURL(second_browser_,
diff --git a/chrome/browser/prefetch/prefetch_browsertest.cc b/chrome/browser/prefetch/prefetch_browsertest.cc
index 9adb78d..19112909 100644
--- a/chrome/browser/prefetch/prefetch_browsertest.cc
+++ b/chrome/browser/prefetch/prefetch_browsertest.cc
@@ -135,7 +135,7 @@
 IN_PROC_BROWSER_TEST_F(PrefetchBrowserTestPrediction, IncognitoTest) {
   Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile));
+      new Browser(Browser::CreateParams(incognito_profile, true));
 
   // Navigate just to have a tab in this window, otherwise there is no
   // WebContents for the incognito browser.
diff --git a/chrome/browser/printing/cloud_print/privet_url_fetcher.cc b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
index 1135e21..7575feb 100644
--- a/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
+++ b/chrome/browser/printing/cloud_print/privet_url_fetcher.cc
@@ -11,7 +11,6 @@
 #include <memory>
 
 #include "base/bind.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
 #include "base/memory/singleton.h"
@@ -202,8 +201,6 @@
   DCHECK_EQ(tries_, 0);  // We haven't called |Start()| yet.
 
   if (!url_.is_valid()) {
-    // Not yet clear why it's possible. crbug.com/513505
-    base::debug::DumpWithoutCrashing();
     return delegate_->OnError(this, UNKNOWN_ERROR);
   }
 
diff --git a/chrome/browser/profiles/avatar_menu_actions_desktop.cc b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
index 1d22aa30..6db41b6 100644
--- a/chrome/browser/profiles/avatar_menu_actions_desktop.cc
+++ b/chrome/browser/profiles/avatar_menu_actions_desktop.cc
@@ -27,7 +27,8 @@
 
   Browser* settings_browser = browser_;
   if (!settings_browser) {
-    const Browser::CreateParams params(ProfileManager::GetLastUsedProfile());
+    const Browser::CreateParams params(ProfileManager::GetLastUsedProfile(),
+                                       true);
     settings_browser = new Browser(params);
   }
   chrome::ShowSettingsSubPage(settings_browser, chrome::kCreateProfileSubPage);
@@ -37,7 +38,7 @@
 void AvatarMenuActionsDesktop::EditProfile(Profile* profile) {
   Browser* settings_browser = browser_;
   if (!settings_browser) {
-    settings_browser = new Browser(Browser::CreateParams(profile));
+    settings_browser = new Browser(Browser::CreateParams(profile, true));
   }
   // TODO(davidben): The manageProfile page only allows editting the profile
   // associated with the browser it is opened in. AvatarMenuActionsDesktop
diff --git a/chrome/browser/profiles/profile_manager_unittest.cc b/chrome/browser/profiles/profile_manager_unittest.cc
index 6a66ac55..f5c4ef1 100644
--- a/chrome/browser/profiles/profile_manager_unittest.cc
+++ b/chrome/browser/profiles/profile_manager_unittest.cc
@@ -713,7 +713,7 @@
   ASSERT_EQ(0U, last_opened_profiles.size());
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1);
+  Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1a(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
@@ -722,7 +722,7 @@
   EXPECT_EQ(profile1, last_opened_profiles[0]);
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2);
+  Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -775,12 +775,12 @@
   ASSERT_TRUE(profile2);
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1);
+  Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile2);
+  Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -825,7 +825,7 @@
   ASSERT_EQ(0U, last_opened_profiles.size());
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(profile1);
+  Browser::CreateParams profile1_params(profile1, true);
   std::unique_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
@@ -834,7 +834,8 @@
   EXPECT_EQ(profile1, last_opened_profiles[0]);
 
   // And for profile2.
-  Browser::CreateParams profile2_params(profile1->GetOffTheRecordProfile());
+  Browser::CreateParams profile2_params(profile1->GetOffTheRecordProfile(),
+                                        true);
   std::unique_ptr<Browser> browser2a(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
@@ -884,7 +885,7 @@
   EXPECT_NE(profile, last_used_profile);
 
   // Create a browser for the profile.
-  Browser::CreateParams profile_params(profile);
+  Browser::CreateParams profile_params(profile, true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
   last_used_profile = profile_manager->GetLastUsedProfile();
@@ -926,16 +927,16 @@
   ASSERT_TRUE(ephemeral_profile2);
 
   // Create a browser for profile1.
-  Browser::CreateParams profile1_params(normal_profile);
+  Browser::CreateParams profile1_params(normal_profile, true);
   std::unique_ptr<Browser> browser1(
       chrome::CreateBrowserWithTestWindowForParams(&profile1_params));
 
   // Create browsers for the ephemeral profile.
-  Browser::CreateParams profile2_params(ephemeral_profile1);
+  Browser::CreateParams profile2_params(ephemeral_profile1, true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
 
-  Browser::CreateParams profile3_params(ephemeral_profile2);
+  Browser::CreateParams profile3_params(ephemeral_profile2, true);
   std::unique_ptr<Browser> browser3(
       chrome::CreateBrowserWithTestWindowForParams(&profile3_params));
 
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index c2f9143..f86db71 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -49,7 +49,6 @@
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "chrome/browser/tab_contents/retargeting_details.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/translate/translate_service.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -1966,24 +1965,6 @@
       content::NotificationService::NoDetails());
 }
 
-void RenderViewContextMenu::NotifyURLOpened(
-    const GURL& url,
-    content::WebContents* new_contents) {
-  RetargetingDetails details;
-  details.source_web_contents = source_web_contents_;
-  // Don't use GetRenderFrameHost() as it may be NULL. crbug.com/399789
-  details.source_render_process_id = render_process_id_;
-  details.source_render_frame_id = render_frame_id_;
-  details.target_url = url;
-  details.target_web_contents = new_contents;
-  details.not_yet_in_tabstrip = false;
-
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_RETARGETING,
-      content::Source<Profile>(GetProfile()),
-      content::Details<RetargetingDetails>(&details));
-}
-
 base::string16 RenderViewContextMenu::PrintableSelectionText() {
   return gfx::TruncateString(params_.selection_text,
                              kMaxSelectionTextLength,
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index ef8b1a8..0239d2c 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -121,8 +121,6 @@
   void HandleAuthorizeAllPlugins() override;
 #endif
   void NotifyMenuShown() override;
-  void NotifyURLOpened(const GURL& url,
-                       content::WebContents* new_contents) override;
 
   // Gets the extension (if any) associated with the WebContents that we're in.
   const extensions::Extension* GetExtension() const;
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index 610515a..df40e77 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -464,8 +464,7 @@
         var extensionId = extension.id;
         assert(this.extensions_.length > 0);
         var newEx = this.extensions_.filter(function(e) {
-          return e.state == chrome.developerPrivate.ExtensionState.ENABLED &&
-              e.id == extensionId;
+          return e.id == extensionId;
         })[0];
         var errors = newEx.manifestErrors.concat(newEx.runtimeErrors);
         extensions.ExtensionErrorOverlay.getInstance().setErrorsAndShowOverlay(
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
index 5d5f101b..605336d0 100644
--- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js
@@ -60,22 +60,30 @@
 
   /** @private */
   onDisplayTap_: function() {
-    settings.navigateTo(settings.Route.DISPLAY);
+    settings.navigateTo(
+        settings.Route.DISPLAY,
+        /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onAppearanceTap_: function() {
-    settings.navigateTo(settings.Route.APPEARANCE);
+    settings.navigateTo(
+        settings.Route.APPEARANCE,
+        /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onKeyboardTap_: function() {
-    settings.navigateTo(settings.Route.KEYBOARD);
+    settings.navigateTo(
+        settings.Route.KEYBOARD,
+        /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
   onMouseTap_: function() {
-    settings.navigateTo(settings.Route.POINTERS);
+    settings.navigateTo(
+        settings.Route.POINTERS,
+        /* dynamicParams */ null, /* removeSearch */ true);
   },
 
   /** @private */
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js
index 5dbfd54..3b57658 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js
+++ b/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.js
@@ -36,7 +36,7 @@
 
     if (this.model) {
       this.dialogTitle_ = loadTimeData.getString('onStartupEditPage');
-      this.actionButtonText_ = loadTimeData.getString('edit');
+      this.actionButtonText_ = loadTimeData.getString('save');
       this.$.actionButton.disabled = false;
       // Pre-populate the input field.
       this.url_ = this.model.url;
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.js b/chrome/browser/resources/settings/settings_menu/settings_menu.js
index 306f691..122f10a 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.js
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.js
@@ -9,6 +9,8 @@
 Polymer({
   is: 'settings-menu',
 
+  behaviors: [settings.RouteObserverBehavior],
+
   properties: {
     advancedOpened: {
       type: Boolean,
@@ -29,18 +31,20 @@
     'subMenu.tap': 'onLinkTap_',
   },
 
-  /** @override */
-  attached: function() {
-    var currentPath = settings.getCurrentRoute().path;
+  /** @param {!settings.Route} newRoute */
+  currentRouteChanged: function(newRoute) {
+    var currentPath = newRoute.path;
 
     // Focus the initially selected path.
     var anchors = this.root.querySelectorAll('a');
     for (var i = 0; i < anchors.length; ++i) {
       if (anchors[i].getAttribute('href') == currentPath) {
         this.setSelectedUrl_(anchors[i].href);
-        break;
+        return;
       }
     }
+
+    this.setSelectedUrl_('');  // Nothing is selected.
   },
 
   /**
diff --git a/chrome/browser/safe_browsing/download_feedback_service.cc b/chrome/browser/safe_browsing/download_feedback_service.cc
index 656c804..adebf92 100644
--- a/chrome/browser/safe_browsing/download_feedback_service.cc
+++ b/chrome/browser/safe_browsing/download_feedback_service.cc
@@ -91,19 +91,19 @@
 // static
 void DownloadFeedbackService::MaybeStorePingsForDownload(
     DownloadProtectionService::DownloadCheckResult result,
+    bool upload_requested,
     content::DownloadItem* download,
     const std::string& ping,
     const std::string& response) {
-  switch (result) {
-    case DownloadProtectionService::UNKNOWN:
-    case DownloadProtectionService::SAFE:
-    case DownloadProtectionService::DANGEROUS:
-      return;
-    case DownloadProtectionService::UNCOMMON:
-    case DownloadProtectionService::DANGEROUS_HOST:
-    case DownloadProtectionService::POTENTIALLY_UNWANTED:
-      break;  // Fall through.
-  }
+  // We never upload SAFE files.
+  if (result == DownloadProtectionService::SAFE)
+    return;
+
+  UMA_HISTOGRAM_BOOLEAN("SBDownloadFeedback.UploadRequestedByServer",
+                        upload_requested);
+  if (!upload_requested)
+    return;
+
   UMA_HISTOGRAM_COUNTS("SBDownloadFeedback.SizeEligibleKB",
                        download->GetReceivedBytes() / 1024);
   if (download->GetReceivedBytes() > DownloadFeedback::kMaxUploadSize)
diff --git a/chrome/browser/safe_browsing/download_feedback_service.h b/chrome/browser/safe_browsing/download_feedback_service.h
index 474e4d8..ae87ad3 100644
--- a/chrome/browser/safe_browsing/download_feedback_service.h
+++ b/chrome/browser/safe_browsing/download_feedback_service.h
@@ -42,10 +42,13 @@
 
   // Stores the request and response ping data from the download check, if the
   // check result and file size are eligible. This must be called after a
-  // download has been flagged as malicious in order for the download to be
-  // enabled for uploading.
+  // download has been flagged as un-SAFE in order for the download to be
+  // enabled for uploading. Some un-SAFE downloads can be marked for
+  // upload by the server with |upload_requested| if it's needed for better
+  // classification.
   static void MaybeStorePingsForDownload(
       DownloadProtectionService::DownloadCheckResult result,
+      bool upload_requested,
       content::DownloadItem* download,
       const std::string& ping,
       const std::string& response);
diff --git a/chrome/browser/safe_browsing/download_feedback_service_unittest.cc b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
index c4cdd824..9779a0d 100644
--- a/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_feedback_service_unittest.cc
@@ -113,12 +113,14 @@
 };
 
 bool WillStorePings(DownloadProtectionService::DownloadCheckResult result,
+                    bool upload_requested,
                     int64_t size) {
   content::MockDownloadItem item;
   EXPECT_CALL(item, GetReceivedBytes()).WillRepeatedly(Return(size));
 
   EXPECT_FALSE(DownloadFeedbackService::IsEnabledForDownload(item));
-  DownloadFeedbackService::MaybeStorePingsForDownload(result, &item, "a", "b");
+  DownloadFeedbackService::MaybeStorePingsForDownload(result, upload_requested,
+                                                      &item, "a", "b");
   return DownloadFeedbackService::IsEnabledForDownload(item);
 }
 
@@ -172,21 +174,42 @@
   const int64_t ok_size = DownloadFeedback::kMaxUploadSize;
   const int64_t bad_size = DownloadFeedback::kMaxUploadSize + 1;
 
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, ok_size));
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, ok_size));
-  EXPECT_TRUE(WillStorePings(DownloadProtectionService::UNCOMMON, ok_size));
-  EXPECT_TRUE(
-      WillStorePings(DownloadProtectionService::DANGEROUS_HOST, ok_size));
-  EXPECT_TRUE(
-      WillStorePings(DownloadProtectionService::POTENTIALLY_UNWANTED, ok_size));
+  std::vector<bool> upload_requests = {false, true};
+  for (bool upload_requested : upload_requests) {
+    // SAFE will never upload
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE,
+                                upload_requested, ok_size));
+    // Others will upload if requested.
+    EXPECT_EQ(upload_requested,
+              WillStorePings(DownloadProtectionService::UNKNOWN,
+                             upload_requested, ok_size));
+    EXPECT_EQ(upload_requested,
+              WillStorePings(DownloadProtectionService::DANGEROUS,
+                             upload_requested, ok_size));
+    EXPECT_EQ(upload_requested,
+              WillStorePings(DownloadProtectionService::UNCOMMON,
+                             upload_requested, ok_size));
+    EXPECT_EQ(upload_requested,
+              WillStorePings(DownloadProtectionService::DANGEROUS_HOST,
+                             upload_requested, ok_size));
+    EXPECT_EQ(upload_requested,
+              WillStorePings(DownloadProtectionService::POTENTIALLY_UNWANTED,
+                             upload_requested, ok_size));
 
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE, bad_size));
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS, bad_size));
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::UNCOMMON, bad_size));
-  EXPECT_FALSE(
-      WillStorePings(DownloadProtectionService::DANGEROUS_HOST, bad_size));
-  EXPECT_FALSE(WillStorePings(DownloadProtectionService::POTENTIALLY_UNWANTED,
-                              bad_size));
+    // Bad sizes never upload
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::SAFE,
+                                upload_requested, bad_size));
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::UNKNOWN,
+                                upload_requested, bad_size));
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS,
+                                upload_requested, bad_size));
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::UNCOMMON,
+                                upload_requested, bad_size));
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::DANGEROUS_HOST,
+                                upload_requested, bad_size));
+    EXPECT_FALSE(WillStorePings(DownloadProtectionService::POTENTIALLY_UNWANTED,
+                                upload_requested, bad_size));
+  }
 }
 
 TEST_F(DownloadFeedbackServiceTest, SingleFeedbackCompleteAndDiscardDownload) {
@@ -206,8 +229,9 @@
 
   DownloadFeedbackService service(request_context_getter_.get(),
                                   file_task_runner_.get());
-  service.MaybeStorePingsForDownload(
-      DownloadProtectionService::UNCOMMON, &item, ping_request, ping_response);
+  service.MaybeStorePingsForDownload(DownloadProtectionService::UNCOMMON,
+                                     true /* upload_requested */, &item,
+                                     ping_request, ping_response);
   ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item));
   service.BeginFeedbackForDownload(&item, DownloadCommands::DISCARD);
   ASSERT_FALSE(download_discarded_callback.is_null());
@@ -247,7 +271,8 @@
 
   DownloadFeedbackService service(request_context_getter_.get(),
                                   file_task_runner_.get());
-  service.MaybeStorePingsForDownload(DownloadProtectionService::UNCOMMON, &item,
+  service.MaybeStorePingsForDownload(DownloadProtectionService::UNCOMMON,
+                                     true /* upload_requested */, &item,
                                      ping_request, ping_response);
   ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item));
   service.BeginFeedbackForDownload(&item, DownloadCommands::KEEP);
@@ -286,8 +311,8 @@
     EXPECT_CALL(item[i], StealDangerousDownload(true, _))
         .WillOnce(SaveArg<1>(&download_discarded_callback[i]));
     DownloadFeedbackService::MaybeStorePingsForDownload(
-        DownloadProtectionService::UNCOMMON, &item[i], ping_request,
-        ping_response);
+        DownloadProtectionService::UNCOMMON, true /* upload_requested */,
+        &item[i], ping_request, ping_response);
     ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i]));
   }
 
@@ -355,8 +380,8 @@
     EXPECT_CALL(item[i], StealDangerousDownload(true, _))
         .WillOnce(SaveArg<1>(&download_discarded_callback[i]));
     DownloadFeedbackService::MaybeStorePingsForDownload(
-        DownloadProtectionService::UNCOMMON, &item[i], ping_request,
-        ping_response);
+        DownloadProtectionService::UNCOMMON, true /* upload_requested */,
+        &item[i], ping_request, ping_response);
     ASSERT_TRUE(DownloadFeedbackService::IsEnabledForDownload(item[i]));
   }
 
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index cdd7d73..c9f6953 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -597,8 +597,9 @@
       if (!token.empty())
         SetDownloadPingToken(item_, token);
 
+      bool upload_requested = response.upload();
       DownloadFeedbackService::MaybeStorePingsForDownload(
-          result, item_, client_download_request_data_, data);
+          result, upload_requested, item_, client_download_request_data_, data);
     }
     // We don't need the fetcher anymore.
     fetcher_.reset();
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index 04a4657..5c40564 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -395,9 +395,11 @@
   void PrepareResponse(net::FakeURLFetcherFactory* factory,
                        ClientDownloadResponse::Verdict verdict,
                        net::HttpStatusCode response_code,
-                       net::URLRequestStatus::Status status) {
+                       net::URLRequestStatus::Status status,
+                       bool upload_requested = false) {
     ClientDownloadResponse response;
     response.set_verdict(verdict);
+    response.set_upload(upload_requested);
     factory->SetFakeResponse(
         DownloadProtectionService::GetDownloadRequestUrl(),
         response.SerializeAsString(),
@@ -1041,11 +1043,11 @@
               MatchDownloadWhitelistUrl(_))
       .WillRepeatedly(Return(false));
   EXPECT_CALL(*binary_feature_extractor_.get(), CheckSignature(tmp_path_, _))
-      .Times(7);
+      .Times(8);
   EXPECT_CALL(*binary_feature_extractor_.get(),
               ExtractImageFeatures(
                   tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _))
-      .Times(7);
+      .Times(8);
   std::string feedback_ping;
   std::string feedback_response;
   ClientDownloadResponse expected_response;
@@ -1079,9 +1081,10 @@
   }
   {
     // If the response is dangerous the result should also be marked as
-    // dangerous.
+    // dangerous, and should not upload if not requested.
     PrepareResponse(&factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK,
-                    net::URLRequestStatus::SUCCESS);
+                    net::URLRequestStatus::SUCCESS,
+                    false /* upload_requested */);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1094,9 +1097,27 @@
     ClearClientDownloadRequest();
   }
   {
+    // If the response is dangerous and the server requests an upload,
+    // we should upload.
+    PrepareResponse(&factory, ClientDownloadResponse::DANGEROUS, net::HTTP_OK,
+                    net::URLRequestStatus::SUCCESS,
+                    true /* upload_requested */);
+    RunLoop run_loop;
+    download_service_->CheckClientDownload(
+        &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
+                          base::Unretained(this), run_loop.QuitClosure()));
+    run_loop.Run();
+    EXPECT_TRUE(DownloadFeedbackService::GetPingsForDownloadForTesting(
+        item, &feedback_ping, &feedback_response));
+    EXPECT_TRUE(IsResult(DownloadProtectionService::DANGEROUS));
+    EXPECT_TRUE(HasClientDownloadRequest());
+    ClearClientDownloadRequest();
+  }
+  {
     // If the response is uncommon the result should also be marked as uncommon.
     PrepareResponse(&factory, ClientDownloadResponse::UNCOMMON, net::HTTP_OK,
-                    net::URLRequestStatus::SUCCESS);
+                    net::URLRequestStatus::SUCCESS,
+                    true /* upload_requested */);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1109,6 +1130,7 @@
     EXPECT_TRUE(decoded_request.ParseFromString(feedback_ping));
     EXPECT_EQ(url_chain_.back().spec(), decoded_request.url());
     expected_response.set_verdict(ClientDownloadResponse::UNCOMMON);
+    expected_response.set_upload(true);
     EXPECT_EQ(expected_response.SerializeAsString(), feedback_response);
     EXPECT_TRUE(HasClientDownloadRequest());
     ClearClientDownloadRequest();
@@ -1117,7 +1139,8 @@
     // If the response is dangerous_host the result should also be marked as
     // dangerous_host.
     PrepareResponse(&factory, ClientDownloadResponse::DANGEROUS_HOST,
-                    net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+                    net::HTTP_OK, net::URLRequestStatus::SUCCESS,
+                    true /* upload_requested */);
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1127,6 +1150,7 @@
     EXPECT_TRUE(DownloadFeedbackService::GetPingsForDownloadForTesting(
         item, &feedback_ping, &feedback_response));
     expected_response.set_verdict(ClientDownloadResponse::DANGEROUS_HOST);
+    expected_response.set_upload(true);
     EXPECT_EQ(expected_response.SerializeAsString(), feedback_response);
     EXPECT_TRUE(HasClientDownloadRequest());
     ClearClientDownloadRequest();
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index 6a3ca19..58c8d59 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -528,7 +528,7 @@
   if (browser->type() != Browser::TYPE_TABBED) {
     browser = chrome::FindTabbedBrowser(profile, false);
     if (!browser)
-      browser = new Browser(Browser::CreateParams(profile));
+      browser = new Browser(Browser::CreateParams(profile, false));
   }
   GlobalErrorService* global_error_service =
       GlobalErrorServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc
index 96809f7..a753866 100644
--- a/chrome/browser/sessions/better_session_restore_browsertest.cc
+++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -547,7 +547,7 @@
   // which stores a session cookie.
   StoreDataWithPage("session_cookies.html");
   Browser* popup = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   popup->window()->Show();
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), false);
@@ -826,7 +826,7 @@
                        SessionCookiesBrowserCloseWithPopupOpen) {
   StoreDataWithPage("session_cookies.html");
   Browser* popup = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   popup->window()->Show();
   Browser* new_browser = QuitBrowserAndRestore(browser(), false);
   NavigateAndCheckStoredData(new_browser, "session_cookies.html");
@@ -838,7 +838,7 @@
                        SessionCookiesBrowserClosePopupLast) {
   StoreDataWithPage("session_cookies.html");
   Browser* popup = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   popup->window()->Show();
   CloseBrowserSynchronously(browser());
   Browser* new_browser = QuitBrowserAndRestore(popup, false);
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index 0e4d121..eeafc2d 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -213,10 +213,9 @@
 
     bool use_new_window = disposition == WindowOpenDisposition::NEW_WINDOW;
 
-    Browser* browser =
-        use_new_window
-            ? new Browser(Browser::CreateParams(profile_))
-            : browser_;
+    Browser* browser = use_new_window
+                           ? new Browser(Browser::CreateParams(profile_, true))
+                           : browser_;
 
     RecordAppLaunchForTab(browser, tab, selected_index);
 
@@ -293,7 +292,7 @@
                                std::vector<RestoredTab>* contents_created) {
     Browser* browser = nullptr;
     if (!created_tabbed_browser && always_create_tabbed_browser_) {
-      browser = new Browser(Browser::CreateParams(profile_));
+      browser = new Browser(Browser::CreateParams(profile_, false));
       if (urls_to_open_.empty()) {
         // No tab browsers were created and no URLs were supplied on the command
         // line. Open the new tab page.
@@ -630,11 +629,11 @@
                                  const std::string& workspace,
                                  ui::WindowShowState show_state,
                                  const std::string& app_name) {
-    Browser::CreateParams params(type, profile_);
+    Browser::CreateParams params(type, profile_, false);
     if (!app_name.empty()) {
       const bool trusted_source = true;  // We only store trusted app windows.
       params = Browser::CreateParams::CreateForApp(app_name, trusted_source,
-                                                   bounds, profile_);
+                                                   bounds, profile_, false);
     } else {
       params.initial_bounds = bounds;
     }
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc
index c3a0a36..eece71e7 100644
--- a/chrome/browser/sessions/session_restore_browsertest.cc
+++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -487,7 +487,7 @@
   // Create a new popup.
   Profile* profile = browser()->profile();
   Browser* popup =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile));
+      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
   popup->window()->Show();
 
   // Close the browser.
diff --git a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
index 8ffe884d..de48f66 100644
--- a/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
+++ b/chrome/browser/sessions/session_restore_browsertest_chromeos.cc
@@ -69,7 +69,7 @@
   Browser::CreateParams CreateParamsForApp(const std::string name,
                                            bool trusted) {
     return Browser::CreateParams::CreateForApp(name, trusted, gfx::Rect(),
-                                               profile());
+                                               profile(), true);
   }
 
   // Turn on session restore before we restart.
@@ -91,10 +91,10 @@
   // One browser window is always created by default.
   EXPECT_TRUE(browser());
   // Create a second normal browser window.
-  CreateBrowserWithParams(Browser::CreateParams(profile()));
+  CreateBrowserWithParams(Browser::CreateParams(profile(), true));
   // Create a third incognito browser window which should not get restored.
   CreateBrowserWithParams(
-      Browser::CreateParams(profile()->GetOffTheRecordProfile()));
+      Browser::CreateParams(profile()->GetOffTheRecordProfile(), true));
   TurnOnSessionRestore();
 }
 
@@ -142,7 +142,8 @@
   // One browser window is always created by default.
   ASSERT_TRUE(browser());
   // Create a second browser window and maximize it.
-  Browser* browser2 = CreateBrowserWithParams(Browser::CreateParams(profile()));
+  Browser* browser2 =
+      CreateBrowserWithParams(Browser::CreateParams(profile(), true));
   browser2->window()->Maximize();
 
   // Create two app popup windows and maximize the second one.
@@ -178,7 +179,8 @@
   ASSERT_TRUE(browser());
   browser()->window()->Minimize();
 
-  Browser* browser2 = CreateBrowserWithParams(Browser::CreateParams(profile()));
+  Browser* browser2 =
+      CreateBrowserWithParams(Browser::CreateParams(profile(), true));
   browser2->window()->Minimize();
 
   EXPECT_TRUE(browser()->window()->IsMinimized());
diff --git a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
index f809ba1..e0a50dd 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
@@ -1289,7 +1289,7 @@
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTestWithPasswordCcSwitch,
                        ConsoleMessage) {
   ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate(
-      Browser::CreateParams(browser()->profile()));
+      Browser::CreateParams(browser()->profile(), true));
   content::WebContents* original_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::WebContents* contents =
@@ -1359,7 +1359,7 @@
   ASSERT_TRUE(embedded_test_server()->Start());
   host_resolver()->AddRule("*", embedded_test_server()->GetURL("/").host());
   ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate(
-      Browser::CreateParams(browser()->profile()));
+      Browser::CreateParams(browser()->profile(), true));
   content::WebContents* original_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::WebContents* contents =
@@ -1448,7 +1448,7 @@
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTestWithPasswordCcSwitch,
                        ConsoleMessageNotPrintedForFrameNavigation) {
   ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate(
-      Browser::CreateParams(browser()->profile()));
+      Browser::CreateParams(browser()->profile(), true));
   content::WebContents* original_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::WebContents* contents =
@@ -1529,7 +1529,7 @@
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTestWithPasswordCcSwitch,
                        ConsoleMessageNotPrintedForPushStateNavigation) {
   ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate(
-      Browser::CreateParams(browser()->profile()));
+      Browser::CreateParams(browser()->profile(), true));
   content::WebContents* original_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   content::WebContents* contents =
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 74d6549..782c4f5 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -531,7 +531,8 @@
   profiles_[index] = profile;
 
   // CheckInitialState() assumes that no windows are open at startup.
-  browsers_[index] = new Browser(Browser::CreateParams(GetProfile(index)));
+  browsers_[index] =
+      new Browser(Browser::CreateParams(GetProfile(index), true));
 
   EXPECT_NE(nullptr, GetBrowser(index)) << "Could not create Browser " << index;
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 0737826..09f800b5 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -54,8 +54,6 @@
     "autofill/autofill_popup_view_delegate.h",
     "autofill/chrome_autofill_client.cc",
     "autofill/chrome_autofill_client.h",
-    "autofill/country_combobox_model.cc",
-    "autofill/country_combobox_model.h",
     "autofill/create_card_unmask_prompt_view.h",
     "autofill/credit_card_scanner_controller.cc",
     "autofill/credit_card_scanner_controller.h",
@@ -1518,6 +1516,8 @@
       "views/payments/payment_request_dialog_view.cc",
       "views/payments/payment_request_dialog_view.h",
       "views/payments/payment_request_dialog_view_ids.h",
+      "views/payments/payment_request_item_list.cc",
+      "views/payments/payment_request_item_list.h",
       "views/payments/payment_request_row_view.cc",
       "views/payments/payment_request_row_view.h",
       "views/payments/payment_request_sheet_controller.cc",
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
index bb8a461d..40d7547 100644
--- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
+++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -149,7 +149,8 @@
   // 3) Hosted apps.
   Browser::CreateParams browser_create_params(
       Browser::CreateParams::CreateForApp("Test", true /* trusted_source */,
-                                          gfx::Rect(), browser()->profile()));
+                                          gfx::Rect(), browser()->profile(),
+                                          true));
 
   Browser* app_host_browser = new Browser(browser_create_params);
   ASSERT_TRUE(app_host_browser->is_app());
@@ -169,7 +170,7 @@
 
   // 4) Popup browser windows.
   browser_create_params =
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile());
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true);
   Browser* popup_browser = new Browser(browser_create_params);
   ASSERT_TRUE(popup_browser->is_type_popup());
   ASSERT_FALSE(popup_browser->is_app());
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index e6017cf..f7b2d75 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -507,7 +507,7 @@
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
 
   if (!browser) {
-    browser = new Browser(Browser::CreateParams(profile));
+    browser = new Browser(Browser::CreateParams(profile, true));
     browser->window()->Show();
   }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
index 35323e0..b204f527 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -1717,7 +1717,7 @@
   ash::ShelfID shortcut_id = CreateShortcut("app1");
 
   // Create a new browser - without activating it - and load an "app" into it.
-  Browser::CreateParams params = Browser::CreateParams(profile());
+  Browser::CreateParams params = Browser::CreateParams(profile(), true);
   params.initial_show_state = ui::SHOW_STATE_INACTIVE;
   Browser* browser2 = new Browser(params);
   controller_->SetRefocusURLPatternForTest(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
index b8b6181..ac40fa9 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -993,7 +993,7 @@
                                           gfx::Rect(10, 10, 20, 30));
     Browser::CreateParams params = Browser::CreateParams::CreateForApp(
         kCrxAppPrefix + app_name, true /* trusted_source */, gfx::Rect(),
-        profile);
+        profile, true);
     params.window = this;
     browser_.reset(new Browser(params));
     chrome::AddTabAt(browser_.get(), GURL(), 0, true);
@@ -2312,7 +2312,7 @@
       multi_user_util::GetAccountIdFromProfile(profile());
 
   // Create a browser window with a native window for the current user.
-  Browser::CreateParams params(profile());
+  Browser::CreateParams params(profile(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithAuraTestWindowForParams(nullptr, &params));
   BrowserWindow* browser_window = browser->window();
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index f32a91d..d30eb2d 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -56,47 +56,6 @@
 // The animation time in ms for a window which get teleported to another screen.
 const int kTeleportAnimationTimeMS = 300;
 
-// Checks if a given event is a user event.
-bool IsUserEvent(const ui::Event* e) {
-  if (e) {
-    ui::EventType type = e->type();
-    if (type != ui::ET_CANCEL_MODE &&
-        type != ui::ET_UMA_DATA &&
-        type != ui::ET_UNKNOWN)
-      return true;
-  }
-  return false;
-}
-
-// Test if we are currently processing a user event which might lead to a
-// browser / app creation.
-bool IsProcessingUserEvent() {
-  // When there is a nested message loop (e.g. active menu or drag and drop
-  // operation) - we are in a nested loop and can ignore this.
-  // Note: Unit tests might not have a message loop.
-  base::MessageLoop* message_loop = base::MessageLoop::current();
-  if (message_loop && message_loop->is_running() && message_loop->IsNested())
-    return false;
-
-  // TODO(skuhne): "Open link in new window" will come here after the menu got
-  // closed, executing the command from the nested menu loop. However at that
-  // time there is no active event processed. A solution for that need to be
-  // found past M-32. A global event handler filter (pre and post) might fix
-  // that problem in conjunction with a depth counter - but - for the menu
-  // execution we come here after the loop was finished (so it's not nested
-  // anymore) and the root window should therefore still have the event which
-  // lead to the menu invocation, but it is not. By fixing that problem this
-  // would "magically work".
-  aura::Window::Windows root_window_list = ash::Shell::GetAllRootWindows();
-  for (aura::Window::Windows::iterator it = root_window_list.begin();
-       it != root_window_list.end();
-       ++it) {
-    if (IsUserEvent((*it)->GetHost()->dispatcher()->current_event()))
-      return true;
-  }
-  return false;
-}
-
 // Records the type of window which was transferred to another desktop.
 void RecordUMAForTransferredWindowType(aura::Window* window) {
   // We need to figure out what kind of window this is to record the transfer.
@@ -317,7 +276,7 @@
 
   // Check if this window was created due to a user interaction. If it was,
   // transfer it to the current user.
-  if (IsProcessingUserEvent())
+  if (window->GetProperty(aura::client::kCreatedByUserGesture))
     window_to_entry_[window]->set_show_for_user(current_account_id_);
 
   // Add all transient children to our set of windows. Note that the function
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index 2114633..38ff3b9 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -1561,7 +1561,7 @@
       aura::client::GetActivationClient(window(0)->GetRootWindow());
   multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
   Profile* profile = multi_user_util::GetProfileFromAccountId(account_id_A);
-  Browser::CreateParams params(profile);
+  Browser::CreateParams params(profile, true);
   std::unique_ptr<Browser> browser(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(16, 32, 640, 320), &params));
   aura::Window* browser_native_window = browser->window()->GetNativeWindow();
diff --git a/chrome/browser/ui/ash/window_positioner_unittest.cc b/chrome/browser/ui/ash/window_positioner_unittest.cc
index d983dea..a71dd18 100644
--- a/chrome/browser/ui/ash/window_positioner_unittest.cc
+++ b/chrome/browser/ui/ash/window_positioner_unittest.cc
@@ -66,12 +66,12 @@
   dummy_popup->SetBounds(gfx::Rect(16, 32, 128, 256));
 
   // Create a browser for the window.
-  Browser::CreateParams window_params(&profile_);
+  Browser::CreateParams window_params(&profile_, true);
   browser_ = chrome::CreateBrowserWithAuraTestWindowForParams(
       std::move(dummy_window), &window_params);
 
   // Creating a browser for the popup.
-  Browser::CreateParams popup_params(Browser::TYPE_POPUP, &profile_);
+  Browser::CreateParams popup_params(Browser::TYPE_POPUP, &profile_, true);
   browser_popup_ = chrome::CreateBrowserWithAuraTestWindowForParams(
       std::move(dummy_popup), &popup_params);
 
diff --git a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
index 21c9118..3f8e2c5 100644
--- a/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
+++ b/chrome/browser/ui/bookmarks/bookmark_bubble_sign_in_delegate.cc
@@ -38,7 +38,7 @@
     Profile* original_profile = profile_->GetOriginalProfile();
     browser_ = chrome::FindLastActiveWithProfile(original_profile);
     if (!browser_) {
-      browser_ = new Browser(Browser::CreateParams(original_profile));
+      browser_ = new Browser(Browser::CreateParams(original_profile, true));
     }
   }
 }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 6d268b3..e27fd84 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -250,8 +250,8 @@
 // How long we wait before updating the browser chrome while loading a page.
 const int kUIUpdateCoalescingTimeMS = 200;
 
-BrowserWindow* CreateBrowserWindow(Browser* browser) {
-  return BrowserWindow::CreateBrowserWindow(browser);
+BrowserWindow* CreateBrowserWindow(Browser* browser, bool user_gesture) {
+  return BrowserWindow::CreateBrowserWindow(browser, user_gesture);
 }
 
 // Is the fast tab unload experiment enabled?
@@ -282,20 +282,24 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Browser, CreateParams:
 
-Browser::CreateParams::CreateParams(Profile* profile)
+Browser::CreateParams::CreateParams(Profile* profile, bool user_gesture)
     : type(TYPE_TABBED),
       profile(profile),
       trusted_source(false),
       initial_show_state(ui::SHOW_STATE_DEFAULT),
       is_session_restore(false),
+      user_gesture(user_gesture),
       window(NULL) {}
 
-Browser::CreateParams::CreateParams(Type type, Profile* profile)
+Browser::CreateParams::CreateParams(Type type,
+                                    Profile* profile,
+                                    bool user_gesture)
     : type(type),
       profile(profile),
       trusted_source(false),
       initial_show_state(ui::SHOW_STATE_DEFAULT),
       is_session_restore(false),
+      user_gesture(user_gesture),
       window(NULL) {}
 
 Browser::CreateParams::CreateParams(const CreateParams& other) = default;
@@ -305,10 +309,11 @@
     const std::string& app_name,
     bool trusted_source,
     const gfx::Rect& window_bounds,
-    Profile* profile) {
+    Profile* profile,
+    bool user_gesture) {
   DCHECK(!app_name.empty());
 
-  CreateParams params(TYPE_POPUP, profile);
+  CreateParams params(TYPE_POPUP, profile, user_gesture);
   params.app_name = app_name;
   params.trusted_source = trusted_source;
   params.initial_bounds = window_bounds;
@@ -319,7 +324,7 @@
 // static
 Browser::CreateParams Browser::CreateParams::CreateForDevTools(
     Profile* profile) {
-  CreateParams params(TYPE_POPUP, profile);
+  CreateParams params(TYPE_POPUP, profile, true);
   params.app_name = DevToolsWindow::kDevToolsApp;
   params.trusted_source = true;
   return params;
@@ -438,7 +443,8 @@
 
   ProfileMetrics::LogProfileLaunch(profile_);
 
-  window_ = params.window ? params.window : CreateBrowserWindow(this);
+  window_ = params.window ? params.window
+                          : CreateBrowserWindow(this, params.user_gesture);
 
   if (hosted_app_controller_)
     hosted_app_controller_->UpdateLocationBarVisibility(false);
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 59da095..cd6244a 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -156,14 +156,15 @@
   };
 
   struct CreateParams {
-    explicit CreateParams(Profile* profile);
-    CreateParams(Type type, Profile* profile);
+    explicit CreateParams(Profile* profile, bool user_gesture);
+    CreateParams(Type type, Profile* profile, bool user_gesture);
     CreateParams(const CreateParams& other);
 
     static CreateParams CreateForApp(const std::string& app_name,
                                      bool trusted_source,
                                      const gfx::Rect& window_bounds,
-                                     Profile* profile);
+                                     Profile* profile,
+                                     bool user_gesture);
 
     static CreateParams CreateForDevTools(Profile* profile);
 
@@ -186,6 +187,12 @@
 
     bool is_session_restore;
 
+    // Whether this browser was created by a user gesture. We track this
+    // specifically for the multi-user case in chromeos where we can place
+    // windows generated by user gestures differently from ones
+    // programmatically created.
+    bool user_gesture;
+
     // Supply a custom BrowserWindow implementation, to be used instead of the
     // default. Intended for testing.
     BrowserWindow* window;
diff --git a/chrome/browser/ui/browser_browsertest.cc b/chrome/browser/ui/browser_browsertest.cc
index 13c514b..5ce38f3 100644
--- a/chrome/browser/ui/browser_browsertest.cc
+++ b/chrome/browser/ui/browser_browsertest.cc
@@ -1636,7 +1636,7 @@
 IN_PROC_BROWSER_TEST_F(BrowserTest, StartMaximized) {
   Browser::Type types[] = { Browser::TYPE_TABBED, Browser::TYPE_POPUP };
   for (size_t i = 0; i < arraysize(types); ++i) {
-    Browser::CreateParams params(types[i], browser()->profile());
+    Browser::CreateParams params(types[i], browser()->profile(), true);
     params.initial_show_state = ui::SHOW_STATE_MAXIMIZED;
     AddBlankTabAndShow(new Browser(params));
   }
@@ -1647,7 +1647,7 @@
 IN_PROC_BROWSER_TEST_F(BrowserTest, StartMinimized) {
   Browser::Type types[] = { Browser::TYPE_TABBED, Browser::TYPE_POPUP };
   for (size_t i = 0; i < arraysize(types); ++i) {
-    Browser::CreateParams params(types[i], browser()->profile());
+    Browser::CreateParams params(types[i], browser()->profile(), true);
     params.initial_show_state = ui::SHOW_STATE_MINIMIZED;
     AddBlankTabAndShow(new Browser(params));
   }
@@ -1712,8 +1712,8 @@
   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
 
   // Create a new browser.
-  Browser* new_browser = new Browser(
-      Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile()));
+  Browser* new_browser = new Browser(Browser::CreateParams(
+      browser()->profile()->GetOffTheRecordProfile(), true));
   CommandUpdater* new_command_updater =
       new_browser->command_controller()->command_updater();
   // It should have Bookmarks & Settings commands disabled by default.
@@ -1746,7 +1746,7 @@
 
   // Create a new browser.
   Browser* new_browser =
-      new Browser(Browser::CreateParams(browser()->profile()));
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   CommandUpdater* new_command_updater =
       new_browser->command_controller()->command_updater();
   EXPECT_FALSE(new_command_updater->IsCommandEnabled(IDC_NEW_INCOGNITO_WINDOW));
@@ -1779,7 +1779,7 @@
   // Create a popup (non-main-UI-type) browser. Settings command as well
   // as Extensions should be disabled.
   Browser* popup_browser = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   CommandUpdater* popup_command_updater =
       popup_browser->command_controller()->command_updater();
   EXPECT_FALSE(popup_command_updater->IsCommandEnabled(IDC_MANAGE_EXTENSIONS));
@@ -1795,7 +1795,7 @@
                        DisableOptionsAndImportMenuItemsConsistently) {
   // Create a popup browser.
   Browser* popup_browser = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   CommandUpdater* command_updater =
       popup_browser->command_controller()->command_updater();
   // OPTIONS and IMPORT_SETTINGS are disabled for a non-normal UI.
@@ -2860,7 +2860,8 @@
     // 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());
+    Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(),
+                                 true);
     params.initial_bounds = gfx::Rect(0, 0, 100, 122);
     Browser* browser = new Browser(params);
     gfx::Rect bounds = browser->window()->GetBounds();
@@ -2877,7 +2878,8 @@
   {
     // 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());
+    Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(),
+                                 true);
     params.initial_bounds = gfx::Rect(0, 0, 100, 122);
     params.trusted_source = true;
     Browser* browser = new Browser(params);
@@ -2894,7 +2896,8 @@
     // 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());
+        "app-name", false, gfx::Rect(0, 0, 100, 122), browser()->profile(),
+        true);
     Browser* browser = new Browser(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
@@ -2909,7 +2912,8 @@
     // 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());
+        "app-name", true, gfx::Rect(0, 0, 100, 122), browser()->profile(),
+        true);
     Browser* browser = new Browser(params);
     gfx::Rect bounds = browser->window()->GetBounds();
 
diff --git a/chrome/browser/ui/browser_close_unittest.cc b/chrome/browser/ui/browser_close_unittest.cc
index d605184..1cd55e20 100644
--- a/chrome/browser/ui/browser_close_unittest.cc
+++ b/chrome/browser/ui/browser_close_unittest.cc
@@ -156,7 +156,7 @@
     std::vector<Browser*> browsers;
     for (int i = 0; i < num_windows; ++i) {
       TestBrowserWindow* window = new TestBrowserWindow();
-      Browser::CreateParams params(profile);
+      Browser::CreateParams params(profile, true);
       params.type = Browser::TYPE_TABBED;
       params.window = window;
       Browser* browser = new Browser(params);
diff --git a/chrome/browser/ui/browser_command_controller_unittest.cc b/chrome/browser/ui/browser_command_controller_unittest.cc
index ee63765f..53bce11 100644
--- a/chrome/browser/ui/browser_command_controller_unittest.cc
+++ b/chrome/browser/ui/browser_command_controller_unittest.cc
@@ -231,7 +231,7 @@
 
   // Create a new browser based on the off the record profile.
   Browser::CreateParams profile_params(
-      original_profile->GetOffTheRecordProfile());
+      original_profile->GetOffTheRecordProfile(), true);
   std::unique_ptr<Browser> otr_browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
 
@@ -456,7 +456,8 @@
   EXPECT_EQ(profile2->GetOriginalProfile(), profile1.get());
 
   // Create a new browser based on the off the record profile.
-  Browser::CreateParams profile_params(profile1->GetOffTheRecordProfile());
+  Browser::CreateParams profile_params(profile1->GetOffTheRecordProfile(),
+                                       true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&profile_params));
 
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index dd93505c..5beb96d4 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -234,7 +234,7 @@
     case WindowOpenDisposition::NEW_WINDOW: {
       WebContents* new_tab = current_tab->Clone();
       Browser* new_browser =
-          new Browser(Browser::CreateParams(browser->profile()));
+          new Browser(Browser::CreateParams(browser->profile(), true));
       new_browser->tab_strip_model()->AddWebContents(
           new_tab, -1, ui::PAGE_TRANSITION_LINK,
           TabStripModel::ADD_ACTIVE);
@@ -393,7 +393,7 @@
 
 Browser* OpenEmptyWindow(Profile* profile) {
   Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+      new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true));
   AddTabAt(browser, GURL(), -1, true);
   browser->window()->Show();
   return browser;
@@ -705,10 +705,10 @@
     if (browser->is_app() && !browser->is_type_popup()) {
       new_browser = new Browser(Browser::CreateParams::CreateForApp(
           browser->app_name(), browser->is_trusted_source(), gfx::Rect(),
-          browser->profile()));
+          browser->profile(), true));
     } else {
       new_browser = new Browser(
-          Browser::CreateParams(browser->type(), browser->profile()));
+          Browser::CreateParams(browser->type(), browser->profile(), true));
     }
     // Preserve the size of the original window. The new window has already
     // been given an offset by the OS, so we shouldn't copy the old bounds.
@@ -748,7 +748,7 @@
   TabStripModel* tab_strip = browser->tab_strip_model();
   WebContents* contents =
       tab_strip->DetachWebContentsAt(tab_strip->active_index());
-  Browser* b = new Browser(Browser::CreateParams(browser->profile()));
+  Browser* b = new Browser(Browser::CreateParams(browser->profile(), true));
   b->tab_strip_model()->AppendWebContents(contents, true);
   b->window()->Show();
 }
@@ -1265,7 +1265,7 @@
         add_types);
   } else {
     Browser* b = new Browser(
-        Browser::CreateParams(Browser::TYPE_TABBED, browser->profile()));
+        Browser::CreateParams(Browser::TYPE_TABBED, browser->profile(), true));
 
     // Preserve the size of the original window. The new window has already
     // been given an offset by the OS, so we shouldn't copy the old bounds.
@@ -1336,7 +1336,8 @@
     browser->tab_strip_model()->DetachWebContentsAt(index);
 
   Browser* app_browser = new Browser(Browser::CreateParams::CreateForApp(
-      app_name, true /* trusted_source */, gfx::Rect(), browser->profile()));
+      app_name, true /* trusted_source */, gfx::Rect(), browser->profile(),
+      true));
   app_browser->tab_strip_model()->AppendWebContents(contents, true);
 
   contents->GetMutableRendererPrefs()->can_accept_load_drops = false;
diff --git a/chrome/browser/ui/browser_finder_chromeos_unittest.cc b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
index c9802e2b..00e9400 100644
--- a/chrome/browser/ui/browser_finder_chromeos_unittest.cc
+++ b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
@@ -116,7 +116,7 @@
   set_browser(nullptr);
 
   // Create an incognito browser.
-  Browser::CreateParams params(profile()->GetOffTheRecordProfile());
+  Browser::CreateParams params(profile()->GetOffTheRecordProfile(), true);
   std::unique_ptr<Browser> incognito_browser(
       chrome::CreateBrowserWithAuraTestWindowForParams(nullptr, &params));
   // Incognito windows are excluded in GetBrowserCount() because kMatchAll
@@ -129,7 +129,7 @@
 TEST_F(BrowserFinderChromeOSTest, FindBrowserOwnedByAnotherProfile) {
   set_browser(nullptr);
 
-  Browser::CreateParams params(profile()->GetOriginalProfile());
+  Browser::CreateParams params(profile()->GetOriginalProfile(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithAuraTestWindowForParams(nullptr, &params));
   GetUserWindowManager()->SetWindowOwner(browser->window()->GetNativeWindow(),
diff --git a/chrome/browser/ui/browser_focus_uitest.cc b/chrome/browser/ui/browser_focus_uitest.cc
index f46298a5..17d0c468 100644
--- a/chrome/browser/ui/browser_focus_uitest.cc
+++ b/chrome/browser/ui/browser_focus_uitest.cc
@@ -372,7 +372,8 @@
   ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
 
   // Open a new browser window.
-  Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile()));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(browser()->profile(), true));
 
   ASSERT_TRUE(browser2);
   chrome::AddTabAt(browser2, GURL(), -1, true);
diff --git a/chrome/browser/ui/browser_instant_controller_unittest.cc b/chrome/browser/ui/browser_instant_controller_unittest.cc
index fe12849..0db9e7e 100644
--- a/chrome/browser/ui/browser_instant_controller_unittest.cc
+++ b/chrome/browser/ui/browser_instant_controller_unittest.cc
@@ -223,7 +223,7 @@
 
 TEST_F(BrowserInstantControllerTest, BrowserWindowLifecycle) {
   std::unique_ptr<BrowserWindow> window(CreateBrowserWindow());
-  Browser::CreateParams params(profile());
+  Browser::CreateParams params(profile(), true);
   params.window = window.get();
   std::unique_ptr<Browser> browser(new Browser(params));
   InstantServiceObserver* bic;
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc
index 40892e2..c6ee3f0 100644
--- a/chrome/browser/ui/browser_live_tab_context.cc
+++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -108,11 +108,11 @@
     const std::string& app_name) {
   Browser* browser;
   if (app_name.empty()) {
-    browser = new Browser(Browser::CreateParams(profile));
+    browser = new Browser(Browser::CreateParams(profile, true));
   } else {
     // Only trusted app popup windows should ever be restored.
     browser = new Browser(Browser::CreateParams::CreateForApp(
-        app_name, true /* trusted_source */, gfx::Rect(), profile));
+        app_name, true /* trusted_source */, gfx::Rect(), profile, true));
   }
   if (browser)
     return browser->live_tab_context();
diff --git a/chrome/browser/ui/browser_mac.cc b/chrome/browser/ui/browser_mac.cc
index 319b318..9719eba 100644
--- a/chrome/browser/ui/browser_mac.cc
+++ b/chrome/browser/ui/browser_mac.cc
@@ -11,56 +11,55 @@
 namespace chrome {
 
 void OpenAboutWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowAboutChrome(browser);
   browser->window()->Show();
 }
 
 void OpenHistoryWindow(Profile* profile) {
-  Browser* browser =
-      new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowHistory(browser);
   browser->window()->Show();
 }
 
 void OpenDownloadsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowDownloads(browser);
   browser->window()->Show();
 }
 
 void OpenHelpWindow(Profile* profile, HelpSource source) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowHelp(browser, source);
   browser->window()->Show();
 }
 
 void OpenOptionsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowSettings(browser);
   browser->window()->Show();
 }
 
 void OpenClearBrowsingDataDialogWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowClearBrowsingDataDialog(browser);
   browser->window()->Show();
 }
 
 void OpenImportSettingsDialogWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowImportDialog(browser);
   browser->window()->Show();
 }
 
 void OpenBookmarkManagerWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowBookmarkManager(browser);
   browser->window()->Show();
 }
 
 void OpenExtensionsWindow(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   ShowExtensions(browser, std::string());
   browser->window()->Show();
 }
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index f7714d42..4197fba 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -81,9 +81,10 @@
 
 // Finds an existing Browser compatible with |profile|, making a new one if no
 // such Browser is located.
-Browser* GetOrCreateBrowser(Profile* profile) {
+Browser* GetOrCreateBrowser(Profile* profile, bool user_gesture) {
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
-  return browser ? browser : new Browser(Browser::CreateParams(profile));
+  return browser ? browser
+                 : new Browser(Browser::CreateParams(profile, user_gesture));
 }
 
 // Change some of the navigation parameters based on the particular URL.
@@ -114,7 +115,7 @@
     }
 
     params->disposition = WindowOpenDisposition::SINGLETON_TAB;
-    params->browser = GetOrCreateBrowser(profile);
+    params->browser = GetOrCreateBrowser(profile, params->user_gesture);
     params->window_action = chrome::NavigateParams::SHOW_WINDOW;
   }
 
@@ -142,7 +143,7 @@
         return params->browser;
       // Find a compatible window and re-execute this command in it. Otherwise
       // re-run with NEW_WINDOW.
-      return GetOrCreateBrowser(profile);
+      return GetOrCreateBrowser(profile, params->user_gesture);
     case WindowOpenDisposition::SINGLETON_TAB:
     case WindowOpenDisposition::NEW_FOREGROUND_TAB:
     case WindowOpenDisposition::NEW_BACKGROUND_TAB:
@@ -151,7 +152,7 @@
         return params->browser;
       // Find a compatible window and re-execute this command in it. Otherwise
       // re-run with NEW_WINDOW.
-      return GetOrCreateBrowser(profile);
+      return GetOrCreateBrowser(profile, params->user_gesture);
     case WindowOpenDisposition::NEW_POPUP: {
       // Make a new popup window.
       // Coerce app-style if |source| represents an app.
@@ -172,22 +173,25 @@
       }
 #endif
       if (app_name.empty()) {
-        Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile);
+        Browser::CreateParams browser_params(Browser::TYPE_POPUP, profile,
+                                             params->user_gesture);
         browser_params.trusted_source = params->trusted_source;
         browser_params.initial_bounds = params->window_bounds;
         return new Browser(browser_params);
       }
 
       return new Browser(Browser::CreateParams::CreateForApp(
-          app_name, params->trusted_source, params->window_bounds, profile));
+          app_name, params->trusted_source, params->window_bounds, profile,
+          params->user_gesture));
     }
     case WindowOpenDisposition::NEW_WINDOW: {
       // Make a new normal browser window.
-      return new Browser(Browser::CreateParams(profile));
+      return new Browser(Browser::CreateParams(profile, params->user_gesture));
     }
     case WindowOpenDisposition::OFF_THE_RECORD:
       // Make or find an incognito window.
-      return GetOrCreateBrowser(profile->GetOffTheRecordProfile());
+      return GetOrCreateBrowser(profile->GetOffTheRecordProfile(),
+                                params->user_gesture);
     // The following types result in no navigation.
     case WindowOpenDisposition::SAVE_TO_DISK:
     case WindowOpenDisposition::IGNORE_ACTION:
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 37c4be3..adf0321 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -121,14 +121,14 @@
 
 Browser* BrowserNavigatorTest::CreateEmptyBrowserForType(Browser::Type type,
                                                          Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(type, profile));
+  Browser* browser = new Browser(Browser::CreateParams(type, profile, true));
   chrome::AddTabAt(browser, GURL(), -1, true);
   return browser;
 }
 
 Browser* BrowserNavigatorTest::CreateEmptyBrowserForApp(Profile* profile) {
   Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
-      "Test", false /* trusted_source */, gfx::Rect(), profile));
+      "Test", false /* trusted_source */, gfx::Rect(), profile, true));
   chrome::AddTabAt(browser, GURL(), -1, true);
   return browser;
 }
diff --git a/chrome/browser/ui/browser_tab_strip_model_delegate.cc b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
index 52d1a020..8788e4a8 100644
--- a/chrome/browser/ui/browser_tab_strip_model_delegate.cc
+++ b/chrome/browser/ui/browser_tab_strip_model_delegate.cc
@@ -57,7 +57,7 @@
   DCHECK(browser_->CanSupportWindowFeature(Browser::FEATURE_TABSTRIP));
 
   // Create an empty new browser window the same size as the old one.
-  Browser::CreateParams params(browser_->profile());
+  Browser::CreateParams params(browser_->profile(), true);
   params.initial_bounds = window_bounds;
   params.initial_show_state =
       maximize ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 136dd3e..58f4c448 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -348,7 +348,8 @@
                                      const gfx::Size& new_size) {}
 
   // Construct a BrowserWindow implementation for the specified |browser|.
-  static BrowserWindow* CreateBrowserWindow(Browser* browser);
+  static BrowserWindow* CreateBrowserWindow(Browser* browser,
+                                            bool user_gesture);
 
   // Shows the avatar bubble on the window frame off of the avatar button with
   // the given mode. The Service Type specified by GAIA is provided as well.
diff --git a/chrome/browser/ui/chrome_pages.cc b/chrome/browser/ui/chrome_pages.cc
index 6dea3c41..95ad166 100644
--- a/chrome/browser/ui/chrome_pages.cc
+++ b/chrome/browser/ui/chrome_pages.cc
@@ -335,7 +335,7 @@
   }
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   if (!browser) {
-    browser = new Browser(Browser::CreateParams(profile));
+    browser = new Browser(Browser::CreateParams(profile, true));
   }
   ShowSettingsSubPageInTabbedBrowser(browser, sub_page_path);
 }
diff --git a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
index d77411d8..a11054a1 100644
--- a/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
+++ b/chrome/browser/ui/cocoa/applescript/browsercrapplication+applescript_test.mm
@@ -27,9 +27,9 @@
   // Create additional |Browser*| objects of different type.
   Profile* profile = browser()->profile();
   Browser* b1 =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile));
+      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
   Browser* b2 = new Browser(Browser::CreateParams::CreateForApp(
-      "Test", true /* trusted_source */, gfx::Rect(), profile));
+      "Test", true /* trusted_source */, gfx::Rect(), profile, true));
 
   EXPECT_EQ(3U, [[NSApp appleScriptWindows] count]);
   for (WindowAppleScript* window in [NSApp appleScriptWindows]) {
diff --git a/chrome/browser/ui/cocoa/applescript/window_applescript.mm b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
index e77835b..9cbb85cb 100644
--- a/chrome/browser/ui/cocoa/applescript/window_applescript.mm
+++ b/chrome/browser/ui/cocoa/applescript/window_applescript.mm
@@ -77,7 +77,7 @@
   }
 
   if ((self = [super init])) {
-    browser_ = new Browser(Browser::CreateParams(aProfile));
+    browser_ = new Browser(Browser::CreateParams(aProfile, false));
     chrome::NewTab(browser_);
     browser_->window()->Show();
     base::scoped_nsobject<NSNumber> numID(
diff --git a/chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac_interactive_uitest.mm b/chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac_interactive_uitest.mm
index 72f333e..97ea6f6 100644
--- a/chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/apps/app_shim_menu_controller_mac_interactive_uitest.mm
@@ -48,7 +48,7 @@
     app1_ = GetFirstAppWindow();
     app2_ = CreateAppWindow(browser()->profile(), extension);
     browser1_ = browser()->window();
-    browser2_ = (new Browser(Browser::CreateParams(profile())))->window();
+    browser2_ = (new Browser(Browser::CreateParams(profile(), true)))->window();
     browser2_->Show();
 
     // Since a pending key status change on any window could cause the test to
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
index f4282078..98d5d3b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_editor_base_controller_unittest.mm
@@ -102,7 +102,7 @@
   }
 
   Browser* CreateBrowser() override {
-    Browser::CreateParams params(profile());
+    Browser::CreateParams params(profile(), true);
     return chrome::CreateBrowserWithTestWindowForParams(&params).release();
   }
 };
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
index 88b94229..bac5b5f 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_menu_cocoa_controller.mm
@@ -93,7 +93,7 @@
 - (void)openURLForNode:(const BookmarkNode*)node {
   Browser* browser = chrome::FindTabbedBrowser(bridge_->GetProfile(), true);
   if (!browser) {
-    browser = new Browser(Browser::CreateParams(bridge_->GetProfile()));
+    browser = new Browser(Browser::CreateParams(bridge_->GetProfile(), true));
   }
   WindowOpenDisposition disposition =
       ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
@@ -113,7 +113,7 @@
 
   Browser* browser = chrome::FindTabbedBrowser(bridge_->GetProfile(), true);
   if (!browser) {
-    browser = new Browser(Browser::CreateParams(bridge_->GetProfile()));
+    browser = new Browser(Browser::CreateParams(bridge_->GetProfile(), true));
   }
   DCHECK(browser);
 
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
index a22fc45..b99bc47 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -127,7 +127,7 @@
   // And make sure a controller for a pop-up window is not normal.
   // popup_browser will be owned by its window.
   Browser* popup_browser(
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile())));
+      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile(), true)));
   NSWindow* cocoaWindow = popup_browser->window()->GetNativeWindow();
   BrowserWindowController* controller =
       static_cast<BrowserWindowController*>([cocoaWindow windowController]);
@@ -141,7 +141,7 @@
 
 TEST_F(BrowserWindowControllerTest, TestSetBounds) {
   // Create a normal browser with bounds smaller than the minimum.
-  Browser::CreateParams params(Browser::TYPE_TABBED, profile());
+  Browser::CreateParams params(Browser::TYPE_TABBED, profile(), true);
   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
@@ -166,7 +166,7 @@
 
 TEST_F(BrowserWindowControllerTest, TestSetBoundsPopup) {
   // Create a popup with bounds smaller than the minimum.
-  Browser::CreateParams params(Browser::TYPE_POPUP, profile());
+  Browser::CreateParams params(Browser::TYPE_POPUP, profile(), true);
   params.initial_bounds = gfx::Rect(0, 0, 50, 50);
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
@@ -206,7 +206,7 @@
 }
 
 TEST_F(BrowserWindowControllerTest, BookmarkBarToggleRespectMinWindowHeight) {
-  Browser::CreateParams params(Browser::TYPE_TABBED, profile());
+  Browser::CreateParams params(Browser::TYPE_TABBED, profile(), true);
   params.initial_bounds = gfx::Rect(0, 0, 50, 280);
   Browser* browser = new Browser(params);
   NSWindow* cocoaWindow = browser->window()->GetNativeWindow();
@@ -233,7 +233,7 @@
   std::unique_ptr<TestingProfile> incognito_profile(new TestingProfile());
   incognito_profile->set_off_the_record(true);
   std::unique_ptr<Browser> browser(
-      new Browser(Browser::CreateParams(incognito_profile.get())));
+      new Browser(Browser::CreateParams(incognito_profile.get(), true)));
   controller_.reset([[BrowserWindowController alloc]
                               initWithBrowser:browser.get()
                                 takeOwnership:NO]);
diff --git a/chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm
index 5ba5199..d18e12f2 100644
--- a/chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_factory_cocoa.mm
@@ -9,7 +9,8 @@
 // Create the controller for the Browser, which handles loading the browser
 // window from the nib. The controller takes ownership of |browser|.
 // static
-BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
+BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser,
+                                                  bool user_gesture) {
   BrowserWindowController* controller =
       [[BrowserWindowController alloc] initWithBrowser:browser];
   return [controller browserWindow];
diff --git a/chrome/browser/ui/cocoa/l10n_util.h b/chrome/browser/ui/cocoa/l10n_util.h
index a7d8a80..8457c7f 100644
--- a/chrome/browser/ui/cocoa/l10n_util.h
+++ b/chrome/browser/ui/cocoa/l10n_util.h
@@ -49,4 +49,8 @@
 // OSes would make Chrome stick out.
 bool ShouldFlipWindowControlsInRTL();
 
+// Returns an autoreleased image containing |image| flipped
+// across the x axis.
+NSImage* FlippedImage(NSImage* image);
+
 }  // namespace cocoa_l10n_util
diff --git a/chrome/browser/ui/cocoa/l10n_util.mm b/chrome/browser/ui/cocoa/l10n_util.mm
index 73db01d..1479c172 100644
--- a/chrome/browser/ui/cocoa/l10n_util.mm
+++ b/chrome/browser/ui/cocoa/l10n_util.mm
@@ -96,4 +96,28 @@
   return ShouldDoExperimentalRTLLayout() && base::mac::IsAtLeastOS10_12();
 }
 
+// Adapted from Apple's RTL docs (goo.gl/cBaFnT)
+NSImage* FlippedImage(NSImage* image) {
+  const NSSize size = [image size];
+  NSImage* flipped_image = [[[NSImage alloc] initWithSize:size] autorelease];
+
+  [flipped_image lockFocus];
+  [[NSGraphicsContext currentContext]
+      setImageInterpolation:NSImageInterpolationHigh];
+
+  NSAffineTransform* transform = [NSAffineTransform transform];
+  [transform translateXBy:size.width yBy:0];
+  [transform scaleXBy:-1 yBy:1];
+  [transform concat];
+
+  [image drawAtPoint:NSZeroPoint
+            fromRect:NSMakeRect(0, 0, size.width, size.height)
+           operation:NSCompositeSourceOver
+            fraction:1.0];
+
+  [flipped_image unlockFocus];
+
+  return flipped_image;
+}
+
 }  // namespace cocoa_l10n_util
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 8225147..20ff012 100644
--- a/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/content_setting_decoration.mm
@@ -262,7 +262,14 @@
 }
 
 NSPoint ContentSettingDecoration::GetBubblePointInFrame(NSRect frame) {
-
+  // Compute the frame as if there is no animation pill in the Omnibox. Place
+  // the bubble where the icon would be without animation, so when the animation
+  // ends, the bubble is pointing in the right place.
+  CGFloat final_width = ImageDecoration::GetWidthForSpace(NSWidth(frame));
+  NSSize image_size = NSMakeSize(final_width, NSHeight(frame));
+  if (!cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
+    frame.origin.x += frame.size.width - image_size.width;
+  frame.size = image_size;
   const NSRect draw_frame = GetDrawRectInFrame(frame);
   return NSMakePoint(NSMidX(draw_frame),
                      NSMaxY(draw_frame) + kPageBubblePointYOffset);
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
index e5170950..18fe91c 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_icon_controller_unittest.mm
@@ -49,8 +49,8 @@
 };
 
 TEST_F(AvatarIconControllerTest, ShowingAvatarIconInIncognito) {
-  Browser* browser =
-      new Browser(Browser::CreateParams(profile()->GetOffTheRecordProfile()));
+  Browser* browser = new Browser(
+      Browser::CreateParams(profile()->GetOffTheRecordProfile(), true));
   BrowserWindowCocoa* window =
       static_cast<BrowserWindowCocoa*>(browser->window());
   AvatarBaseController* icon_controller =
diff --git a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
index 98dc739..05cd5b29 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm
@@ -204,7 +204,7 @@
   ASSERT_EQ(7, [menu numberOfItems]);
 
   // Create a browser and "show" it.
-  Browser::CreateParams profile2_params(profile2);
+  Browser::CreateParams profile2_params(profile2, true);
   std::unique_ptr<Browser> p2_browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile2_params));
   BrowserList::SetLastActive(p2_browser.get());
@@ -215,7 +215,7 @@
   VerifyProfileNamedIsActive(@"Profile 2", __LINE__);
 
   // Open a new browser and make sure it takes effect.
-  Browser::CreateParams profile3_params(profile3);
+  Browser::CreateParams profile3_params(profile3, true);
   std::unique_ptr<Browser> p3_browser(
       chrome::CreateBrowserWithTestWindowForParams(&profile3_params));
   BrowserList::SetLastActive(p3_browser.get());
@@ -282,7 +282,7 @@
   EXPECT_TRUE([controller() validateMenuItem:item]);
 
   // Open a new browser for the supervised user and switch to it.
-  Browser::CreateParams supervised_profile_params(supervised_profile);
+  Browser::CreateParams supervised_profile_params(supervised_profile, true);
   std::unique_ptr<Browser> supervised_browser(
       chrome::CreateBrowserWithTestWindowForParams(&supervised_profile_params));
   BrowserList::SetLastActive(supervised_browser.get());
diff --git a/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm b/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
index 707f143..4362c46 100644
--- a/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
+++ b/chrome/browser/ui/cocoa/test/cocoa_profile_test.mm
@@ -94,5 +94,5 @@
 }
 
 Browser* CocoaProfileTest::CreateBrowser() {
-  return new Browser(Browser::CreateParams(profile()));
+  return new Browser(Browser::CreateParams(profile(), true));
 }
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
index 6e7e612..2640313 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_button_cocoa.mm
@@ -207,12 +207,11 @@
 }
 
 - (const gfx::VectorIcon*)vectorIcon {
-  BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
   switch ([self viewID]) {
     case VIEW_ID_BACK_BUTTON:
-      return isRTL ? &ui::kForwardArrowIcon : &ui::kBackArrowIcon;
+      return &ui::kBackArrowIcon;
     case VIEW_ID_FORWARD_BUTTON:
-      return isRTL ? &ui::kBackArrowIcon : &ui::kForwardArrowIcon;
+      return &ui::kForwardArrowIcon;
     case VIEW_ID_HOME_BUTTON:
       return &kNavigateHomeIcon;
     case VIEW_ID_APP_MENU:
@@ -312,17 +311,21 @@
       normalIcon = [self browserToolsIconForFillColor:normalColor];
       disabledIcon = [self browserToolsIconForFillColor:disabledColor];
     } else {
+      BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
       normalIcon = NSImageFromImageSkia(
           gfx::CreateVectorIcon(*icon,
                                 kMDButtonIconSize.width,
                                 normalColor));
-
+      if (isRTL)
+        normalIcon = cocoa_l10n_util::FlippedImage(normalIcon);
       // The home button has no icon for its disabled state.
       if (icon != &kNavigateReloadIcon) {
         disabledIcon = NSImageFromImageSkia(
             gfx::CreateVectorIcon(*icon,
                                   kMDButtonIconSize.width,
                                   disabledColor));
+        if (isRTL)
+          disabledIcon = cocoa_l10n_util::FlippedImage(disabledIcon);
       }
     }
   }
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 56d65659..e159943 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -194,8 +194,10 @@
         extensions::AppLaunchInfo::GetLaunchHeight(extension));
   }
 
+  // TODO(erg): AppLaunchParams should pass through the user_gesture from the
+  // extension system here.
   Browser::CreateParams browser_params(Browser::CreateParams::CreateForApp(
-      app_name, true /* trusted_source */, initial_bounds, profile));
+      app_name, true /* trusted_source */, initial_bounds, profile, true));
 
   browser_params.initial_show_state = DetermineWindowShowState(profile,
                                                                params.container,
@@ -230,7 +232,11 @@
   WebContents* contents = NULL;
   if (!browser) {
     // No browser for this profile, need to open a new one.
-    browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+    //
+    // TODO(erg): AppLaunchParams should pass user_gesture from the extension
+    // system to here.
+    browser =
+        new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true));
     browser->window()->Show();
     // There's no current tab in this browser window, so add a new one.
     disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_bridge_unittest.cc b/chrome/browser/ui/extensions/extension_message_bubble_bridge_unittest.cc
index aa206d63..bbf6f6f0 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_bridge_unittest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_bridge_unittest.cc
@@ -65,7 +65,7 @@
     InitializeEmptyExtensionService();
 
     browser_window_.reset(new TestBrowserWindow());
-    Browser::CreateParams params(profile());
+    Browser::CreateParams params(profile(), true);
     params.type = Browser::TYPE_TABBED;
     params.window = browser_window_.get();
     browser_.reset(new Browser(params));
diff --git a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
index 887fc11..6e76c1aa 100644
--- a/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
+++ b/chrome/browser/ui/extensions/extension_message_bubble_browsertest.cc
@@ -108,7 +108,7 @@
           extensions::Manifest::UNPACKED);
   extension_service()->AddExtension(action_extension.get());
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -124,7 +124,7 @@
           extensions::extension_action_test_util::NO_ACTION,
           extensions::Manifest::UNPACKED);
   extension_service()->AddExtension(no_action_extension.get());
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -148,7 +148,7 @@
           extensions::Manifest::INTERNAL);
   extension_service()->AddExtension(action_extension.get());
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -169,7 +169,7 @@
 
   // Create a second browser with the extension installed - the bubble will be
   // set to show.
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   // Uninstall the extension before the bubble is shown. This should not crash,
@@ -199,7 +199,7 @@
           extensions::Manifest::UNPACKED);
   extension_service()->AddExtension(action_extension.get());
 
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -209,7 +209,7 @@
   base::RunLoop().RunUntilIdle();
 
   // The bubble was already shown, so it shouldn't be shown again.
-  Browser* third_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* third_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(third_browser);
   third_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -297,13 +297,13 @@
 void ExtensionMessageBubbleBrowserTest::TestBubbleWithMultipleWindows() {
   CheckBubbleIsNotPresent(browser(), false, false);
   LoadExtension(test_data_dir_.AppendASCII("good_unpacked"));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
-  Browser* third_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* third_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(third_browser);
   third_browser->window()->Show();
-  Browser* fourth_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* fourth_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(fourth_browser);
   fourth_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -319,7 +319,7 @@
 void ExtensionMessageBubbleBrowserTest::TestClickingLearnMoreButton() {
   CheckBubbleIsNotPresent(browser(), false, false);
   LoadExtension(test_data_dir_.AppendASCII("good_unpacked"));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -344,7 +344,7 @@
       extensions::ExtensionRegistry::Get(profile());
   std::string id = extension->id();
   EXPECT_TRUE(registry->enabled_extensions().GetByID(id));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
@@ -364,7 +364,7 @@
       extensions::ExtensionRegistry::Get(profile());
   std::string id = extension->id();
   EXPECT_TRUE(registry->enabled_extensions().GetByID(id));
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   ASSERT_TRUE(second_browser);
   second_browser->window()->Show();
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
index 27e3404..1a1b9ffd 100644
--- a/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
+++ b/chrome/browser/ui/find_bar/find_bar_host_browsertest.cc
@@ -1333,7 +1333,7 @@
   // Open a new incognito window and navigate to the same page.
   Profile* incognito_profile = browser()->profile()->GetOffTheRecordProfile();
   Browser* incognito_browser =
-      new Browser(Browser::CreateParams(incognito_profile));
+      new Browser(Browser::CreateParams(incognito_profile, true));
   content::WindowedNotificationObserver observer(
       content::NOTIFICATION_LOAD_STOP,
       content::NotificationService::AllSources());
@@ -1394,7 +1394,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(FindInPageControllerTest, FitWindow) {
-  Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile());
+  Browser::CreateParams params(Browser::TYPE_POPUP, browser()->profile(), true);
   params.initial_bounds = gfx::Rect(0, 0, 250, 500);
   Browser* popup = new Browser(params);
   content::WindowedNotificationObserver observer(
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon.cc b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
index 3aafd0a..eddbddd 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -72,14 +72,15 @@
 bool g_opened = false;
 
 // Retrieved functions from libappindicator.
-app_indicator_new_func app_indicator_new = NULL;
-app_indicator_new_with_path_func app_indicator_new_with_path = NULL;
-app_indicator_set_status_func app_indicator_set_status = NULL;
+app_indicator_new_func app_indicator_new = nullptr;
+app_indicator_new_with_path_func app_indicator_new_with_path = nullptr;
+app_indicator_set_status_func app_indicator_set_status = nullptr;
 app_indicator_set_attention_icon_full_func
-    app_indicator_set_attention_icon_full = NULL;
-app_indicator_set_menu_func app_indicator_set_menu = NULL;
-app_indicator_set_icon_full_func app_indicator_set_icon_full = NULL;
-app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path = NULL;
+    app_indicator_set_attention_icon_full = nullptr;
+app_indicator_set_menu_func app_indicator_set_menu = nullptr;
+app_indicator_set_icon_full_func app_indicator_set_icon_full = nullptr;
+app_indicator_set_icon_theme_path_func app_indicator_set_icon_theme_path =
+    nullptr;
 
 void EnsureMethodsLoaded() {
   if (g_attempted_load)
@@ -177,8 +178,8 @@
                                    const gfx::ImageSkia& image,
                                    const base::string16& tool_tip)
     : id_(id),
-      icon_(NULL),
-      menu_model_(NULL),
+      icon_(nullptr),
+      menu_model_(nullptr),
       icon_change_count_(0),
       weak_factory_(this) {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon_menu.cc b/chrome/browser/ui/libgtkui/app_indicator_icon_menu.cc
index 91674b9..40399a35 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon_menu.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon_menu.cc
@@ -16,7 +16,7 @@
 AppIndicatorIconMenu::AppIndicatorIconMenu(ui::MenuModel* model)
     : menu_model_(model),
       click_action_replacement_menu_item_added_(false),
-      gtk_menu_(NULL),
+      gtk_menu_(nullptr),
       block_activation_(false) {
   {
     ANNOTATE_SCOPED_MEMORY_LEAK; // http://crbug.com/378770
@@ -47,7 +47,7 @@
     GList* children = gtk_container_get_children(GTK_CONTAINER(gtk_menu_));
     for (GList* child = children; child; child = g_list_next(child)) {
       if (g_object_get_data(G_OBJECT(child->data), "click-action-item") !=
-          NULL) {
+          nullptr) {
         gtk_menu_item_set_label(GTK_MENU_ITEM(child->data), label);
         break;
       }
diff --git a/chrome/browser/ui/libgtkui/chrome_gtk_frame.cc b/chrome/browser/ui/libgtkui/chrome_gtk_frame.cc
index 9d23718..6820a47 100644
--- a/chrome/browser/ui/libgtkui/chrome_gtk_frame.cc
+++ b/chrome/browser/ui/libgtkui/chrome_gtk_frame.cc
@@ -147,9 +147,8 @@
 }
 
 GtkWidget* chrome_gtk_frame_new(void) {
-  return GTK_WIDGET(g_object_new(chrome_gtk_frame_get_type(),
-                                 "type", GTK_WINDOW_TOPLEVEL,
-                                 NULL));
+  return GTK_WIDGET(g_object_new(chrome_gtk_frame_get_type(), "type",
+                                 GTK_WINDOW_TOPLEVEL, nullptr));
 }
 
 G_END_DECLS
diff --git a/chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.cc b/chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.cc
index a6705a6..33944bb 100644
--- a/chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.cc
+++ b/chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.cc
@@ -13,7 +13,7 @@
 }
 
 GtkWidget* gtk_custom_menu_new() {
-  return GTK_WIDGET(g_object_new(gtk_custom_menu_get_type(), NULL));
+  return GTK_WIDGET(g_object_new(gtk_custom_menu_get_type(), nullptr));
 }
 
 G_DEFINE_TYPE(GtkCustomMenuItem, gtk_custom_menu_item, GTK_TYPE_MENU_ITEM)
@@ -25,5 +25,5 @@
 }
 
 GtkWidget* gtk_custom_menu_item_new() {
-  return GTK_WIDGET(g_object_new(gtk_custom_menu_item_get_type(), NULL));
+  return GTK_WIDGET(g_object_new(gtk_custom_menu_item_get_type(), nullptr));
 }
diff --git a/chrome/browser/ui/libgtkui/gconf_listener.cc b/chrome/browser/ui/libgtkui/gconf_listener.cc
index 7a3fac7..9beea250 100644
--- a/chrome/browser/ui/libgtkui/gconf_listener.cc
+++ b/chrome/browser/ui/libgtkui/gconf_listener.cc
@@ -43,7 +43,7 @@
 // Public interface:
 
 GConfListener::GConfListener(GtkUi* delegate)
-    : delegate_(delegate), client_(NULL) {
+    : delegate_(delegate), client_(nullptr) {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   base::nix::DesktopEnvironment de =
       base::nix::GetDesktopEnvironment(env.get());
@@ -55,7 +55,7 @@
     // not receiving gconf keys.
     if (client_) {
       // Register that we're interested in the values of this directory.
-      GError* error = NULL;
+      GError* error = nullptr;
       gconf_client_add_dir(client_, kMetacityGeneral,
                            GCONF_CLIENT_PRELOAD_ONELEVEL, &error);
       if (HandleGError(error, kMetacityGeneral))
@@ -80,7 +80,7 @@
 void GConfListener::GetAndRegister(
     const char* key_to_subscribe,
     const base::Callback<void(GConfValue*)>& initial_setter) {
-  GError* error = NULL;
+  GError* error = nullptr;
   GConfValue* gconf_value = gconf_client_get(client_, key_to_subscribe,
                                              &error);
   if (HandleGError(error, key_to_subscribe))
@@ -94,7 +94,7 @@
       client_, key_to_subscribe,
       reinterpret_cast<void (*)(GConfClient*, guint, GConfEntry*, void*)>(
           OnChangeNotificationThunk),
-      this, NULL, &error);
+      this, nullptr, &error);
   if (HandleGError(error, key_to_subscribe))
     return;
 }
@@ -112,11 +112,11 @@
 }
 
 bool GConfListener::HandleGError(GError* error, const char* key) {
-  if (error != NULL) {
+  if (error != nullptr) {
     LOG(ERROR) << "Error with gconf key '" << key << "': " << error->message;
     g_error_free(error);
     g_object_unref(client_);
-    client_ = NULL;
+    client_ = nullptr;
     return true;
   }
   return false;
diff --git a/chrome/browser/ui/libgtkui/gconf_listener.h b/chrome/browser/ui/libgtkui/gconf_listener.h
index 25b60ecc..75d33696 100644
--- a/chrome/browser/ui/libgtkui/gconf_listener.h
+++ b/chrome/browser/ui/libgtkui/gconf_listener.h
@@ -46,7 +46,7 @@
 
   GtkUi* delegate_;
 
-  // Pointer to our gconf context. NULL if we aren't on a desktop that uses
+  // Pointer to our gconf context. nullptr if we aren't on a desktop that uses
   // gconf.
   GConfClient* client_;
 
diff --git a/chrome/browser/ui/libgtkui/gtk_event_loop.cc b/chrome/browser/ui/libgtkui/gtk_event_loop.cc
index ccf4742..1862918e 100644
--- a/chrome/browser/ui/libgtkui/gtk_event_loop.cc
+++ b/chrome/browser/ui/libgtkui/gtk_event_loop.cc
@@ -21,12 +21,12 @@
 }
 
 Gtk2EventLoop::Gtk2EventLoop() {
-  gdk_event_handler_set(DispatchGdkEvent, NULL, NULL);
+  gdk_event_handler_set(DispatchGdkEvent, nullptr, nullptr);
 }
 
 Gtk2EventLoop::~Gtk2EventLoop() {
-  gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), NULL,
-                        NULL);
+  gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event),
+                        nullptr, nullptr);
 }
 
 // static
diff --git a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
index 1a56802..59244f4 100644
--- a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
+++ b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
@@ -81,7 +81,7 @@
 
 GtkWidget* Gtk2KeyBindingsHandler::CreateNewHandler() {
   Handler* handler =
-      static_cast<Handler*>(g_object_new(HandlerGetType(), NULL));
+      static_cast<Handler*>(g_object_new(HandlerGetType(), nullptr));
 
   handler->owner = this;
 
@@ -133,7 +133,7 @@
   gdk_keymap_translate_keyboard_state(
       keymap, gdk_event->hardware_keycode,
       static_cast<GdkModifierType>(gdk_event->state), gdk_event->group,
-      &gdk_event->keyval, NULL, NULL, &consumed);
+      &gdk_event->keyval, nullptr, nullptr, &consumed);
 
   state = static_cast<GdkModifierType>(gdk_event->state & ~consumed);
   gdk_keymap_add_virtual_modifiers(keymap, &state);
@@ -141,7 +141,7 @@
 }
 
 void Gtk2KeyBindingsHandler::HandlerInit(Handler* self) {
-  self->owner = NULL;
+  self->owner = nullptr;
 }
 
 void Gtk2KeyBindingsHandler::HandlerClassInit(HandlerClass* klass) {
diff --git a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
index 4c0cf02..6794cc22d 100644
--- a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
+++ b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.h
@@ -46,7 +46,7 @@
   // Matches a key event against predefined gtk key bindings, false will be
   // returned if the key event doesn't correspond to a predefined key binding.
   // Edit commands matched with |event| will be stored in |edit_commands|, if
-  // non-NULL.
+  // non-nullptr.
   bool MatchEvent(const ui::Event& event,
                   std::vector<ui::TextEditCommandAuraLinux>* commands);
 
diff --git a/chrome/browser/ui/libgtkui/gtk_status_icon.cc b/chrome/browser/ui/libgtkui/gtk_status_icon.cc
index c42da502..5c8357b 100644
--- a/chrome/browser/ui/libgtkui/gtk_status_icon.cc
+++ b/chrome/browser/ui/libgtkui/gtk_status_icon.cc
@@ -75,7 +75,7 @@
                                             guint button,
                                             guint32 activate_time) {
   if (menu_.get()) {
-    gtk_menu_popup(menu_->GetGtkMenu(), NULL, NULL,
+    gtk_menu_popup(menu_->GetGtkMenu(), nullptr, nullptr,
                    gtk_status_icon_position_menu, gtk_status_icon_, button,
                    activate_time);
   }
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 02add34d..3423149 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -82,13 +82,6 @@
 // - Render and inject the omnibox background.
 // - Make sure to test with a light on dark theme, too.
 
-// Work around a header bug:
-// linux/debian_wheezy_i386-sysroot/usr/include/linux/stddef.h redefines NULL
-// to 0, which breaks -Wsentinel. Get back the normal definition of NULL.
-// TODO(thakis): Remove this once we update sysroots.
-#define __need_NULL
-#include <stddef.h>
-
 namespace libgtkui {
 
 namespace {
@@ -155,13 +148,13 @@
     {
       // http://crbug.com/346740
       ANNOTATE_SCOPED_MEMORY_LEAK;
-      pixmap = gtk_widget_get_snapshot(button, NULL);
+      pixmap = gtk_widget_get_snapshot(button, nullptr);
     }
 
     gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h);
     GdkColormap* colormap = gdk_drawable_get_colormap(pixmap);
     GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(
-        NULL, GDK_DRAWABLE(pixmap), colormap, 0, 0, 0, 0, w, h);
+        nullptr, GDK_DRAWABLE(pixmap), colormap, 0, 0, 0, 0, w, h);
 
     gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
     cairo_paint(cr);
@@ -302,11 +295,11 @@
   CHECK(gtk_settings);
   gint antialias = 0;
   gint hinting = 0;
-  gchar* hint_style = NULL;
-  gchar* rgba = NULL;
+  gchar* hint_style = nullptr;
+  gchar* rgba = nullptr;
   g_object_get(gtk_settings, "gtk-xft-antialias", &antialias, "gtk-xft-hinting",
                &hinting, "gtk-xft-hintstyle", &hint_style, "gtk-xft-rgba",
-               &rgba, NULL);
+               &rgba, nullptr);
 
   gfx::FontRenderParams params;
   params.antialiasing = antialias != 0;
@@ -352,7 +345,7 @@
   GtkSettings* gtk_settings = gtk_settings_get_default();
   CHECK(gtk_settings);
   gint gtk_dpi = -1;
-  g_object_get(gtk_settings, "gtk-xft-dpi", &gtk_dpi, NULL);
+  g_object_get(gtk_settings, "gtk-xft-dpi", &gtk_dpi, nullptr);
 
   // GTK multiplies the DPI by 1024 before storing it.
   return (gtk_dpi > 0) ? gtk_dpi / 1024.0 : kDefaultDPI;
@@ -559,12 +552,12 @@
   gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
   gboolean cursor_blink = TRUE;
   g_object_get(gtk_settings_get_default(), "gtk-cursor-blink-time",
-               &cursor_blink_time, "gtk-cursor-blink", &cursor_blink, NULL);
+               &cursor_blink_time, "gtk-cursor-blink", &cursor_blink, nullptr);
   return cursor_blink ? (cursor_blink_time / kGtkCursorBlinkCycleFactor) : 0.0;
 }
 
 ui::NativeTheme* GtkUi::GetNativeTheme(aura::Window* window) const {
-  ui::NativeTheme* native_theme_override = NULL;
+  ui::NativeTheme* native_theme_override = nullptr;
   if (!native_theme_overrider_.is_null())
     native_theme_override = native_theme_overrider_.Run(window);
 
@@ -639,7 +632,7 @@
         static_cast<GtkIconLookupFlags>(GTK_ICON_LOOKUP_FORCE_SIZE)));
     if (!icon_info)
       continue;
-    ScopedGdkPixbuf pixbuf(gtk_icon_info_load_icon(icon_info.get(), NULL));
+    ScopedGdkPixbuf pixbuf(gtk_icon_info_load_icon(icon_info.get(), nullptr));
     if (!pixbuf)
       continue;
 
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.h b/chrome/browser/ui/libgtkui/gtk_ui.h
index f58d943..627aab5 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.h
+++ b/chrome/browser/ui/libgtkui/gtk_ui.h
@@ -178,7 +178,7 @@
   NonClientMiddleClickAction middle_click_action_;
 
   // Used to override the native theme for a window. If no override is provided
-  // or the callback returns NULL, GtkUi will default to a NativeThemeGtk2
+  // or the callback returns nullptr, GtkUi will default to a NativeThemeGtk2
   // instance.
   NativeThemeGetter native_theme_overrider_;
 
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc
index a17fd4b..9463d533 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.cc
+++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -40,7 +40,7 @@
     // here.
     argv[i] = strdup(args[i].c_str());
   }
-  argv[argc] = NULL;
+  argv[argc] = nullptr;
   char** argv_pointer = argv.get();
 
   {
@@ -203,7 +203,7 @@
 }
 
 void ClearAuraTransientParent(GtkWidget* dialog) {
-  g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, NULL);
+  g_object_set_data(G_OBJECT(dialog), kAuraTransientParent, nullptr);
 }
 
 #if GTK_MAJOR_VERSION > 2
diff --git a/chrome/browser/ui/libgtkui/gtk_util.h b/chrome/browser/ui/libgtkui/gtk_util.h
index 167a54c4f..322974a 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.h
+++ b/chrome/browser/ui/libgtkui/gtk_util.h
@@ -66,7 +66,7 @@
 void TurnButtonBlue(GtkWidget* button);
 
 // Sets |dialog| as transient for |parent|, which will keep it on top and center
-// it above |parent|. Do nothing if |parent| is NULL.
+// it above |parent|. Do nothing if |parent| is nullptr.
 void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent);
 
 // Gets the transient parent aura window for |dialog|.
@@ -177,7 +177,7 @@
 typedef ScopedGObject<GtkStyleContext> ScopedStyleContext;
 typedef ScopedGObject<GtkCssProvider> ScopedCssProvider;
 
-// If |context| is NULL, creates a new top-level style context
+// If |context| is nullptr, creates a new top-level style context
 // specified by parsing |css_node|.  Otherwise, creates the child
 // context with |context| as the parent.
 ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
diff --git a/chrome/browser/ui/libgtkui/menu_util.cc b/chrome/browser/ui/libgtkui/menu_util.cc
index e2c95e9..5ce8aaf 100644
--- a/chrome/browser/ui/libgtkui/menu_util.cc
+++ b/chrome/browser/ui/libgtkui/menu_util.cc
@@ -73,7 +73,7 @@
 
 bool GetMenuItemID(GtkWidget* menu_item, int* menu_id) {
   gpointer id_ptr = g_object_get_data(G_OBJECT(menu_item), "menu-id");
-  if (id_ptr != NULL) {
+  if (id_ptr != nullptr) {
     *menu_id = GPOINTER_TO_INT(id_ptr) - 1;
     return true;
   }
@@ -99,7 +99,7 @@
                            bool* block_activation,
                            void* this_ptr) {
   std::map<int, GtkWidget*> radio_groups;
-  GtkWidget* menu_item = NULL;
+  GtkWidget* menu_item = nullptr;
   for (int i = 0; i < model->GetItemCount(); ++i) {
     gfx::Image icon;
     std::string label = ui::ConvertAcceleratorsFromWindowsStyle(
@@ -122,7 +122,7 @@
 
         if (iter == radio_groups.end()) {
           menu_item =
-              gtk_radio_menu_item_new_with_mnemonic(NULL, label.c_str());
+              gtk_radio_menu_item_new_with_mnemonic(nullptr, label.c_str());
           radio_groups[model->GetGroupIdAt(i)] = menu_item;
         } else {
           menu_item = gtk_radio_menu_item_new_with_mnemonic_from_widget(
@@ -170,9 +170,7 @@
 
     ui::Accelerator accelerator;
     if (model->GetAcceleratorAt(i, &accelerator)) {
-      gtk_widget_add_accelerator(menu_item,
-                                 "activate",
-                                 NULL,
+      gtk_widget_add_accelerator(menu_item, "activate", nullptr,
                                  GetGdkKeyCodeForAccelerator(accelerator),
                                  GetGdkModifierForAccelerator(accelerator),
                                  GTK_ACCEL_VISIBLE);
@@ -187,7 +185,7 @@
                          item_activated_cb,
                          this_ptr);
 
-    menu_item = NULL;
+    menu_item = nullptr;
   }
 }
 
@@ -243,7 +241,7 @@
                 gtk_image_new_from_pixbuf(pixbuf));
             g_object_unref(pixbuf);
           } else {
-            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), NULL);
+            gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(widget), nullptr);
           }
         }
       }
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk2.cc b/chrome/browser/ui/libgtkui/native_theme_gtk2.cc
index a4d40f1..1ae5b7b 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk2.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk2.cc
@@ -362,7 +362,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetWindow() const {
-  static GtkWidget* fake_window = NULL;
+  static GtkWidget* fake_window = nullptr;
 
   if (!fake_window) {
     fake_window = chrome_gtk_frame_new();
@@ -373,7 +373,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetEntry() const {
-  static GtkWidget* fake_entry = NULL;
+  static GtkWidget* fake_entry = nullptr;
 
   if (!fake_entry) {
     fake_entry = gtk_entry_new();
@@ -388,7 +388,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetLabel() const {
-  static GtkWidget* fake_label = NULL;
+  static GtkWidget* fake_label = nullptr;
 
   if (!fake_label)
     fake_label = gtk_label_new("");
@@ -397,7 +397,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetButton() const {
-  static GtkWidget* fake_button = NULL;
+  static GtkWidget* fake_button = nullptr;
 
   if (!fake_button)
     fake_button = gtk_button_new();
@@ -406,7 +406,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetBlueButton() const {
-  static GtkWidget* fake_bluebutton = NULL;
+  static GtkWidget* fake_bluebutton = nullptr;
 
   if (!fake_bluebutton) {
     fake_bluebutton = gtk_button_new();
@@ -417,7 +417,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetTree() const {
-  static GtkWidget* fake_tree = NULL;
+  static GtkWidget* fake_tree = nullptr;
 
   if (!fake_tree)
     fake_tree = gtk_tree_view_new();
@@ -426,7 +426,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetTooltip() const {
-  static GtkWidget* fake_tooltip = NULL;
+  static GtkWidget* fake_tooltip = nullptr;
 
   if (!fake_tooltip) {
     fake_tooltip = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -438,7 +438,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetMenu() const {
-  static GtkWidget* fake_menu = NULL;
+  static GtkWidget* fake_menu = nullptr;
 
   if (!fake_menu)
     fake_menu = gtk_custom_menu_new();
@@ -447,7 +447,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetMenuItem() const {
-  static GtkWidget* fake_menu_item = NULL;
+  static GtkWidget* fake_menu_item = nullptr;
 
   if (!fake_menu_item) {
     fake_menu_item = gtk_custom_menu_item_new();
@@ -458,7 +458,7 @@
 }
 
 GtkWidget* NativeThemeGtk2::GetSeparator() const {
-  static GtkWidget* fake_separator = NULL;
+  static GtkWidget* fake_separator = nullptr;
 
   if (!fake_separator)
     fake_separator = gtk_hseparator_new();
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
index 7b8028a2..113951a2 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
@@ -539,7 +539,7 @@
     gtk_style_context_get_border(context, state, &border);
     gtk_style_context_get_padding(context, state, &padding);
     int min_height = 1;
-    gtk_style_context_get(context, state, "min-height", &min_height, NULL);
+    gtk_style_context_get(context, state, "min-height", &min_height, nullptr);
     int w = rect.width() - margin.left - margin.right;
     int h = std::max(
         min_height + padding.top + padding.bottom + border.top + border.bottom,
diff --git a/chrome/browser/ui/libgtkui/print_dialog_gtk.cc b/chrome/browser/ui/libgtkui/print_dialog_gtk.cc
index 0b64072..9e4a97a 100644
--- a/chrome/browser/ui/libgtkui/print_dialog_gtk.cc
+++ b/chrome/browser/ui/libgtkui/print_dialog_gtk.cc
@@ -72,11 +72,11 @@
 }
 
 // Looks up a paper size matching (in terms of PaperSizeMatch) the user selected
-// media in the paper size list reported by GTK. Returns NULL if there's no
+// media in the paper size list reported by GTK. Returns nullptr if there's no
 // match found.
 GtkPaperSize* FindPaperSizeMatch(GList* gtk_paper_sizes,
                                  const PrintSettings::RequestedMedia& media) {
-  GtkPaperSize* first_fuzzy_match = NULL;
+  GtkPaperSize* first_fuzzy_match = nullptr;
   for (GList* p = gtk_paper_sizes; p && p->data; p = g_list_next(p)) {
     GtkPaperSize* gtk_paper_size = static_cast<GtkPaperSize*>(p->data);
     if (PaperSizeMatch(gtk_paper_size, media, false)) {
@@ -116,8 +116,8 @@
 // Helper class to track GTK printers.
 class GtkPrinterList {
  public:
-  GtkPrinterList() : default_printer_(NULL) {
-    gtk_enumerate_printers(SetPrinter, this, NULL, TRUE);
+  GtkPrinterList() : default_printer_(nullptr) {
+    gtk_enumerate_printers(SetPrinter, this, nullptr, TRUE);
   }
 
   ~GtkPrinterList() {
@@ -127,16 +127,16 @@
     }
   }
 
-  // Can return NULL if there's no default printer. E.g. Printer on a laptop
+  // Can return nullptr if there's no default printer. E.g. Printer on a laptop
   // is "home_printer", but the laptop is at work.
   GtkPrinter* default_printer() { return default_printer_; }
 
-  // Can return NULL if the printer cannot be found due to:
+  // Can return nullptr if the printer cannot be found due to:
   // - Printer list out of sync with printer dialog UI.
   // - Querying for non-existant printers like 'Print to PDF'.
   GtkPrinter* GetPrinterWithName(const std::string& name) {
     if (name.empty())
-      return NULL;
+      return nullptr;
 
     for (std::vector<GtkPrinter*>::iterator it = printers_.begin();
          it < printers_.end(); ++it) {
@@ -145,7 +145,7 @@
       }
     }
 
-    return NULL;
+    return nullptr;
   }
 
  private:
@@ -176,10 +176,10 @@
 
 PrintDialogGtk2::PrintDialogGtk2(PrintingContextLinux* context)
     : context_(context),
-      dialog_(NULL),
-      gtk_settings_(NULL),
-      page_setup_(NULL),
-      printer_(NULL) {}
+      dialog_(nullptr),
+      gtk_settings_(nullptr),
+      page_setup_(nullptr),
+      printer_(nullptr) {}
 
 PrintDialogGtk2::~PrintDialogGtk2() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -191,19 +191,19 @@
       libgtkui::ClearAuraTransientParent(dialog_);
     }
     gtk_widget_destroy(dialog_);
-    dialog_ = NULL;
+    dialog_ = nullptr;
   }
   if (gtk_settings_) {
     g_object_unref(gtk_settings_);
-    gtk_settings_ = NULL;
+    gtk_settings_ = nullptr;
   }
   if (page_setup_) {
     g_object_unref(page_setup_);
-    page_setup_ = NULL;
+    page_setup_ = nullptr;
   }
   if (printer_) {
     g_object_unref(printer_);
-    printer_ = NULL;
+    printer_ = nullptr;
   }
 }
 
@@ -250,7 +250,7 @@
                          color_value.c_str());
 
   if (settings->duplex_mode() != printing::UNKNOWN_DUPLEX_MODE) {
-    const char* cups_duplex_mode = NULL;
+    const char* cups_duplex_mode = nullptr;
     switch (settings->duplex_mode()) {
       case printing::LONG_EDGE:
         cups_duplex_mode = kDuplexNoTumble;
@@ -302,7 +302,7 @@
                          reinterpret_cast<GDestroyNotify>(gtk_paper_size_free));
 #else
         g_list_foreach(gtk_paper_sizes,
-                       reinterpret_cast<GFunc>(gtk_paper_size_free), NULL);
+                       reinterpret_cast<GFunc>(gtk_paper_size_free), nullptr);
         g_list_free(gtk_paper_sizes);
 #endif
       }
@@ -326,12 +326,12 @@
   callback_ = callback;
   DCHECK(!callback_.is_null());
 
-  dialog_ = gtk_print_unix_dialog_new(NULL, NULL);
+  dialog_ = gtk_print_unix_dialog_new(nullptr, nullptr);
   libgtkui::SetGtkTransientForAura(dialog_, parent_view);
   if (parent_view)
     parent_view->AddObserver(this);
   g_signal_connect(dialog_, "delete-event",
-                   G_CALLBACK(gtk_widget_hide_on_delete), NULL);
+                   G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
 
   // Handle the case when the existing |gtk_settings_| has "selection" selected
   // as the page range, but |has_selection| is false.
@@ -504,8 +504,8 @@
     const base::string16& document_name) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // If |printer_| is NULL then somehow the GTK printer list changed out under
-  // us. In which case, just bail out.
+  // If |printer_| is nullptr then somehow the GTK printer list changed out
+  // under us. In which case, just bail out.
   if (!printer_) {
     // Matches AddRef() in PrintDocument();
     Release();
@@ -518,8 +518,9 @@
   GtkPrintJob* print_job =
       gtk_print_job_new(base::UTF16ToUTF8(document_name).c_str(), printer_,
                         gtk_settings_, page_setup_);
-  gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(), NULL);
-  gtk_print_job_send(print_job, OnJobCompletedThunk, this, NULL);
+  gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(),
+                                nullptr);
+  gtk_print_job_send(print_job, OnJobCompletedThunk, this, nullptr);
 }
 
 void PrintDialogGtk2::OnJobCompleted(GtkPrintJob* print_job,
diff --git a/chrome/browser/ui/libgtkui/select_file_dialog_impl.cc b/chrome/browser/ui/libgtkui/select_file_dialog_impl.cc
index 6a95ee0..d1bc797 100644
--- a/chrome/browser/ui/libgtkui/select_file_dialog_impl.cc
+++ b/chrome/browser/ui/libgtkui/select_file_dialog_impl.cc
@@ -28,8 +28,8 @@
 
 namespace libgtkui {
 
-base::FilePath* SelectFileDialogImpl::last_saved_path_ = NULL;
-base::FilePath* SelectFileDialogImpl::last_opened_path_ = NULL;
+base::FilePath* SelectFileDialogImpl::last_saved_path_ = nullptr;
+base::FilePath* SelectFileDialogImpl::last_opened_path_ = nullptr;
 
 // static
 ui::SelectFileDialog* SelectFileDialogImpl::Create(
@@ -81,7 +81,7 @@
 SelectFileDialogImpl::~SelectFileDialogImpl() { }
 
 void SelectFileDialogImpl::ListenerDestroyed() {
-  listener_ = NULL;
+  listener_ = nullptr;
 }
 
 bool SelectFileDialogImpl::CallDirectoryExistsOnUIThread(
diff --git a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
index 0671241d..b3bb164 100644
--- a/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/select_file_dialog_impl_gtk.cc
@@ -76,7 +76,7 @@
 
 SelectFileDialogImplGTK::SelectFileDialogImplGTK(Listener* listener,
                                                  ui::SelectFilePolicy* policy)
-    : SelectFileDialogImpl(listener, policy), preview_(NULL) {}
+    : SelectFileDialogImpl(listener, policy), preview_(nullptr) {}
 
 SelectFileDialogImplGTK::~SelectFileDialogImplGTK() {
   for (std::set<aura::Window*>::iterator iter = parents_.begin();
@@ -134,7 +134,7 @@
   if (file_types)
     file_types_ = *file_types;
 
-  GtkWidget* dialog = NULL;
+  GtkWidget* dialog = nullptr;
   switch (type) {
     case SELECT_FOLDER:
     case SELECT_UPLOAD_FOLDER:
@@ -156,7 +156,7 @@
       return;
   }
   g_signal_connect(dialog, "delete-event",
-                   G_CALLBACK(gtk_widget_hide_on_delete), NULL);
+                   G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
   dialogs_.insert(dialog);
 
   preview_ = gtk_image_new();
@@ -197,7 +197,7 @@
 
 void SelectFileDialogImplGTK::AddFilters(GtkFileChooser* chooser) {
   for (size_t i = 0; i < file_types_.extensions.size(); ++i) {
-    GtkFileFilter* filter = NULL;
+    GtkFileFilter* filter = nullptr;
     std::set<std::string> fallback_labels;
 
     for (size_t j = 0; j < file_types_.extensions[i].size(); ++j) {
@@ -296,7 +296,7 @@
     const base::FilePath& default_path,
     gfx::NativeWindow parent) {
   GtkWidget* dialog = gtk_file_chooser_dialog_new(
-      title.c_str(), NULL, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel",
+      title.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel",
       GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, nullptr);
   SetGtkTransientForAura(dialog, parent);
   AddFilters(GTK_FILE_CHOOSER(dialog));
@@ -337,7 +337,7 @@
           : "_Open";
 
   GtkWidget* dialog = gtk_file_chooser_dialog_new(
-      title_string.c_str(), NULL, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+      title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
       "_Cancel", GTK_RESPONSE_CANCEL, accept_button_label.c_str(),
       GTK_RESPONSE_ACCEPT, nullptr);
   SetGtkTransientForAura(dialog, parent);
@@ -394,7 +394,7 @@
                      : l10n_util::GetStringUTF8(IDS_SAVE_AS_DIALOG_TITLE);
 
   GtkWidget* dialog = gtk_file_chooser_dialog_new(
-      title_string.c_str(), NULL, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel",
+      title_string.c_str(), nullptr, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel",
       GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, nullptr);
   SetGtkTransientForAura(dialog, parent);
 
@@ -498,7 +498,7 @@
   }
 
   std::vector<base::FilePath> filenames_fp;
-  for (GSList* iter = filenames; iter != NULL; iter = g_slist_next(iter)) {
+  for (GSList* iter = filenames; iter != nullptr; iter = g_slist_next(iter)) {
     base::FilePath path(static_cast<char*>(iter->data));
     g_free(iter->data);
     if (CallDirectoryExistsOnUIThread(path))
@@ -517,7 +517,7 @@
 void SelectFileDialogImplGTK::OnFileChooserDestroy(GtkWidget* dialog) {
   dialogs_.erase(dialog);
 
-  // |parent| can be NULL when closing the host window
+  // |parent| can be nullptr when closing the host window
   // while opening the file-picker.
   aura::Window* parent = GetAuraTransientParent(dialog);
   if (!parent)
@@ -552,7 +552,7 @@
 
   // This will preserve the image's aspect ratio.
   GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file_at_size(filename, kPreviewWidth,
-                                                       kPreviewHeight, NULL);
+                                                       kPreviewHeight, nullptr);
   g_free(filename);
   if (pixbuf) {
     gtk_image_set_from_pixbuf(GTK_IMAGE(preview_), pixbuf);
diff --git a/chrome/browser/ui/libgtkui/skia_utils_gtk.cc b/chrome/browser/ui/libgtkui/skia_utils_gtk.cc
index 989b4a6..f4a2dd9 100644
--- a/chrome/browser/ui/libgtkui/skia_utils_gtk.cc
+++ b/chrome/browser/ui/libgtkui/skia_utils_gtk.cc
@@ -86,7 +86,7 @@
 
 GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
   if (bitmap.isNull())
-    return NULL;
+    return nullptr;
 
   SkAutoLockPixels lock_pixels(bitmap);
 
diff --git a/chrome/browser/ui/libgtkui/unity_service.cc b/chrome/browser/ui/libgtkui/unity_service.cc
index 78abe9b1..9903568 100644
--- a/chrome/browser/ui/libgtkui/unity_service.cc
+++ b/chrome/browser/ui/libgtkui/unity_service.cc
@@ -38,18 +38,18 @@
 bool attempted_load = false;
 
 // Unity has a singleton object that we can ask whether the unity is running.
-UnityInspector* inspector = NULL;
+UnityInspector* inspector = nullptr;
 
 // A link to the desktop entry in the panel.
-UnityLauncherEntry* chrome_entry = NULL;
+UnityLauncherEntry* chrome_entry = nullptr;
 
 // Retrieved functions from libunity.
-unity_inspector_get_unity_running_func get_unity_running = NULL;
-unity_launcher_entry_set_count_func entry_set_count = NULL;
-unity_launcher_entry_set_count_visible_func entry_set_count_visible = NULL;
-unity_launcher_entry_set_progress_func entry_set_progress = NULL;
+unity_inspector_get_unity_running_func get_unity_running = nullptr;
+unity_launcher_entry_set_count_func entry_set_count = nullptr;
+unity_launcher_entry_set_count_visible_func entry_set_count_visible = nullptr;
+unity_launcher_entry_set_progress_func entry_set_progress = nullptr;
 unity_launcher_entry_set_progress_visible_func entry_set_progress_visible =
-    NULL;
+    nullptr;
 
 void EnsureMethodsLoaded() {
   using base::nix::GetDesktopEnvironment;
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
index cfd6ede..f40654b 100644
--- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
@@ -31,8 +31,8 @@
     ui::LinuxInputMethodContextDelegate* delegate,
     bool is_simple)
     : delegate_(delegate),
-      gtk_context_(NULL),
-      gdk_last_set_client_window_(NULL) {
+      gtk_context_(nullptr),
+      gdk_last_set_client_window_(nullptr) {
   CHECK(delegate_);
 
   ResetXModifierKeycodesCache();
@@ -55,7 +55,7 @@
 X11InputMethodContextImplGtk2::~X11InputMethodContextImplGtk2() {
   if (gtk_context_) {
     g_object_unref(gtk_context_);
-    gtk_context_ = NULL;
+    gtk_context_ = nullptr;
   }
 }
 
@@ -188,15 +188,15 @@
   }
   if (!display) {
     LOG(ERROR) << "Cannot get a GdkDisplay for a key event.";
-    return NULL;
+    return nullptr;
   }
   // Get a keysym and group.
   KeySym keysym = NoSymbol;
   guint8 keyboard_group = 0;
-  XLookupString(&xkey, NULL, 0, &keysym, NULL);
+  XLookupString(&xkey, nullptr, 0, &keysym, nullptr);
   GdkKeymap* keymap = gdk_keymap_get_for_display(display);
-  GdkKeymapKey* keys = NULL;
-  guint* keyvals = NULL;
+  GdkKeymapKey* keys = nullptr;
+  guint* keyvals = nullptr;
   gint n_entries = 0;
   if (keymap && gdk_keymap_get_entries_for_keycode(keymap, xkey.keycode, &keys,
                                                    &keyvals, &n_entries)) {
@@ -208,9 +208,9 @@
     }
   }
   g_free(keys);
-  keys = NULL;
+  keys = nullptr;
   g_free(keyvals);
-  keyvals = NULL;
+  keyvals = nullptr;
 // Get a GdkWindow.
 #if GTK_CHECK_VERSION(2, 24, 0)
   GdkWindow* window = gdk_x11_window_lookup_for_display(display, xkey.window);
@@ -227,7 +227,7 @@
 #endif
   if (!window) {
     LOG(ERROR) << "Cannot get a GdkWindow for a key event.";
-    return NULL;
+    return nullptr;
   }
 
   // Create a GdkEvent.
@@ -242,7 +242,7 @@
   event->key.state = xkey.state;
   event->key.keyval = keysym;
   event->key.length = 0;
-  event->key.string = NULL;
+  event->key.string = nullptr;
   event->key.hardware_keycode = xkey.keycode;
   event->key.group = keyboard_group;
   event->key.is_modifier = IsKeycodeModifierKey(xkey.keycode);
@@ -292,8 +292,8 @@
   if (context != gtk_context_)
     return;
 
-  gchar* str = NULL;
-  PangoAttrList* attrs = NULL;
+  gchar* str = nullptr;
+  PangoAttrList* attrs = nullptr;
   gint cursor_pos = 0;
   gtk_im_context_get_preedit_string(context, &str, &attrs, &cursor_pos);
   ui::CompositionText composition_text;
diff --git a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
index db4011a..d3733a8 100644
--- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
+++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.h
@@ -43,7 +43,7 @@
   void ResetXModifierKeycodesCache();
 
   // Constructs a GdkEventKey from a XKeyEvent and returns it.  Otherwise,
-  // returns NULL.  The returned GdkEvent must be freed by gdk_event_free.
+  // returns nullptr.  The returned GdkEvent must be freed by gdk_event_free.
   GdkEvent* GdkEventFromNativeEvent(const base::NativeEvent& native_event);
 
   // Returns true if the hardware |keycode| is assigned to a modifier key.
@@ -76,7 +76,7 @@
                      OnPreeditStart,
                      GtkIMContext*);
 
-  // A set of callback functions.  Must not be NULL.
+  // A set of callback functions.  Must not be nullptr.
   ui::LinuxInputMethodContextDelegate* delegate_;
 
   // IME's input GTK context.
diff --git a/chrome/browser/ui/scoped_tabbed_browser_displayer.cc b/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
index 6f09f0b..9ad5bffb 100644
--- a/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
+++ b/chrome/browser/ui/scoped_tabbed_browser_displayer.cc
@@ -13,7 +13,7 @@
 ScopedTabbedBrowserDisplayer::ScopedTabbedBrowserDisplayer(Profile* profile) {
   browser_ = FindTabbedBrowser(profile, false);
   if (!browser_)
-    browser_ = new Browser(Browser::CreateParams(profile));
+    browser_ = new Browser(Browser::CreateParams(profile, true));
 }
 
 ScopedTabbedBrowserDisplayer::~ScopedTabbedBrowserDisplayer() {
diff --git a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
index 49f3756..cb8f2584 100644
--- a/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
+++ b/chrome/browser/ui/startup/session_crashed_infobar_delegate_unittest.cc
@@ -57,7 +57,7 @@
               browser()->profile()))));
 
   // Create a browser which we can close during the test.
-  Browser::CreateParams params(browser()->profile());
+  Browser::CreateParams params(browser()->profile(), true);
   std::unique_ptr<Browser> first_browser(
       chrome::CreateBrowserWithTestWindowForParams(&params));
   AddTab(first_browser.get(), GURL(chrome::kChromeUINewTabURL));
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 1cdbcaf..cfe7120 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -229,7 +229,7 @@
   BrowserList::AddObserver(&observer);
 
   Browser* popup = new Browser(
-      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile()));
+      Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile(), true));
   ASSERT_TRUE(popup->is_type_popup());
   ASSERT_EQ(popup, observer.added_browser_);
 
@@ -526,14 +526,14 @@
 
   // Open some urls with the browsers, and close them.
   Browser* browser1 =
-      new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile1));
+      new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile1, true));
   chrome::NewTab(browser1);
   ui_test_utils::NavigateToURL(browser1,
                                embedded_test_server()->GetURL("/empty.html"));
   CloseBrowserSynchronously(browser1);
 
-  Browser* browser2 = new Browser(
-      Browser::CreateParams(Browser::TYPE_TABBED, profile2));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile2, true));
   chrome::NewTab(browser2);
   ui_test_utils::NavigateToURL(browser2,
                                embedded_test_server()->GetURL("/form.html"));
@@ -667,7 +667,7 @@
 
   // Open a page with profile_last.
   Browser* browser_last = new Browser(
-      Browser::CreateParams(Browser::TYPE_TABBED, profile_last));
+      Browser::CreateParams(Browser::TYPE_TABBED, profile_last, true));
   chrome::NewTab(browser_last);
   ui_test_utils::NavigateToURL(browser_last,
                                embedded_test_server()->GetURL("/empty.html"));
@@ -911,7 +911,14 @@
   policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorFirstRunTest, AddFirstRunTab) {
+// http://crbug.com/691707
+#if defined(OS_MACOSX)
+#define MAYBE_AddFirstRunTab DISABLED_AddFirstRunTab
+#else
+#define MAYBE_AddFirstRunTab AddFirstRunTab
+#endif
+IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorFirstRunTest,
+                       MAYBE_AddFirstRunTab) {
   ASSERT_TRUE(embedded_test_server()->Start());
   StartupBrowserCreator browser_creator;
   browser_creator.AddFirstRunTab(
@@ -1047,7 +1054,13 @@
             tab_strip->GetWebContentsAt(0)->GetURL().ExtractFileName());
 }
 
-IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorFirstRunTest, WelcomePages) {
+// http://crbug.com/691707
+#if defined(OS_MACOSX)
+#define MAYBE_WelcomePages DISABLED_WelcomePages
+#else
+#define MAYBE_WelcomePages WelcomePages
+#endif
+IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorFirstRunTest, MAYBE_WelcomePages) {
   ASSERT_TRUE(embedded_test_server()->Start());
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index d3f1d623..7a2e089 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -447,8 +447,15 @@
   if (!profile_ && browser)
     profile_ = browser->profile();
 
-  if (!browser || !browser->is_type_tabbed())
-    browser = new Browser(Browser::CreateParams(profile_));
+  if (!browser || !browser->is_type_tabbed()) {
+    // Startup browsers are not counted as being created by a user_gesture
+    // because of historical accident, even though the startup browser was
+    // created in response to the user clicking on chrome. There was an
+    // incomplete check on whether a user gesture created a window which looked
+    // at the state of the MessageLoop.
+    Browser::CreateParams params = Browser::CreateParams(profile_, false);
+    browser = new Browser(params);
+  }
 
   bool first_tab = true;
   ProtocolHandlerRegistry* registry = profile_ ?
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 4933765..6f89100 100644
--- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
+++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -565,7 +565,7 @@
     // create a new one.
     browser = chrome::FindLastActiveWithProfile(profile);
     if (!browser) {
-      browser = new Browser(Browser::CreateParams(profile));
+      browser = new Browser(Browser::CreateParams(profile, true));
       chrome::AddTabAt(browser, GURL(), -1, true);
     }
     browser->window()->Show();
diff --git a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
index 7c71a2f0..a1398fe 100644
--- a/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
+++ b/chrome/browser/ui/tab_contents/tab_contents_iterator_unittest.cc
@@ -48,12 +48,12 @@
   EXPECT_EQ(0U, CountAllTabs());
 
   // Create more browsers/windows.
-  Browser::CreateParams native_params(profile());
+  Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
   // Create browser 3 and 4 on the Ash desktop (the TabContentsIterator
   // shouldn't see the difference).
-  Browser::CreateParams ash_params(profile());
+  Browser::CreateParams ash_params(profile(), true);
   std::unique_ptr<Browser> browser3(
       chrome::CreateBrowserWithTestWindowForParams(&ash_params));
   std::unique_ptr<Browser> browser4(
@@ -94,12 +94,12 @@
   EXPECT_EQ(1U, BrowserList::GetInstance()->size());
 
   // Create more browsers/windows.
-  Browser::CreateParams native_params(profile());
+  Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser2(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
   // Create browser 3 on the Ash desktop (the TabContentsIterator shouldn't see
   // the difference).
-  Browser::CreateParams ash_params(profile());
+  Browser::CreateParams ash_params(profile(), true);
   std::unique_ptr<Browser> browser3(
       chrome::CreateBrowserWithTestWindowForParams(&ash_params));
 
diff --git a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
index 7ba1521..e851160 100644
--- a/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
+++ b/chrome/browser/ui/tabs/pinned_tab_service_unittest.cc
@@ -57,7 +57,7 @@
   browser()->tab_strip_model()->SetTabPinned(0, true);
 
   // Create a popup.
-  Browser::CreateParams params(Browser::TYPE_POPUP, profile());
+  Browser::CreateParams params(Browser::TYPE_POPUP, profile(), true);
   std::unique_ptr<Browser> popup(
       chrome::CreateBrowserWithTestWindowForParams(&params));
 
diff --git a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
index 48395cb..4ff581c 100644
--- a/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/back_forward_menu_model_unittest.cc
@@ -502,7 +502,7 @@
 TEST_F(BackFwdMenuModelTest, FaviconLoadTest) {
   ASSERT_TRUE(profile()->CreateHistoryService(true, false));
   profile()->CreateFaviconService();
-  Browser::CreateParams native_params(profile());
+  Browser::CreateParams native_params(profile(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
   FaviconDelegate favicon_delegate;
diff --git a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
index 7c0e3f8..9ea5488 100644
--- a/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
+++ b/chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc
@@ -657,7 +657,7 @@
       test_data_dir_.AppendASCII("api_test/browser_action_with_icon"));
   ASSERT_TRUE(extension);
   Browser* second_browser =
-      new Browser(Browser::CreateParams(profile()->GetOriginalProfile()));
+      new Browser(Browser::CreateParams(profile()->GetOriginalProfile(), true));
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(second_browser->profile()->IsOffTheRecord());
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
index c5e3931..6f2584e 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_test.cc
@@ -292,7 +292,7 @@
     bookmarks::test::WaitForBookmarkModelToLoad(model_);
     profile_->GetPrefs()->SetBoolean(bookmarks::prefs::kShowBookmarkBar, true);
 
-    Browser::CreateParams native_params(profile_.get());
+    Browser::CreateParams native_params(profile_.get(), true);
     browser_ = chrome::CreateBrowserWithTestWindowForParams(&native_params);
 
     local_state_.reset(new ScopedTestingLocalState(
diff --git a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
index 5c7ca15..9ef7ea98 100644
--- a/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_frame_ash_browsertest.cc
@@ -39,8 +39,8 @@
   Browser::CreateParams params =
       test_app ? Browser::CreateParams::CreateForApp(
                      "test_browser_app", true /* trusted_source */, gfx::Rect(),
-                     browser()->profile())
-               : Browser::CreateParams(browser()->profile());
+                     browser()->profile(), true)
+               : Browser::CreateParams(browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
   Browser* browser = new Browser(params);
   gfx::NativeWindow window = browser->window()->GetNativeWindow();
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
index f12840b..fcf78786 100644
--- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -85,7 +85,8 @@
 // Additionally when one of the tabs is destroyed NotifyNavigationStateChanged()
 // is invoked on the other.
 IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabs) {
-  Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile()));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   chrome::AddTabAt(browser2, GURL(), -1, true);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   TestWebContentsObserver observer(
@@ -97,7 +98,8 @@
 // Same as CloseWithTabs, but activates the first tab, which is the first tab
 // BrowserView will destroy.
 IN_PROC_BROWSER_TEST_F(BrowserViewTest, CloseWithTabsStartWithActive) {
-  Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile()));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   chrome::AddTabAt(browser2, GURL(), -1, true);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   browser2->tab_strip_model()->ActivateTabAt(0, true);
diff --git a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
index 9fbc0bc..21314ed 100644
--- a/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_focus_uitest.cc
@@ -56,7 +56,8 @@
   // of Activate() is not well defined and can vary by window manager.
 #if defined(OS_WIN)
   // Open a new browser window.
-  Browser* browser2 = new Browser(Browser::CreateParams(browser()->profile()));
+  Browser* browser2 =
+      new Browser(Browser::CreateParams(browser()->profile(), true));
   ASSERT_TRUE(browser2);
   chrome::AddTabAt(browser2, GURL(), -1, true);
   browser2->window()->Show();
diff --git a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
index 9226bf3e..6dbcc82e 100644
--- a/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_interactive_uitest.cc
@@ -74,8 +74,8 @@
   Browser::CreateParams params =
       test_app ? Browser::CreateParams::CreateForApp(
                      "test_browser_app", true /* trusted_source */, gfx::Rect(),
-                     browser()->profile())
-               : Browser::CreateParams(browser()->profile());
+                     browser()->profile(), true)
+               : Browser::CreateParams(browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_DEFAULT;
 
   // Default |browser()| is not used by this test.
diff --git a/chrome/browser/ui/views/frame/browser_window_factory.cc b/chrome/browser/ui/views/frame/browser_window_factory.cc
index 1f66083..f8b524f 100644
--- a/chrome/browser/ui/views/frame/browser_window_factory.cc
+++ b/chrome/browser/ui/views/frame/browser_window_factory.cc
@@ -6,11 +6,14 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 #include "chrome/grit/chromium_strings.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/widget/widget.h"
 
 // static
-BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser) {
+BrowserWindow* BrowserWindow::CreateBrowserWindow(Browser* browser,
+                                                  bool user_gesture) {
   // Create the view and the frame. The frame will attach itself via the view
   // so we don't need to do anything with the pointer.
   BrowserView* view = new BrowserView();
@@ -18,5 +21,8 @@
   (new BrowserFrame(view))->InitBrowserFrame();
   view->GetWidget()->non_client_view()->SetAccessibleName(
       l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
+  // For now, all browser windows are true.
+  view->GetWidget()->GetNativeWindow()->SetProperty(
+      aura::client::kCreatedByUserGesture, user_gesture);
   return view;
 }
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
index 6504936..22fa553 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.cc
@@ -92,11 +92,11 @@
 CreditCardEditorViewController::CreateHeaderView() {
   std::unique_ptr<views::View> view = base::MakeUnique<views::View>();
 
-  // 9dp is required between the first and second row.
-  constexpr int kRowVerticalInset = 9;
+  // 9dp is required between the first row (label) and second row (icons).
+  constexpr int kRowVerticalSpacing = 9;
   views::BoxLayout* layout = new views::BoxLayout(
       views::BoxLayout::kVertical, payments::kPaymentRequestRowHorizontalInsets,
-      payments::kPaymentRequestRowVerticalInsets, kRowVerticalInset);
+      0, kRowVerticalSpacing);
   layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_START);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
@@ -136,12 +136,12 @@
 
 std::vector<EditorField> CreditCardEditorViewController::GetFieldDefinitions() {
   return std::vector<EditorField>{
-      {autofill::CREDIT_CARD_NAME_FULL,
-       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_NAME_ON_CARD),
-       EditorField::LengthHint::HINT_LONG, /* required= */ true},
       {autofill::CREDIT_CARD_NUMBER,
        l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_CREDIT_CARD_NUMBER),
        EditorField::LengthHint::HINT_LONG, /* required= */ true},
+      {autofill::CREDIT_CARD_NAME_FULL,
+       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_NAME_ON_CARD),
+       EditorField::LengthHint::HINT_LONG, /* required= */ true},
       {autofill::CREDIT_CARD_EXP_MONTH,
        l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EXPIRATION_MONTH),
        EditorField::LengthHint::HINT_SHORT, /* required= */ true,
@@ -190,7 +190,8 @@
 CreditCardEditorViewController::CreateValidationDelegate(
     const EditorField& field) {
   return base::MakeUnique<
-      CreditCardEditorViewController::CreditCardValidationDelegate>(field);
+      CreditCardEditorViewController::CreditCardValidationDelegate>(field,
+                                                                    this);
 }
 
 std::unique_ptr<ui::ComboboxModel>
@@ -215,8 +216,9 @@
 }
 
 CreditCardEditorViewController::CreditCardValidationDelegate::
-    CreditCardValidationDelegate(const EditorField& field)
-    : field_(field) {}
+    CreditCardValidationDelegate(const EditorField& field,
+                                 EditorViewController* controller)
+    : field_(field), controller_(controller) {}
 CreditCardEditorViewController::CreditCardValidationDelegate::
     ~CreditCardValidationDelegate() {}
 
@@ -234,12 +236,19 @@
     ValidateValue(const base::string16& value) {
   if (!value.empty()) {
     base::string16 error_message;
-    // TODO(mathp): Display |error_message| around |textfield|.
-    return autofill::IsValidForType(value, field_.type, &error_message);
+    bool is_valid =
+        autofill::IsValidForType(value, field_.type, &error_message);
+    controller_->DisplayErrorMessageForField(field_, error_message);
+    return is_valid;
   }
 
-  // TODO(mathp): Display "required" error if applicable.
-  return !field_.required;
+  bool is_required_valid = !field_.required;
+  const base::string16 displayed_message =
+      is_required_valid ? base::ASCIIToUTF16("")
+                        : l10n_util::GetStringUTF16(
+                              IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE);
+  controller_->DisplayErrorMessageForField(field_, displayed_message);
+  return is_required_valid;
 }
 
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
index 4ea2ef7..c13e8f7 100644
--- a/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/credit_card_editor_view_controller.h
@@ -35,7 +35,8 @@
  private:
   class CreditCardValidationDelegate : public ValidationDelegate {
    public:
-    explicit CreditCardValidationDelegate(const EditorField& field);
+    CreditCardValidationDelegate(const EditorField& field,
+                                 EditorViewController* controller);
     ~CreditCardValidationDelegate() override;
 
     // ValidationDelegate:
@@ -47,6 +48,8 @@
     bool ValidateValue(const base::string16& value);
 
     EditorField field_;
+    // Outlives this class.
+    EditorViewController* controller_;
 
     DISALLOW_COPY_AND_ASSIGN(CreditCardValidationDelegate);
   };
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.cc b/chrome/browser/ui/views/payments/editor_view_controller.cc
index 2b4c1efce..2d6710ab 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.cc
+++ b/chrome/browser/ui/views/payments/editor_view_controller.cc
@@ -61,14 +61,13 @@
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH);
   content_view->SetLayoutManager(layout);
+  // No insets. Child views below are responsible for their padding.
 
+  // An editor can optionally have a header view specific to it.
   content_view->AddChildView(CreateHeaderView().release());
 
-  // Create an input label/textfield for each field definition.
-  std::vector<EditorField> fields = GetFieldDefinitions();
-  for (const auto& field : fields) {
-    content_view->AddChildView(CreateInputField(field).release());
-  }
+  // The heart of the editor dialog: all the input fields with their labels.
+  content_view->AddChildView(CreateEditorView().release());
 
   return CreatePaymentView(
       CreateSheetHeaderView(
@@ -102,6 +101,16 @@
   return content_view;
 }
 
+void EditorViewController::DisplayErrorMessageForField(
+    const EditorField& field,
+    const base::string16& error_message) {
+  const auto& label_it = error_labels_.find(field);
+  DCHECK(label_it != error_labels_.end());
+  label_it->second->SetText(error_message);
+  label_it->second->SchedulePaint();
+  dialog()->Layout();
+}
+
 std::unique_ptr<views::Button> EditorViewController::CreatePrimaryButton() {
   std::unique_ptr<views::Button> button(
       views::MdTextButton::CreateSecondaryUiBlueButton(
@@ -133,31 +142,59 @@
   static_cast<ValidatingCombobox*>(sender)->OnContentsChanged();
 }
 
-std::unique_ptr<views::View> EditorViewController::CreateInputField(
-    const EditorField& field) {
-  std::unique_ptr<views::View> row = base::MakeUnique<views::View>();
+std::unique_ptr<views::View> EditorViewController::CreateEditorView() {
+  std::unique_ptr<views::View> editor_view = base::MakeUnique<views::View>();
 
-  row->SetBorder(payments::CreatePaymentRequestRowBorder());
+  views::GridLayout* editor_layout = new views::GridLayout(editor_view.get());
 
-  views::GridLayout* layout = new views::GridLayout(row.get());
+  // The editor grid layout is padded vertically from the top and bottom, and
+  // horizontally inset like other content views. The top padding needs to be
+  // added to the top padding of the first row.
+  constexpr int kEditorVerticalInset = 16;
+  editor_layout->SetInsets(
+      kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets,
+      kEditorVerticalInset, payments::kPaymentRequestRowHorizontalInsets);
 
-  // The vertical spacing for these rows is slightly different than the spacing
-  // spacing for clickable rows, so don't use kPaymentRequestRowVerticalInsets.
-  constexpr int kRowVerticalInset = 12;
-  layout->SetInsets(
-      kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets,
-      kRowVerticalInset, payments::kPaymentRequestRowHorizontalInsets);
-
-  row->SetLayoutManager(layout);
-  views::ColumnSet* columns = layout->AddColumnSet(0);
+  editor_view->SetLayoutManager(editor_layout);
+  views::ColumnSet* columns = editor_layout->AddColumnSet(0);
   columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
                      views::GridLayout::USE_PREF, 0, 0);
-  columns->AddPaddingColumn(1, 0);
-  columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER, 0,
+
+  // This is the horizontal padding between the label and the input field.
+  constexpr int kLabelInputFieldHorizontalPadding = 16;
+  columns->AddPaddingColumn(0, kLabelInputFieldHorizontalPadding);
+
+  columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
                      views::GridLayout::USE_PREF, 0, 0);
 
-  layout->StartRow(0, 0);
-  layout->AddView(new views::Label(field.label));
+  std::vector<EditorField> fields = GetFieldDefinitions();
+  for (const auto& field : fields) {
+    CreateInputField(editor_layout, field);
+  }
+
+  return editor_view;
+}
+
+// Each input field is a 4-quadrant grid.
+// +----------------------------------------------------------+
+// | Field Label           | Input field (textfield/combobox) |
+// |_______________________|__________________________________|
+// |   (empty)             | Error label                      |
+// +----------------------------------------------------------+
+void EditorViewController::CreateInputField(views::GridLayout* layout,
+                                            const EditorField& field) {
+  // This is the top padding for every row.
+  constexpr int kInputRowSpacing = 6;
+  layout->StartRowWithPadding(0, 0, 0, kInputRowSpacing);
+
+  std::unique_ptr<views::Label> label = base::MakeUnique<views::Label>(
+      field.required ? field.label + base::ASCIIToUTF16("*") : field.label);
+  // A very long label will wrap. Value picked so that left + right label
+  // padding bring the label to half-way in the dialog (~225).
+  constexpr int kMaximumLabelWidth = 192;
+  label->SetMultiLine(true);
+  label->SetMaximumWidth(kMaximumLabelWidth);
+  layout->AddView(label.release());
 
   if (field.control_type == EditorField::ControlType::TEXTFIELD) {
     ValidatingTextfield* text_field =
@@ -186,7 +223,22 @@
     NOTREACHED();
   }
 
-  return row;
+  // This is the vertical space between the input field and its error label.
+  constexpr int kInputErrorLabelPadding = 6;
+  layout->StartRowWithPadding(0, 0, 0, kInputErrorLabelPadding);
+  layout->SkipColumns(1);
+  // Error label is initially empty.
+  std::unique_ptr<views::Label> error_label =
+      base::MakeUnique<views::Label>(base::ASCIIToUTF16(""));
+  error_label->set_id(static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET) +
+                      field.type);
+  error_label->SetFontList(
+      error_label->GetDefaultFontList().DeriveWithSizeDelta(-1));
+  error_label->SetEnabledColor(error_label->GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_AlertSeverityHigh));
+  error_labels_[field] = error_label.get();
+
+  layout->AddView(error_label.release());
 }
 
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/editor_view_controller.h b/chrome/browser/ui/views/payments/editor_view_controller.h
index 3001efd..8788199 100644
--- a/chrome/browser/ui/views/payments/editor_view_controller.h
+++ b/chrome/browser/ui/views/payments/editor_view_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_EDITOR_VIEW_CONTROLLER_H_
 
 #include <memory>
+#include <tuple>
 #include <unordered_map>
 #include <vector>
 
@@ -25,6 +26,8 @@
 }
 
 namespace views {
+class GridLayout;
+class Label;
 class Textfield;
 class View;
 }  // namespace views
@@ -52,6 +55,12 @@
         required(required),
         control_type(control_type) {}
 
+  struct Compare {
+    bool operator()(const EditorField& lhs, const EditorField& rhs) const {
+      return std::tie(lhs.type, lhs.label) < std::tie(rhs.type, rhs.label);
+    }
+  };
+
   // Data type in the field.
   const autofill::ServerFieldType type;
   // Label to be shown alongside the field.
@@ -74,6 +83,8 @@
       std::unordered_map<ValidatingTextfield*, const EditorField>;
   using ComboboxMap =
       std::unordered_map<ValidatingCombobox*, const EditorField>;
+  using ErrorLabelMap =
+      std::map<const EditorField, views::Label*, EditorField::Compare>;
 
   // Does not take ownership of the arguments, which should outlive this object.
   EditorViewController(PaymentRequest* request,
@@ -96,6 +107,11 @@
   virtual std::unique_ptr<ui::ComboboxModel> GetComboboxModelForType(
       const autofill::ServerFieldType& type) = 0;
 
+  // Will display |error_message| alongside the input field represented by
+  // |field|.
+  void DisplayErrorMessageForField(const EditorField& field,
+                                   const base::string16& error_message);
+
   const ComboboxMap& comboboxes() const { return comboboxes_; }
   const TextFieldsMap& text_fields() const { return text_fields_; }
 
@@ -114,10 +130,15 @@
   // views::ComboboxListener:
   void OnPerformAction(views::Combobox* combobox) override;
 
-  // Creates a view for an input field to be added in the editor sheet. |field|
-  // is the field definition, which contains the label and the hint about
-  // the length of the input field.
-  std::unique_ptr<views::View> CreateInputField(const EditorField& field);
+  // Creates the whole editor view to go within the editor dialog. It
+  // encompasses all the input fields created by CreateInputField().
+  std::unique_ptr<views::View> CreateEditorView();
+
+  // Adds some views to |layout|, to represent an input field and its labels.
+  // |field| is the field definition, which contains the label and the hint
+  // about the length of the input field. A placeholder error label is also
+  // added (see implementation).
+  void CreateInputField(views::GridLayout* layout, const EditorField& field);
 
   // Used to remember the association between the input field UI element and the
   // original field definition. The ValidatingTextfield* and ValidatingCombobox*
@@ -125,6 +146,8 @@
   // long as the input field is visible.
   TextFieldsMap text_fields_;
   ComboboxMap comboboxes_;
+  // Tracks the relationship between a field and its error label.
+  ErrorLabelMap error_labels_;
 
   DISALLOW_COPY_AND_ASSIGN(EditorViewController);
 };
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
index 0c98740..8b29bc31 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -8,16 +8,24 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
+#include "chrome/browser/ui/views/payments/payment_request_row_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/autofill/core/browser/autofill_type.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/payments/payment_request.h"
 #include "components/strings/grit/components_strings.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/button/md_text_button.h"
-#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/vector_icons.h"
 
 namespace payments {
 
@@ -32,36 +40,129 @@
   ADD_CREDIT_CARD_BUTTON = kFirstTagValue,
 };
 
+class PaymentMethodListItem : public payments::PaymentRequestItemList::Item,
+                              public views::ButtonListener {
+ public:
+  // Does not take ownership of |card|, which  should not be null and should
+  // outlive this object.
+  explicit PaymentMethodListItem(autofill::CreditCard* card) : card_(card) {}
+  ~PaymentMethodListItem() override {}
+
+ private:
+  // payments::PaymentRequestItemList::Item:
+  std::unique_ptr<views::View> CreateItemView() override {
+    std::unique_ptr<PaymentRequestRowView> row =
+        base::MakeUnique<PaymentRequestRowView>(this);
+    views::GridLayout* layout = new views::GridLayout(row.get());
+    layout->SetInsets(
+        kPaymentRequestRowVerticalInsets, kPaymentRequestRowHorizontalInsets,
+        kPaymentRequestRowVerticalInsets, kPaymentRequestRowHorizontalInsets);
+    row->SetLayoutManager(layout);
+    views::ColumnSet* columns = layout->AddColumnSet(0);
+
+    // A column for the masked number and name on card
+    columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER, 0,
+                       views::GridLayout::USE_PREF, 0, 0);
+
+    // A padding column that resizes to take up the empty space between the
+    // leading and trailing parts.
+    columns->AddPaddingColumn(1, 0);
+
+    // A column for the checkmark when the row is selected.
+    columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
+                       0, views::GridLayout::USE_PREF, 0, 0);
+
+    // A column for the card icon
+    columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
+                       0, views::GridLayout::USE_PREF, 0, 0);
+
+    // A column for the edit button
+    columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
+                       0, views::GridLayout::USE_PREF, 0, 0);
+
+    layout->StartRow(0, 0);
+    std::unique_ptr<views::View> card_info_container =
+        base::MakeUnique<views::View>();
+    card_info_container->set_can_process_events_within_subtree(false);
+
+    std::unique_ptr<views::BoxLayout> box_layout =
+        base::MakeUnique<views::BoxLayout>(views::BoxLayout::kVertical, 0,
+                                           kPaymentRequestRowVerticalInsets, 0);
+    box_layout->set_cross_axis_alignment(
+        views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
+    card_info_container->SetLayoutManager(box_layout.release());
+
+    card_info_container->AddChildView(
+        new views::Label(card_->TypeAndLastFourDigits()));
+    card_info_container->AddChildView(new views::Label(
+        card_->GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
+                       g_browser_process->GetApplicationLocale())));
+    layout->AddView(card_info_container.release());
+
+    std::unique_ptr<views::ImageView> checkmark =
+        base::MakeUnique<views::ImageView>();
+    checkmark->set_interactive(false);
+    checkmark->SetImage(
+        gfx::CreateVectorIcon(views::kMenuCheckIcon, 0xFF609265));
+    layout->AddView(checkmark.release());
+
+    std::unique_ptr<views::ImageView> card_icon_view =
+        CreateCardIconView(card_->type());
+    card_icon_view->SetImageSize(gfx::Size(32, 20));
+    layout->AddView(card_icon_view.release());
+
+    return std::move(row);
+  }
+
+  // views::ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override {}
+
+  autofill::CreditCard* card_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentMethodListItem);
+};
+
 }  // namespace
 
 PaymentMethodViewController::PaymentMethodViewController(
     PaymentRequest* request,
     PaymentRequestDialogView* dialog)
-    : PaymentRequestSheetController(request, dialog) {}
+    : PaymentRequestSheetController(request, dialog) {
+  const std::vector<autofill::CreditCard*>& available_cards =
+      request->credit_cards();
+
+  for (autofill::CreditCard* card : available_cards) {
+    payment_method_list_.AddItem(base::MakeUnique<PaymentMethodListItem>(card));
+  }
+}
 
 PaymentMethodViewController::~PaymentMethodViewController() {}
 
 std::unique_ptr<views::View> PaymentMethodViewController::CreateView() {
-  std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>();
+  return CreatePaymentView(
+      CreateSheetHeaderView(
+          true, l10n_util::GetStringUTF16(
+                    IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME),
+          this),
+      payment_method_list_.CreateListView());
+}
 
-  views::FillLayout* layout = new views::FillLayout();
-  content_view->SetLayoutManager(layout);
+std::unique_ptr<views::View> PaymentMethodViewController::CreateExtraView() {
+  std::unique_ptr<views::View> extra_view = base::MakeUnique<views::View>();
 
-  // Create the "Add a card" button.
+  extra_view->SetLayoutManager(new views::BoxLayout(
+      views::BoxLayout::kHorizontal, kPaymentRequestRowHorizontalInsets,
+      kPaymentRequestRowVerticalInsets, kPaymentRequestButtonSpacing));
+
   views::LabelButton* button = views::MdTextButton::CreateSecondaryUiButton(
       this, l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_CREDITCARD_CAPTION));
   button->set_tag(static_cast<int>(
       PaymentMethodViewControllerTags::ADD_CREDIT_CARD_BUTTON));
   button->set_id(
       static_cast<int>(DialogViewID::PAYMENT_METHOD_ADD_CARD_BUTTON));
-  content_view->AddChildView(button);
+  extra_view->AddChildView(button);
 
-  return CreatePaymentView(CreateSheetHeaderView(
-          true,
-          l10n_util::GetStringUTF16(
-              IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME),
-          this),
-      std::move(content_view));
+  return extra_view;
 }
 
 void PaymentMethodViewController::ButtonPressed(views::Button* sender,
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.h b/chrome/browser/ui/views/payments/payment_method_view_controller.h
index 8abb216..4662d27 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_METHOD_VIEW_CONTROLLER_H_
 
 #include "base/macros.h"
+#include "chrome/browser/ui/views/payments/payment_request_item_list.h"
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
 
 namespace payments {
@@ -27,8 +28,11 @@
 
  private:
   // PaymentRequestSheetController:
+  std::unique_ptr<views::View> CreateExtraView() override;
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
+  PaymentRequestItemList payment_method_list_;
+
   DISALLOW_COPY_AND_ASSIGN(PaymentMethodViewController);
 };
 
diff --git a/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc b/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc
index 3e7b5f3..d41a30e 100644
--- a/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc
@@ -15,9 +15,11 @@
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/payments/payment_request.h"
+#include "components/strings/grit/components_strings.h"
 #include "content/public/test/browser_test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace payments {
 
@@ -130,6 +132,42 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest,
+                       EnteringNothingInARequiredField) {
+  autofill::TestAutofillClock test_clock;
+  test_clock.SetNow(kJune2017);
+
+  InvokePaymentRequestUI();
+
+  OpenPaymentMethodScreen();
+
+  OpenCreditCardEditorScreen();
+
+  // This field is required. Entering nothing and blurring out will show
+  // "Required field".
+  SetEditorTextfieldValue(base::ASCIIToUTF16(""), autofill::CREDIT_CARD_NUMBER);
+  EXPECT_TRUE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NUMBER));
+  EXPECT_EQ(
+      l10n_util::GetStringUTF16(IDS_PAYMENTS_FIELD_REQUIRED_VALIDATION_MESSAGE),
+      GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
+
+  // Set the value to something which is not a valid card number. The "invalid
+  // card number" string takes precedence over "required field"
+  SetEditorTextfieldValue(base::ASCIIToUTF16("41111111invalidcard"),
+                          autofill::CREDIT_CARD_NUMBER);
+  EXPECT_TRUE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NUMBER));
+  EXPECT_EQ(l10n_util::GetStringUTF16(
+                IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
+            GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
+
+  // Set the value to a valid number now. No more errors!
+  SetEditorTextfieldValue(base::ASCIIToUTF16("4111111111111111"),
+                          autofill::CREDIT_CARD_NUMBER);
+  EXPECT_FALSE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NUMBER));
+  EXPECT_EQ(base::ASCIIToUTF16(""),
+            GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest,
                        EnteringInvalidCardNumber) {
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(kJune2017);
@@ -144,6 +182,9 @@
                           autofill::CREDIT_CARD_NAME_FULL);
   SetEditorTextfieldValue(base::ASCIIToUTF16("41111111invalidcard"),
                           autofill::CREDIT_CARD_NUMBER);
+  EXPECT_EQ(l10n_util::GetStringUTF16(
+                IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
+            GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
   SetComboboxValue(base::ASCIIToUTF16("05"), autofill::CREDIT_CARD_EXP_MONTH);
   SetComboboxValue(base::ASCIIToUTF16("2026"),
                    autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
@@ -160,6 +201,66 @@
   EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size());
 }
 
+IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest,
+                       EnteringInvalidCardNumber_AndFixingIt) {
+  autofill::TestAutofillClock test_clock;
+  test_clock.SetNow(kJune2017);
+
+  InvokePaymentRequestUI();
+
+  OpenPaymentMethodScreen();
+
+  OpenCreditCardEditorScreen();
+
+  SetEditorTextfieldValue(base::ASCIIToUTF16("Bob Jones"),
+                          autofill::CREDIT_CARD_NAME_FULL);
+  SetEditorTextfieldValue(base::ASCIIToUTF16("41111111invalidcard"),
+                          autofill::CREDIT_CARD_NUMBER);
+  EXPECT_EQ(l10n_util::GetStringUTF16(
+                IDS_PAYMENTS_CARD_NUMBER_INVALID_VALIDATION_MESSAGE),
+            GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
+  SetComboboxValue(base::ASCIIToUTF16("05"), autofill::CREDIT_CARD_EXP_MONTH);
+  SetComboboxValue(base::ASCIIToUTF16("2026"),
+                   autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+  ClickOnDialogViewAndWait(DialogViewID::EDITOR_SAVE_BUTTON);
+
+  EXPECT_FALSE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NAME_FULL));
+  EXPECT_TRUE(IsEditorTextfieldInvalid(autofill::CREDIT_CARD_NUMBER));
+  EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH));
+  EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
+
+  // Fixing the card number.
+  SetEditorTextfieldValue(base::ASCIIToUTF16("4111111111111111"),
+                          autofill::CREDIT_CARD_NUMBER);
+  // The error message has gone.
+  EXPECT_EQ(base::ASCIIToUTF16(""),
+            GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
+
+  // Verifying the data is in the DB.
+  autofill::PersonalDataManager* personal_data_manager =
+      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  personal_data_manager->AddObserver(&personal_data_observer_);
+
+  ResetEventObserver(DialogEvent::BACK_NAVIGATION);
+
+  // Wait until the web database has been updated and the notification sent.
+  base::RunLoop data_loop;
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMessageLoop(&data_loop));
+  ClickOnDialogViewAndWait(DialogViewID::EDITOR_SAVE_BUTTON);
+  data_loop.Run();
+
+  EXPECT_EQ(1u, personal_data_manager->GetCreditCards().size());
+  autofill::CreditCard* credit_card =
+      personal_data_manager->GetCreditCards()[0];
+  EXPECT_EQ(5, credit_card->expiration_month());
+  EXPECT_EQ(2026, credit_card->expiration_year());
+  EXPECT_EQ(base::ASCIIToUTF16("1111"), credit_card->LastFourDigits());
+  EXPECT_EQ(base::ASCIIToUTF16("Bob Jones"),
+            credit_card->GetRawInfo(autofill::CREDIT_CARD_NAME_FULL));
+}
+
 IN_PROC_BROWSER_TEST_F(PaymentRequestCreditCardEditorTest, EnteringEmptyData) {
   InvokePaymentRequestUI();
 
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
index a7f0843..e3de7b51 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h
@@ -5,13 +5,15 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_DIALOG_VIEW_IDS_H_
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_DIALOG_VIEW_IDS_H_
 
+#include "components/autofill/core/browser/field_types.h"
+
 // This defines an enumeration of IDs that can uniquely identify a view within
 // the scope of the Payment Request Dialog.
 
 namespace payments {
 
 enum class DialogViewID : int {
-  VIEW_ID_NONE,
+  VIEW_ID_NONE = autofill::MAX_VALID_FIELD_TYPE,
 
   // The following are views::Button (clickable).
   PAYMENT_SHEET_CONTACT_INFO_SECTION,
@@ -26,6 +28,10 @@
   ORDER_SUMMARY_LINE_ITEM_1,
   ORDER_SUMMARY_LINE_ITEM_2,
   ORDER_SUMMARY_LINE_ITEM_3,
+
+  // Used to label the error labels with an offset, which gets added to
+  // the Autofill type value they represent (for tests).
+  ERROR_LABEL_OFFSET,
 };
 
 }  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
index 02f114e..991adf4 100644
--- a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
+++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.cc
@@ -30,6 +30,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/test/ui_controls.h"
 #include "ui/gfx/animation/test_animation_delegate.h"
+#include "ui/views/controls/label.h"
 #include "ui/views/controls/styled_label.h"
 
 namespace payments {
@@ -243,6 +244,14 @@
   return static_cast<views::StyledLabel*>(view)->text();
 }
 
+const base::string16& PaymentRequestInteractiveTestBase::GetErrorLabelForType(
+    autofill::ServerFieldType type) {
+  views::View* view = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET) + type);
+  DCHECK(view);
+  return static_cast<views::Label*>(view)->text();
+}
+
 PaymentRequestInteractiveTestBase::DialogEventObserver::DialogEventObserver(
     PaymentRequestInteractiveTestBase::DialogEvent event)
     : event_(event), seen_(false) {}
diff --git a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
index b111131d..3b718a8 100644
--- a/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
+++ b/chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h
@@ -101,6 +101,8 @@
   // Returns the text of the StyledLabel with the specific |view_id| that is a
   // child of the Payment Request dialog view.
   const base::string16& GetStyledLabelText(DialogViewID view_id);
+  // Returns the error label text associated with a given field |type|.
+  const base::string16& GetErrorLabelForType(autofill::ServerFieldType type);
 
   net::EmbeddedTestServer* https_server() { return https_server_.get(); }
 
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc
new file mode 100644
index 0000000..0cb3ce87
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -0,0 +1,49 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/payments/payment_request_item_list.h"
+
+#include "chrome/browser/ui/views/payments/payment_request_views_util.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/view.h"
+
+namespace payments {
+
+PaymentRequestItemList::Item::Item() {}
+
+PaymentRequestItemList::Item::~Item() {}
+
+views::View* PaymentRequestItemList::Item::GetItemView() {
+  if (!item_view_) {
+    item_view_ = CreateItemView();
+    item_view_->set_owned_by_client();
+  }
+
+  return item_view_.get();
+}
+
+PaymentRequestItemList::PaymentRequestItemList() {}
+
+PaymentRequestItemList::~PaymentRequestItemList() {}
+
+void PaymentRequestItemList::AddItem(
+    std::unique_ptr<PaymentRequestItemList::Item> item) {
+  items_.push_back(std::move(item));
+}
+
+std::unique_ptr<views::View> PaymentRequestItemList::CreateListView() {
+  std::unique_ptr<views::View> content_view = base::MakeUnique<views::View>();
+
+  views::BoxLayout* layout = new views::BoxLayout(
+      views::BoxLayout::kVertical, 0, kPaymentRequestRowVerticalInsets, 0);
+  content_view->SetLayoutManager(layout);
+
+  for (auto& item : items_) {
+    content_view->AddChildView(item->GetItemView());
+  }
+
+  return content_view;
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.h b/chrome/browser/ui/views/payments/payment_request_item_list.h
new file mode 100644
index 0000000..71f4c04
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.h
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_ITEM_LIST_H_
+#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_ITEM_LIST_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace views {
+class View;
+}
+
+namespace payments {
+
+// A control representing a list of selectable items in the PaymentRequest
+// dialog. These lists enforce that only one of their elements be selectable at
+// a time and that "incomplete" items (for example, a credit card with no known
+// expriration date) behave differently when selected. Most of the time, this
+// behavior is to show an editor screen.
+class PaymentRequestItemList {
+ public:
+  // Represents an item in the item list.
+  class Item {
+   public:
+    Item();
+    virtual ~Item();
+
+    // Gets the view associated with this item. It's owned by this object so
+    // that it can listen to any changes to the underlying model and update the
+    // view.
+    views::View* GetItemView();
+
+   protected:
+    // Creates and returns the view associated with this list item.
+    virtual std::unique_ptr<views::View> CreateItemView() = 0;
+
+   private:
+    std::unique_ptr<views::View> item_view_;
+
+    DISALLOW_COPY_AND_ASSIGN(Item);
+  };
+
+  PaymentRequestItemList();
+  ~PaymentRequestItemList();
+
+  // Adds an item to this list.
+  void AddItem(std::unique_ptr<Item> item);
+
+  // Creates and returns the UI representation of this list. It iterates over
+  // the items it contains, creates their associated views, and adds them to the
+  // hierarchy.
+  std::unique_ptr<views::View> CreateListView();
+
+ private:
+  std::vector<std::unique_ptr<Item>> items_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentRequestItemList);
+};
+
+}  // namespace payments
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_REQUEST_ITEM_LIST_H_
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
index 09c3050f..ae91215 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -25,6 +25,10 @@
   return nullptr;
 }
 
+std::unique_ptr<views::View> PaymentRequestSheetController::CreateExtraView() {
+  return nullptr;
+}
+
 void PaymentRequestSheetController::ButtonPressed(
     views::Button* sender, const ui::Event& event) {
   switch (static_cast<PaymentRequestCommonTags>(sender->tag())) {
@@ -86,25 +90,19 @@
   columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                      0, views::GridLayout::USE_PREF, 0, 0);
 
-  // The horizontal distance between the right/left edges of the dialog and the
-  // elements.
-  constexpr int kFooterHorizontalInset = 16;
-  // The vertical distance between footer elements and the top/bottom border
-  // (the bottom border is the edge of the dialog).
-  constexpr int kFooterVerticalInset = 16;
-  layout->SetInsets(kFooterVerticalInset, kFooterHorizontalInset,
-                    kFooterVerticalInset, kFooterHorizontalInset);
-
   layout->StartRow(0, 0);
-
-  layout->AddView(CreateLeadingFooterView().release());
+  std::unique_ptr<views::View> extra_view = CreateExtraView();
+  if (extra_view)
+    layout->AddView(extra_view.release());
+  else
+    layout->SkipColumns(1);
 
   std::unique_ptr<views::View> trailing_buttons_container =
       base::MakeUnique<views::View>();
 
-  constexpr int kButtonSpacing = 10;
   trailing_buttons_container->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kHorizontal, 0, 0, kButtonSpacing));
+      views::BoxLayout::kHorizontal, kPaymentRequestRowHorizontalInsets,
+      kPaymentRequestRowVerticalInsets, kPaymentRequestButtonSpacing));
 
   std::unique_ptr<views::Button> primary_button = CreatePrimaryButton();
   if (primary_button)
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
index d7c73e7..fbe3339 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
@@ -55,6 +55,17 @@
   // enabled state).
   virtual std::unique_ptr<views::Button> CreatePrimaryButton();
 
+  // Creates and returns the view to be displayed next to the "Pay" and "Cancel"
+  // buttons. May return an empty std::unique_ptr (nullptr) to indicate that no
+  // extra view is to be displayed.The caller takes ownership of the view but
+  // the view is guaranteed to be outlived by the controller so subclasses may
+  // retain a raw pointer to the returned view (for example to control its
+  // enabled state).
+  // +---------------------------+
+  // | EXTRA VIEW | PAY | CANCEL |
+  // +---------------------------+
+  virtual std::unique_ptr<views::View> CreateExtraView();
+
   // views::VectorIconButtonDelegate:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
@@ -71,7 +82,7 @@
   // |          CONTENT          |
   // |           VIEW            |
   // +---------------------------+
-  // |            | CANCEL | PAY | <-- footer
+  // | EXTRA VIEW | PAY | CANCEL | <-- footer
   // +---------------------------+
   std::unique_ptr<views::View> CreatePaymentView(
       std::unique_ptr<views::View> header_view,
diff --git a/chrome/browser/ui/views/payments/payment_request_views_util.h b/chrome/browser/ui/views/payments/payment_request_views_util.h
index 424771b..10e23be 100644
--- a/chrome/browser/ui/views/payments/payment_request_views_util.h
+++ b/chrome/browser/ui/views/payments/payment_request_views_util.h
@@ -25,9 +25,11 @@
 
 constexpr int kPaymentRequestRowHorizontalInsets = 16;
 constexpr int kPaymentRequestRowVerticalInsets = 8;
+
 // Extra inset relative to the header when a right edge should line up with the
 // close button's X rather than its invisible right edge.
 constexpr int kPaymentRequestRowExtraRightInset = 8;
+constexpr int kPaymentRequestButtonSpacing = 10;
 
 enum class PaymentRequestCommonTags {
   BACK_BUTTON_TAG = 0,
diff --git a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
index 21129d6..32ecb4b8 100644
--- a/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_sheet_view_controller.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/ui/views/payments/payment_request_row_view.h"
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -301,8 +300,7 @@
 // +----------------------------------------------+
 std::unique_ptr<views::Button>
 PaymentSheetViewController::CreatePaymentMethodRow() {
-  autofill::CreditCard* selected_card =
-      request()->GetCurrentlySelectedCreditCard();
+  autofill::CreditCard* selected_card = request()->selected_credit_card();
 
   std::unique_ptr<views::View> content_view;
   std::unique_ptr<views::ImageView> card_icon_view;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 1997b873..7e52331 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1733,7 +1733,7 @@
 
   Profile* profile =
       Profile::FromBrowserContext(drag_data_[0].contents->GetBrowserContext());
-  Browser::CreateParams create_params(Browser::TYPE_TABBED, profile);
+  Browser::CreateParams create_params(Browser::TYPE_TABBED, profile, true);
   create_params.initial_bounds = new_bounds;
   Browser* browser = new Browser(create_params);
   is_dragging_new_browser_ = true;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index ebfe232..244c71de 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2015,7 +2015,7 @@
                             ->GetDisplayNearestWindow(second_root)
                             .work_area();
   work_area.Inset(20, 20, 20, 60);
-  Browser::CreateParams params(browser()->profile());
+  Browser::CreateParams params(browser()->profile(), true);
   params.initial_show_state = ui::SHOW_STATE_NORMAL;
   params.initial_bounds = work_area;
   Browser* browser2 = new Browser(params);
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
index ceabb1c..4822be7 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container_browsertest.cc
@@ -153,7 +153,7 @@
           browser_actions();
 
   // Create a second browser.
-  Browser* second_browser = new Browser(Browser::CreateParams(profile()));
+  Browser* second_browser = new Browser(Browser::CreateParams(profile(), true));
   BrowserActionsContainer* second =
       BrowserView::GetBrowserViewForBrowser(second_browser)->toolbar()->
           browser_actions();
diff --git a/chrome/browser/ui/webui/chrome_web_contents_handler.cc b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
index 7f5fd4d08..419cc8b 100644
--- a/chrome/browser/ui/webui/chrome_web_contents_handler.cc
+++ b/chrome/browser/ui/webui/chrome_web_contents_handler.cc
@@ -39,8 +39,12 @@
 
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   const bool browser_created = !browser;
-  if (!browser)
-    browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+  if (!browser) {
+    // TODO(erg): OpenURLParams should pass a user_gesture flag, pass it to
+    // CreateParams, and pass the real value to nav_params below.
+    browser =
+        new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile, true));
+  }
   chrome::NavigateParams nav_params(browser, params.url, params.transition);
   nav_params.referrer = params.referrer;
   if (source && source->IsCrashed() &&
@@ -82,14 +86,16 @@
 
   Browser* browser = chrome::FindTabbedBrowser(profile, false);
   const bool browser_created = !browser;
-  if (!browser)
-    browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile));
+  if (!browser) {
+    browser = new Browser(
+        Browser::CreateParams(Browser::TYPE_TABBED, profile, user_gesture));
+  }
   chrome::NavigateParams params(browser, new_contents);
   params.source_contents = source;
   params.disposition = disposition;
   params.window_bounds = initial_rect;
   params.window_action = chrome::NavigateParams::SHOW_WINDOW;
-  params.user_gesture = true;
+  params.user_gesture = user_gesture;
   chrome::Navigate(&params);
 
   // Close the browser if chrome::Navigate created a new one.
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
index bf074962..5dcdd4fc 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.cc
@@ -39,9 +39,9 @@
 AppLaunchSplashScreenHandler::AppLaunchSplashScreenHandler(
     const scoped_refptr<NetworkStateInformer>& network_state_informer,
     ErrorScreen* error_screen)
-    : BaseScreenHandler(kJsScreenPath),
-      network_state_informer_(network_state_informer),
+    : network_state_informer_(network_state_informer),
       error_screen_(error_screen) {
+  set_call_js_prefix(kJsScreenPath);
   network_state_informer_->AddObserver(this);
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
index eca3ab8..6533113 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.cc
@@ -24,8 +24,9 @@
 
 namespace chromeos {
 
-ArcKioskSplashScreenHandler::ArcKioskSplashScreenHandler()
-    : BaseScreenHandler(kJsScreenPath) {}
+ArcKioskSplashScreenHandler::ArcKioskSplashScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
+}
 
 ArcKioskSplashScreenHandler::~ArcKioskSplashScreenHandler() = default;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
index 7e0c9a7..0c149ae 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.cc
@@ -26,8 +26,8 @@
 
 namespace chromeos {
 
-ArcTermsOfServiceScreenHandler::ArcTermsOfServiceScreenHandler()
-    : BaseScreenHandler(kJsScreenPath) {
+ArcTermsOfServiceScreenHandler::ArcTermsOfServiceScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 ArcTermsOfServiceScreenHandler::~ArcTermsOfServiceScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.cc
index e100f8e..9bcf4f2 100644
--- a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.cc
@@ -16,10 +16,8 @@
 
 namespace chromeos {
 
-AutoEnrollmentCheckScreenHandler::AutoEnrollmentCheckScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false) {
+AutoEnrollmentCheckScreenHandler::AutoEnrollmentCheckScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 AutoEnrollmentCheckScreenHandler::~AutoEnrollmentCheckScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
index 4517e1b..db480ba 100644
--- a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
@@ -33,10 +33,10 @@
   void RegisterMessages() override;
 
  private:
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Keeps whether screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentCheckScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
index 52b76a7..db8cd34 100644
--- a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.cc
@@ -19,16 +19,7 @@
 const char kMethodContextChanged[] = "contextChanged";
 }  // namespace
 
-BaseScreenHandler::BaseScreenHandler()
-    : page_is_ready_(false), base_screen_(nullptr) {
-}
-
-BaseScreenHandler::BaseScreenHandler(const std::string& js_screen_path)
-    : page_is_ready_(false),
-      base_screen_(nullptr),
-      js_screen_path_prefix_(js_screen_path + ".") {
-  CHECK(!js_screen_path.empty());
-}
+BaseScreenHandler::BaseScreenHandler() = default;
 
 BaseScreenHandler::~BaseScreenHandler() {
   if (base_screen_)
diff --git a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
index 4c485f58..2e46198 100644
--- a/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/base_screen_handler.h
@@ -36,12 +36,7 @@
 class BaseScreenHandler : public content::WebUIMessageHandler,
                           public ModelViewChannel {
  public:
-  // C-tor used when JS screen prefix is not needed.
   BaseScreenHandler();
-
-  // C-tor used when JS screen prefix is needed.
-  explicit BaseScreenHandler(const std::string& js_screen_path);
-
   ~BaseScreenHandler() override;
 
   // Gets localized strings to be used on the page.
@@ -65,6 +60,13 @@
     return async_assets_load_id_;
   }
 
+  // Set the prefix used when running CallJs with a method. For example,
+  //    set_call_js_prefix("Oobe")
+  //    CallJs("lock") -> Invokes JS global named "Oobe.lock"
+  void set_call_js_prefix(const std::string& prefix) {
+    js_screen_path_prefix_ = prefix + ".";
+  }
+
  protected:
   // All subclasses should implement this method to provide localized values.
   virtual void DeclareLocalizedValues(
@@ -178,9 +180,9 @@
   void HandleContextChanged(const base::DictionaryValue* diff);
 
   // Keeps whether page is ready.
-  bool page_is_ready_;
+  bool page_is_ready_ = false;
 
-  BaseScreen* base_screen_;
+  BaseScreen* base_screen_ = nullptr;
 
   // Full name of the corresponding JS screen object. Can be empty, if
   // there are no corresponding screen object or several different
diff --git a/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.cc
index 43c3b89c..4446044 100644
--- a/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.cc
@@ -30,8 +30,8 @@
 
 }  // namespace
 
-ControllerPairingScreenHandler::ControllerPairingScreenHandler()
-    : BaseScreenHandler(kJsScreenPath), delegate_(NULL), show_on_init_(false) {
+ControllerPairingScreenHandler::ControllerPairingScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 ControllerPairingScreenHandler::~ControllerPairingScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.h
index ea1038ee..a2c3e8f 100644
--- a/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/controller_pairing_screen_handler.h
@@ -36,8 +36,8 @@
   void OnContextChanged(const base::DictionaryValue& diff) override;
   content::BrowserContext* GetBrowserContext() override;
 
-  ControllerPairingScreenActor::Delegate* delegate_;
-  bool show_on_init_;
+  ControllerPairingScreenActor::Delegate* delegate_ = nullptr;
+  bool show_on_init_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(ControllerPairingScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
index 6f5f7d2..0d6cac5 100644
--- a/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/core_oobe_handler.cc
@@ -56,9 +56,8 @@
 // Note that show_oobe_ui_ defaults to false because WizardController assumes
 // OOBE UI is not visible by default.
 CoreOobeHandler::CoreOobeHandler(OobeUI* oobe_ui)
-    : BaseScreenHandler(kJsScreenPath),
-      oobe_ui_(oobe_ui),
-      version_info_updater_(this) {
+    : oobe_ui_(oobe_ui), version_info_updater_(this) {
+  set_call_js_prefix(kJsScreenPath);
   if (!chrome::IsRunningInMash()) {
     AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
     CHECK(accessibility_manager);
diff --git a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc
index 2bd4bf4..2062b454 100644
--- a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.cc
@@ -17,10 +17,8 @@
 
 namespace chromeos {
 
-DeviceDisabledScreenHandler::DeviceDisabledScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false) {
+DeviceDisabledScreenHandler::DeviceDisabledScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 DeviceDisabledScreenHandler::~DeviceDisabledScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
index f69d0af..5aebbed 100644
--- a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
@@ -33,10 +33,10 @@
   // WebUIMessageHandler:
   void RegisterMessages() override;
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Indicates whether the screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceDisabledScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
index 6b37f0aa..da2f76f 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.cc
@@ -35,10 +35,8 @@
 namespace chromeos {
 
 EnableDebuggingScreenHandler::EnableDebuggingScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false),
-      weak_ptr_factory_(this) {
+    : weak_ptr_factory_(this) {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 EnableDebuggingScreenHandler::~EnableDebuggingScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
index da45fc5f..51a87da 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
@@ -76,10 +76,10 @@
   // Updates UI state.
   void UpdateUIState(UIState state);
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Keeps whether screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   base::WeakPtrFactory<EnableDebuggingScreenHandler> weak_ptr_factory_;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
index 17e6e0e..00ae028 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc
@@ -123,11 +123,11 @@
 EnrollmentScreenHandler::EnrollmentScreenHandler(
     const scoped_refptr<NetworkStateInformer>& network_state_informer,
     ErrorScreen* error_screen)
-    : BaseScreenHandler(kJsScreenPath),
-      network_state_informer_(network_state_informer),
+    : network_state_informer_(network_state_informer),
       error_screen_(error_screen),
       histogram_helper_(new ErrorScreensHistogramHelper("Enrollment")),
       weak_ptr_factory_(this) {
+  set_call_js_prefix(kJsScreenPath);
   set_async_assets_load_id(
       GetOobeScreenName(OobeScreen::SCREEN_OOBE_ENROLLMENT));
   DCHECK(network_state_informer_.get());
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
index f8b7e674..5f0d589 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.cc
@@ -21,9 +21,8 @@
 
 namespace chromeos {
 
-ErrorScreenHandler::ErrorScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      weak_ptr_factory_(this) {
+ErrorScreenHandler::ErrorScreenHandler() : weak_ptr_factory_(this) {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 ErrorScreenHandler::~ErrorScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
index 7f15ab01..d8bcff6 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.cc
@@ -83,8 +83,8 @@
 namespace chromeos {
 
 EulaScreenHandler::EulaScreenHandler(CoreOobeActor* core_oobe_actor)
-    : BaseScreenHandler(kJsScreenPath),
-      core_oobe_actor_(core_oobe_actor) {
+    : core_oobe_actor_(core_oobe_actor) {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 EulaScreenHandler::~EulaScreenHandler() {
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 2304809..4fadb2b 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -228,11 +228,11 @@
 GaiaScreenHandler::GaiaScreenHandler(
     CoreOobeActor* core_oobe_actor,
     const scoped_refptr<NetworkStateInformer>& network_state_informer)
-    : BaseScreenHandler(kJsScreenPath),
-      network_state_informer_(network_state_informer),
+    : network_state_informer_(network_state_informer),
       core_oobe_actor_(core_oobe_actor),
       weak_factory_(this) {
   DCHECK(network_state_informer_.get());
+  set_call_js_prefix(kJsScreenPath);
 }
 
 GaiaScreenHandler::~GaiaScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
index 66faf84d..b6d5803 100644
--- a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.cc
@@ -30,7 +30,9 @@
 
 HIDDetectionScreenHandler::HIDDetectionScreenHandler(
     CoreOobeActor* core_oobe_actor)
-    : BaseScreenHandler(kJsScreenPath), core_oobe_actor_(core_oobe_actor) {}
+    : core_oobe_actor_(core_oobe_actor) {
+  set_call_js_prefix(kJsScreenPath);
+}
 
 HIDDetectionScreenHandler::~HIDDetectionScreenHandler() {
   if (screen_)
diff --git a/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.cc
index 30acb8e..420d76a 100644
--- a/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.cc
@@ -26,11 +26,8 @@
 
 }  // namespace
 
-HostPairingScreenHandler::HostPairingScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false),
-      js_context_ready_(false) {
+HostPairingScreenHandler::HostPairingScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 HostPairingScreenHandler::~HostPairingScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.h
index cfe7d111..26df3e4 100644
--- a/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/host_pairing_screen_handler.h
@@ -35,9 +35,9 @@
   void SetDelegate(Delegate* delegate) override;
   void OnContextChanged(const base::DictionaryValue& diff) override;
 
-  HostPairingScreenActor::Delegate* delegate_;
-  bool show_on_init_;
-  bool js_context_ready_;
+  HostPairingScreenActor::Delegate* delegate_ = nullptr;
+  bool show_on_init_ = false;
+  bool js_context_ready_ = false;
 
   // Caches context changes while JS part is not ready to receive messages.
   ::login::ScreenContext context_cache_;
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
index 409dc18..d71d260 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.cc
@@ -32,11 +32,8 @@
 
 namespace chromeos {
 
-KioskAutolaunchScreenHandler::KioskAutolaunchScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false),
-      is_visible_(false) {
+KioskAutolaunchScreenHandler::KioskAutolaunchScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
   KioskAppManager::Get()->AddObserver(this);
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
index 01be4a23..3f1d51fd 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
@@ -47,11 +47,11 @@
   void HandleOnConfirm();
   void HandleOnVisible();
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Keeps whether screen should be shown right after initialization.
-  bool show_on_init_;
-  bool is_visible_;
+  bool show_on_init_ = false;
+  bool is_visible_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(KioskAutolaunchScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
index 81cbff3..2046082 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.cc
@@ -24,12 +24,8 @@
 
 namespace chromeos {
 
-KioskEnableScreenHandler::KioskEnableScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false),
-      is_configurable_(false),
-      weak_ptr_factory_(this) {
+KioskEnableScreenHandler::KioskEnableScreenHandler() : weak_ptr_factory_(this) {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 KioskEnableScreenHandler::~KioskEnableScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
index 5498785..9d1b9bb 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
@@ -45,13 +45,13 @@
   void OnGetConsumerKioskAutoLaunchStatus(
       KioskAppManager::ConsumerKioskAutoLaunchStatus status);
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Keeps whether screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   // True if machine's consumer kiosk mode is in a configurable state.
-  bool is_configurable_;
+  bool is_configurable_ = false;
 
   base::WeakPtrFactory<KioskEnableScreenHandler> weak_ptr_factory_;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/network_dropdown_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_dropdown_handler.cc
index 42b46c7c..fdfbf203 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_dropdown_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_dropdown_handler.cc
@@ -30,8 +30,8 @@
 
 namespace chromeos {
 
-NetworkDropdownHandler::NetworkDropdownHandler()
-    : BaseScreenHandler(kJsScreenPath) {
+NetworkDropdownHandler::NetworkDropdownHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 NetworkDropdownHandler::~NetworkDropdownHandler() {
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 5d6e079..79f1ad63 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -55,7 +55,8 @@
 // NetworkScreenHandler, public: -----------------------------------------------
 
 NetworkScreenHandler::NetworkScreenHandler(CoreOobeActor* core_oobe_actor)
-    : BaseScreenHandler(kJsScreenPath), core_oobe_actor_(core_oobe_actor) {
+    : core_oobe_actor_(core_oobe_actor) {
+  set_call_js_prefix(kJsScreenPath);
   DCHECK(core_oobe_actor_);
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
index bbd56c3..3906059 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.cc
@@ -27,7 +27,9 @@
 
 namespace chromeos {
 
-ResetScreenHandler::ResetScreenHandler() : BaseScreenHandler(kJsScreenPath) {}
+ResetScreenHandler::ResetScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
+}
 
 ResetScreenHandler::~ResetScreenHandler() {
   if (screen_)
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 d8b2768..fb5dfbd4 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
@@ -36,9 +36,8 @@
 
 namespace chromeos {
 
-SupervisedUserCreationScreenHandler::SupervisedUserCreationScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL) {
+SupervisedUserCreationScreenHandler::SupervisedUserCreationScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   media::SoundsManager* manager = media::SoundsManager::Get();
   manager->Initialize(SOUND_OBJECT_DELETE,
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 313eb3f..345541c 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
@@ -132,7 +132,7 @@
 
   void UpdateText(const std::string& element_id, const base::string16& text);
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(SupervisedUserCreationScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
index 79f2b10..ef316de01 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.cc
@@ -38,11 +38,8 @@
 
 TermsOfServiceScreenHandler::TermsOfServiceScreenHandler(
     CoreOobeActor* core_oobe_actor)
-    : BaseScreenHandler(kJsScreenPath),
-      screen_(NULL),
-      core_oobe_actor_(core_oobe_actor),
-      show_on_init_(false),
-      load_error_(false) {
+    : core_oobe_actor_(core_oobe_actor) {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 TermsOfServiceScreenHandler::~TermsOfServiceScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
index adf55e37..88d1b47 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
@@ -68,18 +68,18 @@
   // and continue" button.
   void HandleAccept();
 
-  TermsOfServiceScreenHandler::Delegate* screen_;
+  TermsOfServiceScreenHandler::Delegate* screen_ = nullptr;
 
-  CoreOobeActor* core_oobe_actor_;
+  CoreOobeActor* core_oobe_actor_ = nullptr;
 
   // Whether the screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   // The domain name whose Terms of Service are being shown.
   std::string domain_;
 
   // Set to |true| when the download of the Terms of Service fails.
-  bool load_error_;
+  bool load_error_ = false;
 
   // Set to the Terms of Service when the download is successful.
   std::string terms_of_service_;
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
index 955022e4..24be021c 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.cc
@@ -21,7 +21,9 @@
 
 namespace chromeos {
 
-UpdateScreenHandler::UpdateScreenHandler() : BaseScreenHandler(kJsScreenPath) {}
+UpdateScreenHandler::UpdateScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
+}
 
 UpdateScreenHandler::~UpdateScreenHandler() {
   if (screen_)
diff --git a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
index ad0dc0e75..c1d4841 100644
--- a/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/user_image_screen_handler.cc
@@ -38,8 +38,8 @@
 
 namespace chromeos {
 
-UserImageScreenHandler::UserImageScreenHandler()
-    : BaseScreenHandler(kJsScreenPath) {
+UserImageScreenHandler::UserImageScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
   media::SoundsManager* manager = media::SoundsManager::Get();
   manager->Initialize(SOUND_OBJECT_DELETE,
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
index 38d82a1..7767ab9c 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.cc
@@ -16,10 +16,8 @@
 
 namespace chromeos {
 
-WrongHWIDScreenHandler::WrongHWIDScreenHandler()
-    : BaseScreenHandler(kJsScreenPath),
-      delegate_(NULL),
-      show_on_init_(false) {
+WrongHWIDScreenHandler::WrongHWIDScreenHandler() {
+  set_call_js_prefix(kJsScreenPath);
 }
 
 WrongHWIDScreenHandler::~WrongHWIDScreenHandler() {
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
index 0865850..6dfdae54 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
@@ -37,10 +37,10 @@
   // JS messages handlers.
   void HandleOnSkip();
 
-  Delegate* delegate_;
+  Delegate* delegate_ = nullptr;
 
   // Keeps whether screen should be shown right after initialization.
-  bool show_on_init_;
+  bool show_on_init_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(WrongHWIDScreenHandler);
 };
diff --git a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
index db2adde..88c7485 100644
--- a/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_loader_handler.cc
@@ -14,12 +14,11 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "chrome/browser/extensions/path_util.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/generated_resources.h"
-#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -160,15 +159,13 @@
 
   // This will read the manifest and call AddFailure with the read manifest
   // contents.
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(),
+  base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE,
+      base::TaskTraits().MayBlock().WithPriority(
+          base::TaskPriority::USER_BLOCKING),
       base::Bind(&ReadFileToString, file_path.Append(kManifestFilename)),
       base::Bind(&ExtensionLoaderHandler::AddFailure,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 file_path,
-                 error,
-                 line));
+                 weak_ptr_factory_.GetWeakPtr(), file_path, error, line));
 }
 
 void ExtensionLoaderHandler::DidStartNavigation(
diff --git a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
index 2081f93..9971504 100644
--- a/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/local_discovery/local_discovery_ui_browsertest.cc
@@ -447,6 +447,7 @@
     command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
                                     chrome::kTestUserProfileDir);
 #endif
+    command_line->AppendSwitch(switches::kDisableDeviceDiscoveryNotifications);
     WebUIBrowserTest::SetUpCommandLine(command_line);
   }
 
@@ -516,7 +517,7 @@
 }
 
 // Flaky: http://crbug.com/660669.
-IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, DISABLED_RegisterTest) {
+IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, RegisterTest) {
   TestMessageLoopCondition condition_token_claimed;
 
   ui_test_utils::NavigateToURL(browser(), GURL(
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.cc b/chrome/browser/ui/webui/options/autofill_options_handler.cc
index 8b8044f..8241b38 100644
--- a/chrome/browser/ui/webui/options/autofill_options_handler.cc
+++ b/chrome/browser/ui/webui/options/autofill_options_handler.cc
@@ -25,13 +25,13 @@
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/autofill/country_combobox_model.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -168,9 +168,11 @@
 
 // Sets data related to the country <select>.
 void SetCountryData(const PersonalDataManager& manager,
-                    base::DictionaryValue* localized_strings) {
+                    base::DictionaryValue* localized_strings,
+                    const std::string& ui_language_code) {
   autofill::CountryComboboxModel model;
-  model.SetCountries(manager, base::Callback<bool(const std::string&)>());
+  model.SetCountries(manager, base::Callback<bool(const std::string&)>(),
+                     ui_language_code);
   const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries =
       model.countries();
   localized_strings->SetString("defaultCountryCode",
@@ -192,8 +194,7 @@
   std::unique_ptr<base::ListValue> default_country_components(
       new base::ListValue);
   std::string default_country_language_code;
-  GetAddressComponents(countries.front()->country_code(),
-                       g_browser_process->GetApplicationLocale(),
+  GetAddressComponents(countries.front()->country_code(), ui_language_code,
                        default_country_components.get(),
                        &default_country_language_code);
   localized_strings->Set("autofillDefaultCountryComponents",
@@ -312,7 +313,8 @@
       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_PHONE));
   localized_strings->SetString("autofillEmailLabel",
       l10n_util::GetStringUTF16(IDS_AUTOFILL_FIELD_LABEL_EMAIL));
-  SetCountryData(*personal_data_, localized_strings);
+  SetCountryData(*personal_data_, localized_strings,
+                 g_browser_process->GetApplicationLocale());
 }
 
 void AutofillOptionsHandler::SetCreditCardOverlayStrings(
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler.cc b/chrome/browser/ui/webui/options/sync_setup_handler.cc
index d9f8054..c24a5fe 100644
--- a/chrome/browser/ui/webui/options/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/options/sync_setup_handler.cc
@@ -363,8 +363,8 @@
   bool force_new_tab = false;
   if (!browser) {
     // Settings is not displayed in a browser window. Open a new window.
-    browser =
-        new Browser(Browser::CreateParams(Browser::TYPE_TABBED, GetProfile()));
+    browser = new Browser(
+        Browser::CreateParams(Browser::TYPE_TABBED, GetProfile(), true));
     force_new_tab = true;
   }
 
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index b86c221e..823dd2b 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -269,8 +269,8 @@
   bool force_new_tab = false;
   if (!browser) {
     // Settings is not displayed in a browser window. Open a new window.
-    browser =
-        new Browser(Browser::CreateParams(Browser::TYPE_TABBED, profile_));
+    browser = new Browser(
+        Browser::CreateParams(Browser::TYPE_TABBED, profile_, true));
     force_new_tab = true;
   }
 
diff --git a/chrome/browser/ui/webui/signin/signin_supervised_user_import_handler.cc b/chrome/browser/ui/webui/signin/signin_supervised_user_import_handler.cc
index 5cb3448..1a53687 100644
--- a/chrome/browser/ui/webui/signin/signin_supervised_user_import_handler.cc
+++ b/chrome/browser/ui/webui/signin/signin_supervised_user_import_handler.cc
@@ -125,8 +125,8 @@
     // it doesn't exist.
     Browser* browser = chrome::FindLastActiveWithProfile(last_used_profile);
     if (!browser)
-      browser = new Browser(Browser::CreateParams(Browser::TYPE_TABBED,
-                                                  last_used_profile));
+      browser = new Browser(
+          Browser::CreateParams(Browser::TYPE_TABBED, last_used_profile, true));
     browser->OpenURL(params);
   }
 }
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index ed672f45..09f8b85 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -416,25 +416,25 @@
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
   // Creating a popup handler here to make sure it does not interfere with the
   // existing windows.
-  Browser::CreateParams native_params(profile.get());
+  Browser::CreateParams native_params(profile.get(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
 
   // Creating a popup handler here to make sure it does not interfere with the
   // existing windows.
-  Browser::CreateParams params2(profile.get());
+  Browser::CreateParams params2(profile.get(), true);
   std::unique_ptr<Browser> browser2(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(16, 32, 640, 320), &params2));
   BrowserWindow* browser_window = browser2->window();
 
   // Creating a popup to make sure it does not interfere with the positioning.
-  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get());
+  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get(), true);
   std::unique_ptr<Browser> browser_popup(
       CreateTestBrowser(CreateTestWindowInShellWithId(1),
                         gfx::Rect(16, 32, 128, 256), &params_popup));
 
   // Creating a panel to make sure it does not interfere with the positioning.
-  Browser::CreateParams params_panel(Browser::TYPE_POPUP, profile.get());
+  Browser::CreateParams params_panel(Browser::TYPE_POPUP, profile.get(), true);
   std::unique_ptr<Browser> browser_panel(
       CreateTestBrowser(CreateTestWindowInShellWithId(2),
                         gfx::Rect(32, 48, 256, 512), &params_panel));
@@ -482,7 +482,7 @@
 TEST_F(WindowSizerAshTest, PlaceNewBrowserWindowOnEmptyDesktop) {
   // Create a browser to pass into the GetWindowBoundsAndShowState function.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
-  Browser::CreateParams native_params(profile.get());
+  Browser::CreateParams native_params(profile.get(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
 
@@ -567,7 +567,7 @@
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
 
   // Create browser windows that are used as reference.
-  Browser::CreateParams params(profile.get());
+  Browser::CreateParams params(profile.get(), true);
   std::unique_ptr<Browser> browser(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(10, 10, 200, 200), &params));
   BrowserWindow* browser_window = browser->window();
@@ -575,7 +575,7 @@
   browser_window->Show();
   EXPECT_EQ(native_window->GetRootWindow(), ash::Shell::GetTargetRootWindow());
 
-  Browser::CreateParams another_params(profile.get());
+  Browser::CreateParams another_params(profile.get(), true);
   std::unique_ptr<Browser> another_browser(
       CreateTestBrowser(CreateTestWindowInShellWithId(1),
                         gfx::Rect(400, 10, 300, 300), &another_params));
@@ -585,7 +585,7 @@
   another_browser_window->Show();
 
   // Creating a new window to verify the new placement.
-  Browser::CreateParams new_params(profile.get());
+  Browser::CreateParams new_params(profile.get(), true);
   std::unique_ptr<Browser> new_browser(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(), &new_params));
 
@@ -654,12 +654,12 @@
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
 
   // Creating a browser & window to play with.
-  Browser::CreateParams params(Browser::TYPE_TABBED, profile.get());
+  Browser::CreateParams params(Browser::TYPE_TABBED, profile.get(), true);
   std::unique_ptr<Browser> browser(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(16, 32, 640, 320), &params));
 
   // Create also a popup browser since that behaves different.
-  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get());
+  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get(), true);
   std::unique_ptr<Browser> browser_popup(
       CreateTestBrowser(CreateTestWindowInShellWithId(1),
                         gfx::Rect(16, 32, 640, 320), &params_popup));
@@ -691,7 +691,7 @@
   // Now create a top level window and check again for both. Only the tabbed
   // window should follow the top level window's state.
   // Creating a browser & window to play with.
-  Browser::CreateParams params2(Browser::TYPE_TABBED, profile.get());
+  Browser::CreateParams params2(Browser::TYPE_TABBED, profile.get(), true);
   std::unique_ptr<Browser> browser2(CreateTestBrowser(
       CreateTestWindowInShellWithId(3), gfx::Rect(16, 32, 640, 320), &params2));
 
@@ -727,13 +727,13 @@
   // Creating a browser & window to play with.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
 
-  Browser::CreateParams params(Browser::TYPE_TABBED, profile.get());
+  Browser::CreateParams params(Browser::TYPE_TABBED, profile.get(), true);
   std::unique_ptr<Browser> browser(CreateTestBrowser(
       CreateTestWindowInShellWithId(0), gfx::Rect(16, 32, 640, 320), &params));
 
   // Create also a popup browser since that behaves slightly different for
   // defaults.
-  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get());
+  Browser::CreateParams params_popup(Browser::TYPE_POPUP, profile.get(), true);
   std::unique_ptr<Browser> browser_popup(
       CreateTestBrowser(CreateTestWindowInShellWithId(1),
                         gfx::Rect(16, 32, 128, 256), &params_popup));
@@ -784,7 +784,7 @@
 TEST_F(WindowSizerAshTest, DefaultStateBecomesMaximized) {
   // Create a browser to pass into the GetWindowBounds function.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
-  Browser::CreateParams native_params(profile.get());
+  Browser::CreateParams native_params(profile.get(), true);
   std::unique_ptr<Browser> browser(
       chrome::CreateBrowserWithTestWindowForParams(&native_params));
 
@@ -850,7 +850,7 @@
 TEST_F(WindowSizerAshTest, TrustedPopupBehavior) {
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
   Browser::CreateParams trusted_popup_create_params(Browser::TYPE_POPUP,
-                                                    profile.get());
+                                                    profile.get(), true);
   trusted_popup_create_params.trusted_source = true;
 
   std::unique_ptr<Browser> trusted_popup(CreateTestBrowser(
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 937dee5..f370fd87 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -50,8 +50,6 @@
 #endif
 
 #if defined(OS_WIN)
-const char kHungAudioThreadDetails[] = "hung-audio-thread-details";
-
 const char kHungRendererOutstandingAckCount[] = "hung-outstanding-acks";
 const char kHungRendererOutstandingEventType[] = "hung-outstanding-event-type";
 const char kHungRendererLastEventType[] = "hung-last-event-type";
@@ -177,9 +175,6 @@
     { kViewCount, kSmallSize },
 
     // media/:
-#if defined(OS_WIN)
-    { kHungAudioThreadDetails, kSmallSize },
-#endif
     { kZeroEncodeDetails, kSmallSize },
 
     // gin/:
diff --git a/chrome/common/extensions/api/chromeos_info_private.json b/chrome/common/extensions/api/chromeos_info_private.json
index 55d86a71..c084542 100644
--- a/chrome/common/extensions/api/chromeos_info_private.json
+++ b/chrome/common/extensions/api/chromeos_info_private.json
@@ -40,6 +40,12 @@
         "type": "string",
         "enum": ["not available", "available", "enabled"],
         "description": "Status of the play store. Note: 'available' means that the device supports the playstore but it is not enabled."
+      },
+      {
+        "id": "ManagedDeviceStatus",
+        "type": "string",
+        "enum": ["managed", "not managed"],
+        "description": "Status of enterprise enrollment."
       }
     ],
     "functions": [
@@ -71,6 +77,7 @@
                   "isOwner" : {"type": "boolean", "optional": true, "description": "True if current logged in user is device owner"},
                   "sessionType": {"$ref": "SessionType", "optional": true},
                   "playStoreStatus": {"$ref": "PlayStoreStatus", "optional": true},
+                  "managedDeviceStatus": {"$ref": "ManagedDeviceStatus", "optional": true},
                   "clientId" : {"type": "string", "optional": true, "description": "Device client id"},
                   "timezone" : {"type": "string", "optional": true, "description": "Timezone"},
                   "a11yLargeCursorEnabled" : {"type": "boolean", "optional": true, "description": "If true, ChromeOS is showing enlarged cursor."},
diff --git a/chrome/common/extensions/api/commands/commands_handler.cc b/chrome/common/extensions/api/commands/commands_handler.cc
index 818e6041..b9c7d794 100644
--- a/chrome/common/extensions/api/commands/commands_handler.cc
+++ b/chrome/common/extensions/api/commands/commands_handler.cc
@@ -64,8 +64,7 @@
   if (!extension->manifest()->HasKey(keys::kCommands)) {
     std::unique_ptr<CommandsInfo> commands_info(new CommandsInfo);
     MaybeSetBrowserActionDefault(extension, commands_info.get());
-    extension->SetManifestData(keys::kCommands,
-                               commands_info.release());
+    extension->SetManifestData(keys::kCommands, std::move(commands_info));
     return true;
   }
 
@@ -126,8 +125,7 @@
 
   MaybeSetBrowserActionDefault(extension, commands_info.get());
 
-  extension->SetManifestData(keys::kCommands,
-                             commands_info.release());
+  extension->SetManifestData(keys::kCommands, std::move(commands_info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/extension_action/action_info.cc b/chrome/common/extensions/api/extension_action/action_info.cc
index 767eb6e..aa8376b0 100644
--- a/chrome/common/extensions/api/extension_action/action_info.cc
+++ b/chrome/common/extensions/api/extension_action/action_info.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
 #include "extensions/common/constants.h"
@@ -198,19 +199,20 @@
 // static
 void ActionInfo::SetBrowserActionInfo(Extension* extension, ActionInfo* info) {
   extension->SetManifestData(keys::kBrowserAction,
-                             new ActionInfoData(info));
+                             base::MakeUnique<ActionInfoData>(info));
 }
 
 // static
 void ActionInfo::SetPageActionInfo(Extension* extension, ActionInfo* info) {
   extension->SetManifestData(keys::kPageAction,
-                             new ActionInfoData(info));
+                             base::MakeUnique<ActionInfoData>(info));
 }
 
 // static
 void ActionInfo::SetSystemIndicatorInfo(Extension* extension,
                                         ActionInfo* info) {
-  extension->SetManifestData(keys::kSystemIndicator, new ActionInfoData(info));
+  extension->SetManifestData(keys::kSystemIndicator,
+                             base::MakeUnique<ActionInfoData>(info));
 }
 
 // static
diff --git a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
index d41a9ee..c30b117a 100644
--- a/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
+++ b/chrome/common/extensions/api/file_browser_handlers/file_browser_handler.cc
@@ -299,7 +299,7 @@
     return false;  // Failed to parse file browser actions definition.
   }
 
-  extension->SetManifestData(keys::kFileBrowserHandlers, info.release());
+  extension->SetManifestData(keys::kFileBrowserHandlers, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.cc b/chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.cc
index ce676d40..2416f9975 100644
--- a/chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.cc
+++ b/chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.cc
@@ -113,7 +113,7 @@
           source));
 
   extension->SetManifestData(manifest_keys::kFileSystemProviderCapabilities,
-                             capabilities.release());
+                             std::move(capabilities));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/input_ime/input_components_handler.cc b/chrome/common/extensions/api/input_ime/input_components_handler.cc
index 036a253..89b4d61f 100644
--- a/chrome/common/extensions/api/input_ime/input_components_handler.cc
+++ b/chrome/common/extensions/api/input_ime/input_components_handler.cc
@@ -232,7 +232,7 @@
     info->input_components.back().options_page_url = options_page_url;
     info->input_components.back().input_view_url = input_view_url;
   }
-  extension->SetManifestData(keys::kInputComponents, info.release());
+  extension->SetManifestData(keys::kInputComponents, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/omnibox/omnibox_handler.cc b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
index 872ea125..f0d392d 100644
--- a/chrome/common/extensions/api/omnibox/omnibox_handler.cc
+++ b/chrome/common/extensions/api/omnibox/omnibox_handler.cc
@@ -45,7 +45,7 @@
     *error = base::ASCIIToUTF16(manifest_errors::kInvalidOmniboxKeyword);
     return false;
   }
-  extension->SetManifestData(manifest_keys::kOmnibox, info.release());
+  extension->SetManifestData(manifest_keys::kOmnibox, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/plugins/plugins_handler.cc b/chrome/common/extensions/api/plugins/plugins_handler.cc
index f88cbe9..dedf995 100644
--- a/chrome/common/extensions/api/plugins/plugins_handler.cc
+++ b/chrome/common/extensions/api/plugins/plugins_handler.cc
@@ -113,7 +113,7 @@
   }
 
   if (!plugins_data->plugins.empty()) {
-    extension->SetManifestData(keys::kPlugins, plugins_data.release());
+    extension->SetManifestData(keys::kPlugins, std::move(plugins_data));
     PermissionsParser::AddAPIPermission(extension, APIPermission::kPlugin);
   }
 
diff --git a/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc b/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
index ccc891be2..7ee2968 100644
--- a/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
+++ b/chrome/common/extensions/api/speech/tts_engine_manifest_handler.cc
@@ -145,7 +145,7 @@
     info->voices.push_back(voice_data);
   }
 
-  extension->SetManifestData(keys::kTtsVoices, info.release());
+  extension->SetManifestData(keys::kTtsVoices, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc b/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
index f7e7867e..0a903fe 100644
--- a/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
+++ b/chrome/common/extensions/api/spellcheck/spellcheck_handler.cc
@@ -59,7 +59,7 @@
     *error = base::ASCIIToUTF16(errors::kInvalidSpellcheckDictionaryPath);
     return false;
   }
-  extension->SetManifestData(keys::kSpellcheck, spellcheck_info.release());
+  extension->SetManifestData(keys::kSpellcheck, std::move(spellcheck_info));
   return true;
 }
 
diff --git a/chrome/common/extensions/api/url_handlers/url_handlers_parser.cc b/chrome/common/extensions/api/url_handlers/url_handlers_parser.cc
index a5829a2..61dc4998 100644
--- a/chrome/common/extensions/api/url_handlers/url_handlers_parser.cc
+++ b/chrome/common/extensions/api/url_handlers/url_handlers_parser.cc
@@ -159,7 +159,7 @@
     }
   }
 
-  extension->SetManifestData(mkeys::kUrlHandlers, info.release());
+  extension->SetManifestData(mkeys::kUrlHandlers, std::move(info));
 
   return true;
 }
diff --git a/chrome/common/extensions/chrome_manifest_url_handlers.cc b/chrome/common/extensions/chrome_manifest_url_handlers.cc
index 3d13dd9..96246f53 100644
--- a/chrome/common/extensions/chrome_manifest_url_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_url_handlers.cc
@@ -77,7 +77,7 @@
     return false;
   }
   manifest_url->url_ = extension->GetResourceURL(devtools_str);
-  extension->SetManifestData(keys::kDevToolsPage, manifest_url.release());
+  extension->SetManifestData(keys::kDevToolsPage, std::move(manifest_url));
   PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
   return true;
 }
@@ -143,7 +143,7 @@
     return false;
   }
   extension->SetManifestData(keys::kChromeURLOverrides,
-                             url_overrides.release());
+                             std::move(url_overrides));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc b/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
index 26822b2..a03a5db 100644
--- a/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
@@ -75,7 +75,7 @@
   }
 
   extension->SetManifestData(keys::kAppIconColor,
-                             app_icon_color_info.release());
+                             std::move(app_icon_color_info));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/app_launch_info.cc b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
index 6ee7e34..8f1316f8 100644
--- a/chrome/common/extensions/manifest_handlers/app_launch_info.cc
+++ b/chrome/common/extensions/manifest_handlers/app_launch_info.cc
@@ -305,7 +305,7 @@
   std::unique_ptr<AppLaunchInfo> info(new AppLaunchInfo);
   if (!info->Parse(extension, error))
     return false;
-  extension->SetManifestData(keys::kLaunch, info.release());
+  extension->SetManifestData(keys::kLaunch, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/automation.cc b/chrome/common/extensions/manifest_handlers/automation.cc
index c1f5a3ff..b8db260 100644
--- a/chrome/common/extensions/manifest_handlers/automation.cc
+++ b/chrome/common/extensions/manifest_handlers/automation.cc
@@ -174,7 +174,7 @@
   if (!info)
     return true;
 
-  extension->SetManifestData(keys::kAutomation, info.release());
+  extension->SetManifestData(keys::kAutomation, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc b/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
index 8fa6823..affae04 100644
--- a/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/content_scripts_handler.cc
@@ -418,7 +418,7 @@
     content_scripts_info->content_scripts.push_back(std::move(user_script));
   }
   extension->SetManifestData(keys::kContentScripts,
-                             content_scripts_info.release());
+                             std::move(content_scripts_info));
   PermissionsParser::SetScriptableHosts(
       extension, ContentScriptsInfo::GetScriptableHosts(extension));
   return true;
diff --git a/chrome/common/extensions/manifest_handlers/linked_app_icons.cc b/chrome/common/extensions/manifest_handlers/linked_app_icons.cc
index b1f089c..5fcc5a7 100644
--- a/chrome/common/extensions/manifest_handlers/linked_app_icons.cc
+++ b/chrome/common/extensions/manifest_handlers/linked_app_icons.cc
@@ -101,7 +101,8 @@
     }
   }
 
-  extension->SetManifestData(keys::kLinkedAppIcons, linked_app_icons.release());
+  extension->SetManifestData(keys::kLinkedAppIcons,
+                             std::move(linked_app_icons));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
index 4f05e00..10c4a5c7 100644
--- a/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -174,8 +174,7 @@
             PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
             FormatUrlForDisplay(*(info->homepage))));
   }
-  extension->SetManifestData(manifest_keys::kSettingsOverride,
-                             info.release());
+  extension->SetManifestData(manifest_keys::kSettingsOverride, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/theme_handler.cc b/chrome/common/extensions/manifest_handlers/theme_handler.cc
index 99106c9..f4359117 100644
--- a/chrome/common/extensions/manifest_handlers/theme_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/theme_handler.cc
@@ -185,7 +185,7 @@
   if (!LoadDisplayProperties(theme_value, error, theme_info.get()))
     return false;
 
-  extension->SetManifestData(keys::kTheme, theme_info.release());
+  extension->SetManifestData(keys::kTheme, std::move(theme_info));
   return true;
 }
 
diff --git a/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc b/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc
index 7620516..4566738 100644
--- a/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc
+++ b/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc
@@ -143,7 +143,7 @@
   }
   info->manifest_permission.reset(new ManifestPermissionImpl(
       info->bookmarks_ui.get() != NULL));
-  extension->SetManifestData(manifest_keys::kUIOverride, info.release());
+  extension->SetManifestData(manifest_keys::kUIOverride, std::move(info));
   return true;
 }
 
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto
index 902ea1b..9e3b5e5b 100644
--- a/chrome/common/safe_browsing/csd.proto
+++ b/chrome/common/safe_browsing/csd.proto
@@ -468,6 +468,9 @@
 
   // An arbitrary token that should be sent along for further server requests.
   optional bytes token = 3;
+
+  // Whether the server requests that this binary be uploaded.
+  optional bool upload = 5;
 }
 
 // The following protocol buffer holds the feedback report gathered
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 87875d24..356dd92 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3792,7 +3792,6 @@
       "../browser/lifetime/keep_alive_registry_unittest.cc",
       "../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/country_combobox_model_unittest.cc",
       "../browser/ui/autofill/save_card_bubble_controller_impl_unittest.cc",
       "../browser/ui/bluetooth/bluetooth_chooser_controller_unittest.cc",
       "../browser/ui/passwords/manage_passwords_ui_controller_unittest.cc",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
index 8ecb7ba..3df0201 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java
@@ -43,22 +43,20 @@
 
     /**
      * Opens a context menu.
-     * @param testCase              The test harness.
      * @param tab                   The tab to open a context menu for.
      * @param openerDOMNodeId       The DOM node to long press to open the context menu for.
      * @return                      The {@link ContextMenu} that was opened.
      * @throws InterruptedException
      * @throws TimeoutException
      */
-    public static ContextMenu openContextMenu(ActivityInstrumentationTestCase2<?> testCase,
-            Tab tab, String openerDOMNodeId) throws InterruptedException, TimeoutException {
+    public static ContextMenu openContextMenu(Tab tab, String openerDOMNodeId)
+            throws InterruptedException, TimeoutException {
         String jsCode = "document.getElementById('" + openerDOMNodeId + "')";
-        return openContextMenuByJs(testCase, tab, jsCode);
+        return openContextMenuByJs(tab, jsCode);
     }
 
     /**
      * Opens a context menu.
-     * @param testCase              The test harness.
      * @param tab                   The tab to open a context menu for.
      * @param jsCode                The javascript to get the DOM node to long press to
      *                              open the context menu for.
@@ -66,8 +64,8 @@
      * @throws InterruptedException
      * @throws TimeoutException
      */
-    public static ContextMenu openContextMenuByJs(ActivityInstrumentationTestCase2<?> testCase,
-            Tab tab, String jsCode) throws InterruptedException, TimeoutException {
+    public static ContextMenu openContextMenuByJs(Tab tab, String jsCode)
+            throws InterruptedException, TimeoutException {
         final OnContextMenuShownHelper helper = new OnContextMenuShownHelper();
         tab.addObserver(new EmptyTabObserver() {
             @Override
@@ -77,7 +75,7 @@
             }
         });
         int callCount = helper.getCallCount();
-        DOMUtils.longPressNodeByJs(testCase, tab.getContentViewCore(), jsCode);
+        DOMUtils.longPressNodeByJs(tab.getContentViewCore(), jsCode);
 
         helper.waitForCallback(callCount);
         return helper.getContextMenu();
@@ -112,7 +110,7 @@
     public static void selectContextMenuItemByJs(ActivityInstrumentationTestCase2<?> testCase,
             Tab tab, String jsCode, final int itemId) throws InterruptedException,
             TimeoutException {
-        ContextMenu menu = openContextMenuByJs(testCase, tab, jsCode);
+        ContextMenu menu = openContextMenuByJs(tab, jsCode);
         Assert.assertNotNull("Failed to open context menu", menu);
 
         selectOpenContextMenuItem(testCase, menu, itemId);
@@ -130,7 +128,7 @@
     public static void selectContextMenuItemByTitle(ActivityInstrumentationTestCase2<?> testCase,
             Tab tab, String openerDOMNodeId,
             String itemTitle) throws InterruptedException, TimeoutException {
-        ContextMenu menu = openContextMenu(testCase, tab, openerDOMNodeId);
+        ContextMenu menu = openContextMenu(tab, openerDOMNodeId);
         Assert.assertNotNull("Failed to open context menu", menu);
 
         Integer itemId = null;
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index 883b6ff7..08a9dd7 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -198,10 +198,10 @@
     Browser::Type browser_type,
     bool hosted_app,
     BrowserWindow* browser_window) {
-  Browser::CreateParams params(profile);
+  Browser::CreateParams params(profile, true);
   if (hosted_app) {
     params = Browser::CreateParams::CreateForApp(
-        "Test", true /* trusted_source */, gfx::Rect(), profile);
+        "Test", true /* trusted_source */, gfx::Rect(), profile, true);
   } else {
     params.type = browser_type;
   }
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 99651be2..11abd4407 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -446,22 +446,22 @@
 // Creates a browser with a single tab (about:blank), waits for the tab to
 // finish loading and shows the browser.
 Browser* InProcessBrowserTest::CreateBrowser(Profile* profile) {
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
 
 Browser* InProcessBrowserTest::CreateIncognitoBrowser() {
   // Create a new browser with using the incognito profile.
-  Browser* incognito = new Browser(
-      Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile()));
+  Browser* incognito = new Browser(Browser::CreateParams(
+      browser()->profile()->GetOffTheRecordProfile(), true));
   AddBlankTabAndShow(incognito);
   return incognito;
 }
 
 Browser* InProcessBrowserTest::CreateBrowserForPopup(Profile* profile) {
   Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile));
+      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
@@ -469,9 +469,8 @@
 Browser* InProcessBrowserTest::CreateBrowserForApp(
     const std::string& app_name,
     Profile* profile) {
-  Browser* browser = new Browser(
-      Browser::CreateParams::CreateForApp(
-          app_name, false /* trusted_source */, gfx::Rect(), profile));
+  Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
+      app_name, false /* trusted_source */, gfx::Rect(), profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
diff --git a/chrome/test/base/in_process_browser_test_mac.cc b/chrome/test/base/in_process_browser_test_mac.cc
index c25cc90b..85ccd74 100644
--- a/chrome/test/base/in_process_browser_test_mac.cc
+++ b/chrome/test/base/in_process_browser_test_mac.cc
@@ -46,7 +46,7 @@
   // autorelease pool. Flush the pool when this function returns.
   base::mac::ScopedNSAutoreleasePool pool;
 
-  Browser* browser = new Browser(Browser::CreateParams(profile));
+  Browser* browser = new Browser(Browser::CreateParams(profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
@@ -57,8 +57,8 @@
   base::mac::ScopedNSAutoreleasePool pool;
 
   // Create a new browser with using the incognito profile.
-  Browser* incognito = new Browser(
-      Browser::CreateParams(browser()->profile()->GetOffTheRecordProfile()));
+  Browser* incognito = new Browser(Browser::CreateParams(
+      browser()->profile()->GetOffTheRecordProfile(), true));
   AddBlankTabAndShow(incognito);
   return incognito;
 }
@@ -69,7 +69,7 @@
   base::mac::ScopedNSAutoreleasePool pool;
 
   Browser* browser =
-      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile));
+      new Browser(Browser::CreateParams(Browser::TYPE_POPUP, profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
@@ -82,7 +82,7 @@
   base::mac::ScopedNSAutoreleasePool pool;
 
   Browser* browser = new Browser(Browser::CreateParams::CreateForApp(
-      app_name, false /* trusted_source */, gfx::Rect(), profile));
+      app_name, false /* trusted_source */, gfx::Rect(), profile, true));
   AddBlankTabAndShow(browser);
   return browser;
 }
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 27c492c6..1adb0e2d 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -83,6 +83,8 @@
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1673
     'ChromeDownloadDirTest.testFileDownloadWithGet',
     'ChromeDriverPageLoadTimeoutTest.*',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1683
+    'ChromeDriverTest.testShadowDomClick',
 ]
 _VERSION_SPECIFIC_FILTER['57'] = [
     # https://code.google.com/p/chromedriver/issues/detail?id=992
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 1e15157a..fb8da8e5 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -147,15 +147,23 @@
 ]
 
 _SPECIFIC_OS_REVISION_NEGATIVE_FILTER = {}
-_SPECIFIC_OS_REVISION_NEGATIVE_FILTER['linux_53'] = [
-    # Flaky on Linux32 against v53:
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1418
-    'ClickTest.testShouldOnlyFollowHrefOnce',
-    'JavascriptEnabledDriverTest.*',
-    'WindowSwitchingTest.testCanCloseWindowWhenMultipleWindowsAreOpen',
-    'WindowSwitchingTest.testCanCallGetWindowHandlesAfterClosingAWindow',
-    'WindowSwitchingTest.testCanCloseWindowAndSwitchBackToMainWindow',
-    'XPathElementFindingTest.testShouldFindElementsByXPath',
+_SPECIFIC_OS_REVISION_NEGATIVE_FILTER['linux_HEAD'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1683
+    'ClickScrollingTest.testShouldBeAbleToClickElementInAFrameThatIsOutOfView',
+    'ClickScrollingTest.testShouldBeAbleToClickElementThatIsOutOfViewInAFrameThatIsOutOfView',
+    'ClickTest.testClickingLabelShouldSetCheckbox',
+    'ElementFindingTest.testRemovingAnElementDynamicallyFromTheDomShouldCauseAStaleRefException',
+    'FrameSwitchingTest.testShouldBeAbleToSwitchToTheTopIfTheFrameIsDeletedFromUnderUs',
+]
+_SPECIFIC_OS_REVISION_NEGATIVE_FILTER['win_HEAD'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1683
+    'RenderedWebElementTest.testMoveRelativeToBody',
+    'RenderedWebElementTest.testCanClickOnSuckerFishMenuItem',
+    'BasicKeyboardInterfaceTest.testBasicKeyboardInput',
+]
+_SPECIFIC_OS_REVISION_NEGATIVE_FILTER['mac_HEAD'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1683
+    'AlertsTest.testShouldHandleAlertOnPageLoad',
 ]
 
 _OS_NEGATIVE_FILTER['android:chrome'] = [
diff --git a/chrome/test/data/extensions/api_test/chromeos_info_private/basic/background.js b/chrome/test/data/extensions/api_test/chromeos_info_private/basic/background.js
index f0808fc..60f4c82 100644
--- a/chrome/test/data/extensions/api_test/chromeos_info_private/basic/background.js
+++ b/chrome/test/data/extensions/api_test/chromeos_info_private/basic/background.js
@@ -23,6 +23,9 @@
               if (keys[i] == 'playStoreStatus') {
                 chrome.test.assertEq('not available', values[keys[i]]);
               }
+              if (keys[i] == 'managedDeviceStatus') {
+                chrome.test.assertEq('not managed', values[keys[i]]);
+              }
               // Debug
               if (keys[i] in values) {
                 console.log('  values["' + keys[i] + '"] = ' +
@@ -117,6 +120,7 @@
                                   'isOwner',
                                   'sessionType',
                                   'playStoreStatus',
+                                  'managedDeviceStatus',
                                   'clientId',
                                   'a11yLargeCursorEnabled',
                                   'a11yStickyKeysEnabled',
diff --git a/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js b/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js
index 9297957..b4e2c74 100644
--- a/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js
+++ b/chrome/test/data/extensions/api_test/chromeos_info_private/extended/background.js
@@ -9,18 +9,27 @@
       chrome.test.fail("Missing test name.");
       return;
     }
-    chrome.chromeosInfoPrivate.get(['sessionType', 'playStoreStatus'],
-        function (values) {
-      if (testName == 'kiosk') {
-        chrome.test.assertEq('kiosk', values['sessionType']);
-      } else if (testName == 'arc not-available') {
-        chrome.test.assertEq('not available', values['playStoreStatus']);
-      } else if (testName == 'arc available') {
-        chrome.test.assertEq('available', values['playStoreStatus']);
-      } else if (testName == 'arc enabled') {
-        chrome.test.assertEq('enabled', values['playStoreStatus']);
-      }
-      chrome.test.succeed();
-    });
+    chrome.chromeosInfoPrivate.get([
+      'sessionType',
+      'playStoreStatus',
+      'managedDeviceStatus'
+    ], chrome.test.callbackPass(function(values) {
+          switch (testName) {
+            case 'kiosk':
+              chrome.test.assertEq('kiosk', values['sessionType']);
+              break;
+            case 'arc not-available':
+              chrome.test.assertEq('not available', values['playStoreStatus']);
+              break;
+            case 'arc available':
+              chrome.test.assertEq('available', values['playStoreStatus']);
+              break;
+            case 'arc enabled':
+              chrome.test.assertEq('enabled', values['playStoreStatus']);
+              break;
+            case 'managed':
+              chrome.test.assertEq('managed', values['managedDeviceStatus']);
+          }
+        }));
   });
 });
diff --git a/chrome/test/data/webui/settings/settings_menu_test.js b/chrome/test/data/webui/settings/settings_menu_test.js
index 3f5d5e6..9752927 100644
--- a/chrome/test/data/webui/settings/settings_menu_test.js
+++ b/chrome/test/data/webui/settings/settings_menu_test.js
@@ -87,6 +87,30 @@
         var path = new window.URL(selector.selected).pathname;
         assertEquals('/reset', path);
       });
+
+      test('navigateToAnotherSection', function() {
+        var selector = settingsMenu.$.subMenu;
+        var path = new window.URL(selector.selected).pathname;
+        assertEquals('/reset', path);
+
+        settings.navigateTo(settings.Route.PEOPLE, '');
+        Polymer.dom.flush();
+
+        path = new window.URL(selector.selected).pathname;
+        assertEquals('/people', path);
+      });
+
+      test('navigateToBasic', function() {
+        var selector = settingsMenu.$.subMenu;
+        var path = new window.URL(selector.selected).pathname;
+        assertEquals('/reset', path);
+
+        settings.navigateTo(settings.Route.BASIC, '');
+        Polymer.dom.flush();
+
+        // BASIC has no sub page selected.
+        assertFalse(!!selector.selected);
+      });
     });
   }
 
diff --git a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
index 04892f09..82ae9da 100644
--- a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
+++ b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
@@ -80,7 +80,7 @@
 class CPUMemoryCastBenckmark(_BaseCastBenchmark):
   """Benchmark for CPU and memory usage with Media Router."""
 
-  options = {'page_repeat': 1}
+  options = {'pageset_repeat': 1}
 
   page_set = media_router_perf_pages.MediaRouterCPUMemoryPageSet
 
@@ -95,7 +95,7 @@
 class CPUMemoryBenckmark(perf_benchmark.PerfBenchmark):
   """Benchmark for CPU and memory usage without Media Router."""
 
-  options = {'page_repeat': 1}
+  options = {'pageset_repeat': 1}
 
   page_set = media_router_perf_pages.CPUMemoryPageSet
 
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 6e0581f8..aff4184 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -309,6 +309,10 @@
     "//chromecast/app:test_support",
     "//chromecast/browser:browsertests",
   ]
+
+  data_deps = [
+    ":chromecast_locales_pak",
+  ]
 }
 
 group("cast_shell_lib") {
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index cd535eb..9d4883c 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -45,6 +45,7 @@
     "//crypto",
     "//crypto:platform",
     "//google_apis",
+    "//media/base:video_facing",
     "//net",
     "//skia",  # For components/user_manager
     "//third_party/icu",
diff --git a/chromeos/DEPS b/chromeos/DEPS
index 512e62d..85d0d21 100644
--- a/chromeos/DEPS
+++ b/chromeos/DEPS
@@ -10,6 +10,7 @@
   "+components/signin/core/account_id/account_id.h",
   "+components/user_manager/known_user.h",
   "+crypto",
+  "+media/base/video_facing.h",
   "+net",
   "+third_party/cros_system_api",
   "+third_party/libxml",
diff --git a/chromeos/audio/cras_audio_handler.cc b/chromeos/audio/cras_audio_handler.cc
index a6cd9f0..444eab6 100644
--- a/chromeos/audio/cras_audio_handler.cc
+++ b/chromeos/audio/cras_audio_handler.cc
@@ -126,6 +126,14 @@
   return g_cras_audio_handler;
 }
 
+void CrasAudioHandler::OnVideoCaptureStarted(media::VideoFacingMode facing) {
+  // TODO(jennyz): Switch active audio device according to video facing.
+}
+
+void CrasAudioHandler::OnVideoCaptureStopped(media::VideoFacingMode facing) {
+  // TODO(jennyz): Switch active audio device according to video facing.
+}
+
 void CrasAudioHandler::AddAudioObserver(AudioObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/chromeos/audio/cras_audio_handler.h b/chromeos/audio/cras_audio_handler.h
index 1408f06..ac8a756 100644
--- a/chromeos/audio/cras_audio_handler.h
+++ b/chromeos/audio/cras_audio_handler.h
@@ -21,6 +21,7 @@
 #include "chromeos/dbus/cras_audio_client.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/dbus/volume_state.h"
+#include "media/base/video_facing.h"
 
 namespace chromeos {
 
@@ -28,11 +29,12 @@
 
 class CHROMEOS_EXPORT CrasAudioHandler : public CrasAudioClient::Observer,
                                          public AudioPrefObserver,
-                                         public SessionManagerClient::Observer {
+                                         public SessionManagerClient::Observer,
+                                         public media::VideoCaptureObserver {
  public:
-  typedef std::priority_queue<AudioDevice,
-                              std::vector<AudioDevice>,
-                              AudioDeviceCompare> AudioDevicePriorityQueue;
+  typedef std::
+      priority_queue<AudioDevice, std::vector<AudioDevice>, AudioDeviceCompare>
+          AudioDevicePriorityQueue;
   typedef std::vector<uint64_t> NodeIdList;
 
   // Volume change reasons that are not user-initiated.
@@ -103,6 +105,10 @@
   // Gets the global instance. Initialize must be called first.
   static CrasAudioHandler* Get();
 
+  // Overrides media::VideoCaptureObserver.
+  void OnVideoCaptureStarted(media::VideoFacingMode facing) override;
+  void OnVideoCaptureStopped(media::VideoFacingMode facing) override;
+
   // Adds an audio observer.
   void AddAudioObserver(AudioObserver* observer);
 
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index eaed6e9c..d8af06c 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/format_macros.h"
 #include "base/guid.h"
 #include "base/json/json_string_value_serializer.h"
@@ -19,6 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
+#include "chromeos/chromeos_switches.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/network_event_log.h"
 #include "chromeos/network/network_state.h"
@@ -122,6 +124,13 @@
 NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState(
     const NetworkTypePattern& type) const {
   std::string technology = GetTechnologyForType(type);
+
+  if (technology == kTypeTether) {
+    bool is_tether_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
+        chromeos::switches::kEnableTether);
+    return is_tether_enabled ? TECHNOLOGY_ENABLED : TECHNOLOGY_UNAVAILABLE;
+  }
+
   TechnologyState state;
   if (shill_property_handler_->IsTechnologyEnabled(technology))
     state = TECHNOLOGY_ENABLED;
@@ -307,6 +316,20 @@
   }
 }
 
+void NetworkStateHandler::GetTetherNetworkList(int limit,
+                                               NetworkStateList* list) {
+  DCHECK(list);
+  list->clear();
+  int count = 0;
+
+  for (auto iter = tether_network_list_.begin();
+       iter != tether_network_list_.end(); ++iter) {
+    list->push_back((*iter)->AsNetworkState());
+    if (limit > 0 && ++count >= limit)
+      return;
+  }
+}
+
 const NetworkState* NetworkStateHandler::GetNetworkStateFromServicePath(
     const std::string& service_path,
     bool configured_only) const {
@@ -343,9 +366,19 @@
   return nullptr;
 }
 
-const std::string NetworkStateHandler::CreateTetherNetworkState(
-    const std::string& name) {
-  const std::string& guid = base::GenerateGUID();
+void NetworkStateHandler::AddTetherNetworkState(const std::string& guid,
+                                                const std::string& name) {
+  DCHECK(!guid.empty());
+
+  // If the network already exists, do nothing.
+  for (auto iter = tether_network_list_.begin();
+       iter != tether_network_list_.end(); ++iter) {
+    if (iter->get()->AsNetworkState()->guid() == guid) {
+      NET_LOG(ERROR) << "AddTetherNetworkState: " << name
+                     << " called with existing guid:" << guid;
+      return;
+    }
+  }
 
   std::unique_ptr<NetworkState> tether_managed_state =
       base::MakeUnique<NetworkState>(base::GenerateGUID());
@@ -357,8 +390,6 @@
 
   tether_network_list_.push_back(std::move(tether_managed_state));
   NotifyNetworkListChanged();
-
-  return guid;
 }
 
 void NetworkStateHandler::RemoveTetherNetworkState(const std::string& guid) {
@@ -1028,6 +1059,9 @@
   if (type.MatchesType(shill::kTypeCellular))
     return shill::kTypeCellular;
 
+  if (type.MatchesType(kTypeTether))
+    return kTypeTether;
+
   NOTREACHED();
   return std::string();
 }
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index 99398bc..2866d3c 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -91,7 +91,8 @@
                       const tracked_objects::Location& from_here);
 
   // Returns the state for technology |type|. Only
-  // NetworkTypePattern::Primitive, ::Mobile and ::Ethernet are supported.
+  // NetworkTypePattern::Primitive, ::Mobile, ::Ethernet, and ::Tether are
+  // supported.
   TechnologyState GetTechnologyState(const NetworkTypePattern& type) const;
   bool IsTechnologyAvailable(const NetworkTypePattern& type) const {
     return GetTechnologyState(type) != TECHNOLOGY_UNAVAILABLE;
@@ -181,6 +182,15 @@
                             int limit,
                             NetworkStateList* list);
 
+  // Sets |list| to contain the list of "tether" networks. If |limit| > 0, that
+  // will determine the number of results; pass 0 for no limit. The returned
+  // list contains a copy of NetworkState pointers which should not be stored or
+  // used beyond the scope of the calling function (i.e. they may later become
+  // invalid, but only on the UI thread).
+  // NOTE: See AddTetherNetworkState for more information about "tether"
+  // networks.
+  void GetTetherNetworkList(int limit, NetworkStateList* list);
+
   // Finds and returns the NetworkState associated with |service_path| or NULL
   // if not found. If |configured_only| is true, only returns saved entries
   // (IsInProfile is true).
@@ -194,14 +204,15 @@
 
   // Creates a "tether" NetworkState that has no underlying shill type or
   // service. When initially created, it does not actually represent a real
-  // network. Generates and returns a guid to be used to refer to and fetch this
-  // NetworkState in the future.
+  // network. The |guid| provided must be non-empty. If a network with |guid|
+  // already exists, this method will do nothing. Use the provided |guid| to
+  // refer to and fetch this NetworkState in the future.
   // NOTE: only GetNetworkStateFromGuid is supported to fetch "tether"
   // NetworkStates.
-  const std::string CreateTetherNetworkState(const std::string& name);
+  void AddTetherNetworkState(const std::string& guid, const std::string& name);
 
-  // Remove a "tether" NetworkState, using the same guid that was returned by
-  // CreateTetherNetworkState.
+  // Remove a "tether" NetworkState, using the same |guid| passed to
+  // AddTetherNetworkState.
   void RemoveTetherNetworkState(const std::string& guid);
 
   // Sets |list| to contain the list of devices.  The returned list contains
diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc
index 8f48ef2e..056f58e 100644
--- a/chromeos/network/network_state_handler_unittest.cc
+++ b/chromeos/network/network_state_handler_unittest.cc
@@ -12,10 +12,12 @@
 #include <string>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/values.h"
+#include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_device_client.h"
 #include "chromeos/dbus/shill_ipconfig_client.h"
@@ -45,7 +47,10 @@
 const char kShillManagerClientStubWifi2[] = "/service/wifi2";
 const char kShillManagerClientStubCellular[] = "/service/cellular1";
 
-const char kTetherName[] = "Device";
+const char kTetherGuid1[] = "tether1";
+const char kTetherGuid2[] = "tether2";
+const char kTetherName1[] = "Device1";
+const char kTetherName2[] = "Device2";
 
 using chromeos::DeviceState;
 using chromeos::NetworkState;
@@ -371,6 +376,30 @@
   EXPECT_EQ(1u, networks.size());
 }
 
+TEST_F(NetworkStateHandlerTest, GetTetherNetworkList) {
+  NetworkStateHandler::NetworkStateList tether_networks;
+
+  network_state_handler_->GetTetherNetworkList(0 /* no limit */,
+                                               &tether_networks);
+  EXPECT_EQ(0u, tether_networks.size());
+
+  network_state_handler_->AddTetherNetworkState(kTetherGuid1, kTetherName1);
+
+  network_state_handler_->GetTetherNetworkList(0 /* no limit */,
+                                               &tether_networks);
+  EXPECT_EQ(1u, tether_networks.size());
+
+  network_state_handler_->AddTetherNetworkState(kTetherGuid2, kTetherName2);
+
+  network_state_handler_->GetTetherNetworkList(0 /* no limit */,
+                                               &tether_networks);
+  EXPECT_EQ(2u, tether_networks.size());
+
+  network_state_handler_->GetTetherNetworkList(1 /* no limit */,
+                                               &tether_networks);
+  EXPECT_EQ(1u, tether_networks.size());
+}
+
 TEST_F(NetworkStateHandlerTest, NetworkListChanged) {
   size_t stub_network_count = test_observer_->network_count();
   // Set up two additional visible networks.
@@ -497,6 +526,19 @@
       network_state_handler_->GetTechnologyState(NetworkTypePattern::Wimax()));
 }
 
+TEST_F(NetworkStateHandlerTest, TetherTechnologyState) {
+  EXPECT_EQ(
+      NetworkStateHandler::TECHNOLOGY_UNAVAILABLE,
+      network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      chromeos::switches::kEnableTether);
+
+  EXPECT_EQ(
+      NetworkStateHandler::TECHNOLOGY_ENABLED,
+      network_state_handler_->GetTechnologyState(NetworkTypePattern::Tether()));
+}
+
 TEST_F(NetworkStateHandlerTest, ServicePropertyChanged) {
   // Set a service property.
   const std::string eth1 = kShillManagerClientStubDefaultService;
@@ -547,21 +589,20 @@
 TEST_F(NetworkStateHandlerTest, TetherNetworkState) {
   EXPECT_EQ(0u, test_observer_->network_list_changed_count());
 
-  const std::string& guid =
-      network_state_handler_->CreateTetherNetworkState(kTetherName);
+  network_state_handler_->AddTetherNetworkState(kTetherGuid1, kTetherName1);
 
   EXPECT_EQ(1u, test_observer_->network_list_changed_count());
 
   const NetworkState* tether_network =
-      network_state_handler_->GetNetworkStateFromGuid(guid);
+      network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1);
   ASSERT_TRUE(tether_network);
-  EXPECT_EQ(kTetherName, tether_network->name());
+  EXPECT_EQ(kTetherName1, tether_network->name());
 
-  network_state_handler_->RemoveTetherNetworkState(guid);
+  network_state_handler_->RemoveTetherNetworkState(kTetherGuid1);
 
   EXPECT_EQ(2u, test_observer_->network_list_changed_count());
 
-  ASSERT_FALSE(network_state_handler_->GetNetworkStateFromGuid(guid));
+  ASSERT_FALSE(network_state_handler_->GetNetworkStateFromGuid(kTetherGuid1));
 }
 
 TEST_F(NetworkStateHandlerTest, NetworkConnectionStateChanged) {
diff --git a/cloud_print/OWNERS b/cloud_print/OWNERS
index 8a47a27..e04ac0f 100644
--- a/cloud_print/OWNERS
+++ b/cloud_print/OWNERS
@@ -5,3 +5,4 @@
 # vitalybuka is not on the Chrome project use only as a last resort!
 vitalybuka@chromium.org
 
+# COMPONENT: Services>CloudPrint
diff --git a/components/OWNERS b/components/OWNERS
index ffa8c1d..1dbc3891 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -21,6 +21,7 @@
 per-file payments_strings.grdp=file://components/payments/OWNERS
 per-file pdf_strings.grdp=raymes@chromium.org
 per-file pdf_strings.grdp=tsergeant@chromium.org
+per-file physical_web_ui_strings.grdp=file://components/physical_web/OWNERS
 per-file policy_strings.grdp=file://components/policy/OWNERS
 per-file security_interstitials_strings.grdp=file://components/security_interstitials/OWNERS
 per-file security_state_strings.grdp=file://components/security_state/OWNERS
diff --git a/components/arc/common/notifications.mojom b/components/arc/common/notifications.mojom
index 37268d20..b1b07b72 100644
--- a/components/arc/common/notifications.mojom
+++ b/components/arc/common/notifications.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 9
+// Next MinVersion: 10
 
 module arc.mojom;
 
@@ -131,10 +131,20 @@
   SendNotificationEventToAndroid@1(string key, ArcNotificationEvent event);
 
   // Requests to Android side to create the notification window.
+  // |key| is the identifier of the notification which is generated by Android
+  // side.
   [MinVersion=7]
   CreateNotificationWindow@2(string key);
 
   // Requests to Android side to close the notification window.
+  // |key| is the identifier of the notification which is generated by Android
+  // side.
   [MinVersion=7]
   CloseNotificationWindow@3(string key);
+
+  // Requests to Android side to open notification settings.
+  // |key| is the identifier of the notification which is generated by Android
+  // side.
+  [MinVersion=9]
+  OpenNotificationSettings@4(string key);
 };
diff --git a/components/arc/test/fake_notifications_instance.cc b/components/arc/test/fake_notifications_instance.cc
index 3a9f631..67ec0bd 100644
--- a/components/arc/test/fake_notifications_instance.cc
+++ b/components/arc/test/fake_notifications_instance.cc
@@ -21,6 +21,9 @@
 void FakeNotificationsInstance::CloseNotificationWindow(
     const std::string& key) {}
 
+void FakeNotificationsInstance::OpenNotificationSettings(
+    const std::string& key) {}
+
 void FakeNotificationsInstance::Init(mojom::NotificationsHostPtr host_ptr) {}
 
 const std::vector<std::pair<std::string, mojom::ArcNotificationEvent>>&
diff --git a/components/arc/test/fake_notifications_instance.h b/components/arc/test/fake_notifications_instance.h
index a615a4d..320dc79 100644
--- a/components/arc/test/fake_notifications_instance.h
+++ b/components/arc/test/fake_notifications_instance.h
@@ -25,6 +25,7 @@
       mojom::ArcNotificationEvent event) override;
   void CreateNotificationWindow(const std::string& key) override;
   void CloseNotificationWindow(const std::string& key) override;
+  void OpenNotificationSettings(const std::string& key) override;
 
   const std::vector<std::pair<std::string, mojom::ArcNotificationEvent>>&
   events() const;
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index 8dc6d34..3865c03 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -4,21 +4,32 @@
 
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 
+#include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
-#include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/autofill_manager.h"
-#include "components/autofill/core/browser/form_structure.h"
-#include "components/autofill/core/common/autofill_switches.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 
 namespace autofill {
 
+namespace {
+
+std::unique_ptr<AutofillDriver> CreateDriver(
+    content::RenderFrameHost* render_frame_host,
+    AutofillClient* client,
+    const std::string& app_locale,
+    AutofillManager::AutofillDownloadManagerState enable_download_manager) {
+  return base::MakeUnique<ContentAutofillDriver>(
+      render_frame_host, client, app_locale, enable_download_manager);
+}
+
+}  // namespace
+
 const char ContentAutofillDriverFactory::
     kContentAutofillDriverFactoryWebContentsUserDataKey[] =
         "web_contents_autofill_driver_factory";
@@ -83,31 +94,29 @@
     AutofillClient* client,
     const std::string& app_locale,
     AutofillManager::AutofillDownloadManagerState enable_download_manager)
-    : content::WebContentsObserver(web_contents),
-      client_(client),
+    : AutofillDriverFactory(client),
+      content::WebContentsObserver(web_contents),
       app_locale_(app_locale),
       enable_download_manager_(enable_download_manager) {}
 
 ContentAutofillDriver* ContentAutofillDriverFactory::DriverForFrame(
     content::RenderFrameHost* render_frame_host) {
-  auto mapping = frame_driver_map_.find(render_frame_host);
-  return mapping == frame_driver_map_.end() ? nullptr : mapping->second.get();
+  // This cast is safe because AutofillDriverFactory::AddForKey is protected
+  // and always called with ContentAutofillDriver instances within
+  // ContentAutofillDriverFactory.
+  return static_cast<ContentAutofillDriver*>(DriverForKey(render_frame_host));
 }
 
 void ContentAutofillDriverFactory::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
-  auto insertion_result =
-      frame_driver_map_.insert(std::make_pair(render_frame_host, nullptr));
-  // This is called twice for the main frame.
-  if (insertion_result.second) {  // This was the first time.
-    insertion_result.first->second = base::MakeUnique<ContentAutofillDriver>(
-        render_frame_host, client_, app_locale_, enable_download_manager_);
-  }
+  AddForKey(render_frame_host,
+            base::Bind(CreateDriver, render_frame_host, client(), app_locale_,
+                       enable_download_manager_));
 }
 
 void ContentAutofillDriverFactory::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
-  frame_driver_map_.erase(render_frame_host);
+  DeleteForKey(render_frame_host);
 }
 
 void ContentAutofillDriverFactory::DidFinishNavigation(
@@ -115,13 +124,13 @@
   if (!navigation_handle->HasCommitted())
     return;
 
-  client_->HideAutofillPopup();
-  frame_driver_map_[navigation_handle->GetRenderFrameHost()]->
-      DidNavigateFrame(navigation_handle);
+  NavigationFinished();
+  DriverForFrame(navigation_handle->GetRenderFrameHost())
+      ->DidNavigateFrame(navigation_handle);
 }
 
 void ContentAutofillDriverFactory::WasHidden() {
-  client_->HideAutofillPopup();
+  TabHidden();
 }
 
 }  // namespace autofill
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.h b/components/autofill/content/browser/content_autofill_driver_factory.h
index 63e168f6..df2d8bc 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.h
+++ b/components/autofill/content/browser/content_autofill_driver_factory.h
@@ -5,12 +5,11 @@
 #ifndef COMPONENTS_AUTOFILL_CONTENT_BROWSER_CONTENT_AUTOFILL_DRIVER_FACTORY_H_
 #define COMPONENTS_AUTOFILL_CONTENT_BROWSER_CONTENT_AUTOFILL_DRIVER_FACTORY_H_
 
-#include <map>
-#include <memory>
 #include <string>
 
 #include "base/supports_user_data.h"
 #include "components/autofill/content/common/autofill_driver.mojom.h"
+#include "components/autofill/core/browser/autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -24,7 +23,8 @@
 
 // Manages lifetime of ContentAutofillDriver. One Factory per WebContents
 // creates one Driver per RenderFrame.
-class ContentAutofillDriverFactory : public content::WebContentsObserver,
+class ContentAutofillDriverFactory : public AutofillDriverFactory,
+                                     public content::WebContentsObserver,
                                      public base::SupportsUserData::Data {
  public:
   ~ContentAutofillDriverFactory() override;
@@ -53,20 +53,15 @@
 
   static const char kContentAutofillDriverFactoryWebContentsUserDataKey[];
 
- protected:
+ private:
   ContentAutofillDriverFactory(
       content::WebContents* web_contents,
       AutofillClient* client,
       const std::string& app_locale,
       AutofillManager::AutofillDownloadManagerState enable_download_manager);
 
- private:
-  AutofillClient* client_;
   std::string app_locale_;
   AutofillManager::AutofillDownloadManagerState enable_download_manager_;
-
-  std::map<content::RenderFrameHost*, std::unique_ptr<ContentAutofillDriver>>
-      frame_driver_map_;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 30ec621..fb237cad 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -28,6 +28,8 @@
     "autofill_download_manager.cc",
     "autofill_download_manager.h",
     "autofill_driver.h",
+    "autofill_driver_factory.cc",
+    "autofill_driver_factory.h",
     "autofill_experiments.cc",
     "autofill_experiments.h",
     "autofill_external_delegate.cc",
@@ -60,6 +62,8 @@
     "card_unmask_delegate.h",
     "contact_info.cc",
     "contact_info.h",
+    "country_combobox_model.cc",
+    "country_combobox_model.h",
     "country_data.cc",
     "country_data.h",
     "country_names.cc",
@@ -297,6 +301,7 @@
     "autofill_data_model_unittest.cc",
     "autofill_data_util_unittest.cc",
     "autofill_download_manager_unittest.cc",
+    "autofill_driver_factory_unittest.cc",
     "autofill_external_delegate_unittest.cc",
     "autofill_field_unittest.cc",
     "autofill_ie_toolbar_import_win_unittest.cc",
@@ -307,6 +312,7 @@
     "autofill_profile_unittest.cc",
     "autofill_type_unittest.cc",
     "contact_info_unittest.cc",
+    "country_combobox_model_unittest.cc",
     "country_names_unittest.cc",
     "credit_card_field_unittest.cc",
     "credit_card_unittest.cc",
diff --git a/components/autofill/core/browser/autofill_driver_factory.cc b/components/autofill/core/browser/autofill_driver_factory.cc
new file mode 100644
index 0000000..19d369bb1
--- /dev/null
+++ b/components/autofill/core/browser/autofill_driver_factory.cc
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_driver_factory.h"
+
+#include "base/callback.h"
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/autofill_driver.h"
+
+namespace autofill {
+
+AutofillDriverFactory::AutofillDriverFactory(AutofillClient* client)
+    : client_(client) {}
+
+AutofillDriverFactory::~AutofillDriverFactory() {}
+
+AutofillDriver* AutofillDriverFactory::DriverForKey(void* key) {
+  auto mapping = driver_map_.find(key);
+  return mapping == driver_map_.end() ? nullptr : mapping->second.get();
+}
+
+void AutofillDriverFactory::AddForKey(
+    void* key,
+    base::Callback<std::unique_ptr<AutofillDriver>()> factory_method) {
+  auto insertion_result = driver_map_.insert(std::make_pair(key, nullptr));
+  // This can be called twice for the key representing the main frame.
+  if (insertion_result.second)
+    insertion_result.first->second = factory_method.Run();
+}
+
+void AutofillDriverFactory::DeleteForKey(void* key) {
+  driver_map_.erase(key);
+}
+
+void AutofillDriverFactory::NavigationFinished() {
+  client_->HideAutofillPopup();
+}
+
+void AutofillDriverFactory::TabHidden() {
+  client_->HideAutofillPopup();
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver_factory.h b/components/autofill/core/browser/autofill_driver_factory.h
new file mode 100644
index 0000000..8446d7a
--- /dev/null
+++ b/components/autofill/core/browser/autofill_driver_factory.h
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef AUTOFILL_CORE_BROWSER_AUTOFILL_DRIVER_FACTORY_H_
+#define AUTOFILL_CORE_BROWSER_AUTOFILL_DRIVER_FACTORY_H_
+
+#include <memory>
+#include <unordered_map>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+
+namespace autofill {
+
+class AutofillClient;
+class AutofillDriver;
+
+// Manages the lifetime of AutofillDrivers for a particular AutofillClient by
+// creating, retrieveing and deleting on demand.
+class AutofillDriverFactory {
+  // The API is protected to guarantee subclasses that nothing else can
+  // interfere with the map of drivers.
+ protected:
+  explicit AutofillDriverFactory(AutofillClient* client);
+
+  ~AutofillDriverFactory();
+
+  // A convenience function to retrieve an AutofillDriver for the given key or
+  // null if there is none.
+  AutofillDriver* DriverForKey(void* key);
+
+  // Adds a driver, constructed by calling |factory_method|, for |key|. If there
+  // already is a driver for |key|, |factory_method| is not called.
+  void AddForKey(
+      void* key,
+      base::Callback<std::unique_ptr<AutofillDriver>()> factory_method);
+
+  // Deletes the AutofillDriver for |key|.
+  void DeleteForKey(void* key);
+
+  // Handles finished navigation in any of the frames.
+  void NavigationFinished();
+
+  // Handles hiding of the corresponding tab.
+  void TabHidden();
+
+  AutofillClient* client() { return client_; };
+
+ private:
+  AutofillClient* const client_;
+
+  std::unordered_map<void*, std::unique_ptr<AutofillDriver>> driver_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillDriverFactory);
+};
+
+}  // namespace autofill
+
+#endif  // AUTOFILL_CORE_BROWSER_AUTOFILL_DRIVER_FACTORY_H_
diff --git a/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/components/autofill/core/browser/autofill_driver_factory_unittest.cc
new file mode 100644
index 0000000..e79c4716
--- /dev/null
+++ b/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/autofill_driver_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "components/autofill/core/browser/test_autofill_client.h"
+#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+namespace {
+
+class MockAutofillClient : public TestAutofillClient {
+ public:
+  MOCK_METHOD0(HideAutofillPopup, void());
+};
+
+// Just a stub AutofillDriver implementation which announces its construction
+// and desctruction by updating the passed |instance_counter|.
+class CountingAutofillDriver : public TestAutofillDriver {
+ public:
+  CountingAutofillDriver(int* instance_counter)
+      : instance_counter_(instance_counter) {
+    ++*instance_counter;
+  }
+
+  ~CountingAutofillDriver() override { --*instance_counter_; }
+
+ private:
+  int* const instance_counter_;
+
+  DISALLOW_COPY_AND_ASSIGN(CountingAutofillDriver);
+};
+
+// Code-wise this class is identitcal to AutofillDriverFactory, but exposes the
+// protected API to the test. Do not modify any of the methods, only include
+// "using" declarations to make the AutofillDriverFactory methods public.
+class PublicAutofillDriverFactory : public AutofillDriverFactory {
+ public:
+  explicit PublicAutofillDriverFactory(AutofillClient* client)
+      : AutofillDriverFactory(client) {}
+
+  ~PublicAutofillDriverFactory() {}
+
+  using AutofillDriverFactory::DriverForKey;
+  using AutofillDriverFactory::AddForKey;
+  using AutofillDriverFactory::DeleteForKey;
+  using AutofillDriverFactory::NavigationFinished;
+  using AutofillDriverFactory::TabHidden;
+};
+
+// Wrapper around an integer, checking that the integer is 0 on desctruction.
+class CheckedInt {
+ public:
+  CheckedInt() {}
+
+  ~CheckedInt() { EXPECT_EQ(0, val_); }
+
+  int* val() { return &val_; }
+
+ private:
+  int val_ = 0;
+};
+
+}  // namespace
+
+class AutofillDriverFactoryTest : public testing::Test {
+ public:
+  AutofillDriverFactoryTest() : factory_(&client_) {}
+
+  ~AutofillDriverFactoryTest() override {}
+
+  // AutofillDriverFactory stores drivers in a map with keys, which are void*
+  // pointers. The factory never dereferences them, so their value does not
+  // matter. This is a handy function to create such pointers from integer
+  // constants.
+  void* KeyFrom(int x) { return reinterpret_cast<void*>(x); }
+
+  std::unique_ptr<AutofillDriver> CreateDriver() {
+    ++drivers_created_;
+    return base::MakeUnique<CountingAutofillDriver>(instance_counter_.val());
+  }
+
+  base::Callback<std::unique_ptr<AutofillDriver>()> CreateDriverCallback() {
+    return base::Bind(&AutofillDriverFactoryTest::CreateDriver,
+                      base::Unretained(this));
+  }
+
+ protected:
+  base::MessageLoop message_loop_;  // For TestAutofillDriver.
+
+  MockAutofillClient client_;
+
+  CheckedInt instance_counter_;
+
+  PublicAutofillDriverFactory factory_;
+
+  // How many AutofillDriver instances were created with CreateDriver().
+  int drivers_created_ = 0;
+};
+
+TEST_F(AutofillDriverFactoryTest, DriverForKey_NoKey) {
+  EXPECT_FALSE(factory_.DriverForKey(nullptr));
+  EXPECT_FALSE(factory_.DriverForKey(KeyFrom(1)));
+}
+
+TEST_F(AutofillDriverFactoryTest, DriverForKey_OneKey) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_FALSE(factory_.DriverForKey(nullptr));
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+}
+
+TEST_F(AutofillDriverFactoryTest, DriverForKey_TwoKeys) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_FALSE(factory_.DriverForKey(nullptr));
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(1, *instance_counter_.val());
+
+  factory_.AddForKey(nullptr, CreateDriverCallback());
+  EXPECT_TRUE(factory_.DriverForKey(nullptr));
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(2, *instance_counter_.val());
+}
+
+TEST_F(AutofillDriverFactoryTest, AddForKey_Duplicated) {
+  EXPECT_FALSE(factory_.DriverForKey(KeyFrom(1)));
+
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(1, drivers_created_);
+  EXPECT_EQ(1, *instance_counter_.val());
+
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(1, drivers_created_);
+  EXPECT_EQ(1, *instance_counter_.val());
+}
+
+TEST_F(AutofillDriverFactoryTest, DeleteForKey) {
+  EXPECT_FALSE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(0, *instance_counter_.val());
+
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_TRUE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(1, *instance_counter_.val());
+
+  factory_.DeleteForKey(KeyFrom(1));
+  EXPECT_FALSE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(0, *instance_counter_.val());
+
+  // Duplicated calls should raise no errors.
+  factory_.DeleteForKey(KeyFrom(1));
+  EXPECT_FALSE(factory_.DriverForKey(KeyFrom(1)));
+  EXPECT_EQ(0, *instance_counter_.val());
+}
+
+TEST_F(AutofillDriverFactoryTest, NavigationFinished) {
+  EXPECT_CALL(client_, HideAutofillPopup());
+  factory_.NavigationFinished();
+}
+
+TEST_F(AutofillDriverFactoryTest, TabHidden) {
+  EXPECT_CALL(client_, HideAutofillPopup());
+  factory_.TabHidden();
+}
+
+}  // namespace autofill
diff --git a/chrome/browser/ui/autofill/country_combobox_model.cc b/components/autofill/core/browser/country_combobox_model.cc
similarity index 89%
rename from chrome/browser/ui/autofill/country_combobox_model.cc
rename to components/autofill/core/browser/country_combobox_model.cc
index 9a2c147e..c9f8a47 100644
--- a/chrome/browser/ui/autofill/country_combobox_model.cc
+++ b/components/autofill/core/browser/country_combobox_model.cc
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/autofill/country_combobox_model.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
 
 #include <algorithm>
 #include <iterator>
+#include <utility>
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "build/build_config.h"
-#include "chrome/browser/browser_process.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/country_data.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
@@ -27,7 +26,8 @@
 
 void CountryComboboxModel::SetCountries(
     const PersonalDataManager& manager,
-    const base::Callback<bool(const std::string&)>& filter) {
+    const base::Callback<bool(const std::string&)>& filter,
+    const std::string& app_locale) {
   countries_.clear();
 
   // Insert the default country at the top as well as in the ordered list.
@@ -35,7 +35,6 @@
       manager.GetDefaultCountryCodeForNewAddress();
   DCHECK(!default_country_code.empty());
 
-  const std::string& app_locale = g_browser_process->GetApplicationLocale();
   if (filter.is_null() || filter.Run(default_country_code)) {
     countries_.push_back(
         base::MakeUnique<AutofillCountry>(default_country_code, app_locale));
@@ -69,8 +68,7 @@
           base::MakeUnique<AutofillCountry>(country_code, app_locale));
   }
 
-  l10n_util::SortStringsUsingMethod(app_locale,
-                                    &sorted_countries,
+  l10n_util::SortStringsUsingMethod(app_locale, &sorted_countries,
                                     &AutofillCountry::name);
   std::move(sorted_countries.begin(), sorted_countries.end(),
             std::back_inserter(countries_));
diff --git a/chrome/browser/ui/autofill/country_combobox_model.h b/components/autofill/core/browser/country_combobox_model.h
similarity index 83%
rename from chrome/browser/ui/autofill/country_combobox_model.h
rename to components/autofill/core/browser/country_combobox_model.h
index d7e25a6a..b3d90c3a 100644
--- a/chrome/browser/ui/autofill/country_combobox_model.h
+++ b/components/autofill/core/browser/country_combobox_model.h
@@ -2,18 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_AUTOFILL_COUNTRY_COMBOBOX_MODEL_H_
-#define CHROME_BROWSER_UI_AUTOFILL_COUNTRY_COMBOBOX_MODEL_H_
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_COUNTRY_COMBOBOX_MODEL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_COUNTRY_COMBOBOX_MODEL_H_
 
 #include <memory>
-#include <set>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
-#include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "ui/base/models/combobox_model.h"
 
 namespace autofill {
@@ -33,7 +30,8 @@
   // true, an item for that country is added to the model (else it's omitted).
   // |manager| determines the default choice.
   void SetCountries(const PersonalDataManager& manager,
-                    const base::Callback<bool(const std::string&)>& filter);
+                    const base::Callback<bool(const std::string&)>& filter,
+                    const std::string& app_locale);
 
   // ui::ComboboxModel implementation:
   int GetItemCount() const override;
@@ -55,4 +53,4 @@
 
 }  // namespace autofill
 
-#endif  // CHROME_BROWSER_UI_AUTOFILL_COUNTRY_COMBOBOX_MODEL_H_
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_COUNTRY_COMBOBOX_MODEL_H_
diff --git a/chrome/browser/ui/autofill/country_combobox_model_unittest.cc b/components/autofill/core/browser/country_combobox_model_unittest.cc
similarity index 60%
rename from chrome/browser/ui/autofill/country_combobox_model_unittest.cc
rename to components/autofill/core/browser/country_combobox_model_unittest.cc
index 43883538..ca3e9f0 100644
--- a/chrome/browser/ui/autofill/country_combobox_model_unittest.cc
+++ b/components/autofill/core/browser/country_combobox_model_unittest.cc
@@ -2,19 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/autofill/country_combobox_model.h"
+#include "components/autofill/core/browser/country_combobox_model.h"
 
 #include <memory>
 
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/signin/account_tracker_service_factory.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/test/base/testing_profile.h"
 #include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
-#include "components/signin/core/browser/account_tracker_service.h"
-#include "components/signin/core/browser/signin_manager.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "components/prefs/pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui.h"
 #include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_ui_component.h"
@@ -24,24 +19,23 @@
 
 class CountryComboboxModelTest : public testing::Test {
  public:
-  CountryComboboxModelTest() {
-    manager_.Init(
-        NULL, profile_.GetPrefs(),
-        AccountTrackerServiceFactory::GetForProfile(&profile_),
-        SigninManagerFactory::GetForProfile(&profile_), false);
+  CountryComboboxModelTest()
+      : pref_service_(autofill::test::PrefServiceForTesting()) {
+    manager_.SetTestingPrefService(pref_service_.get());
     manager_.set_timezone_country_code("KR");
     model_.reset(new CountryComboboxModel());
-    model_->SetCountries(manager_, base::Callback<bool(const std::string&)>());
+    model_->SetCountries(manager_, base::Callback<bool(const std::string&)>(),
+                         "en-US");
   }
 
+  void TearDown() override { manager_.SetTestingPrefService(nullptr); }
+
   TestPersonalDataManager* manager() { return &manager_; }
   CountryComboboxModel* model() { return model_.get(); }
 
  private:
-  // NB: order is important here - |profile_| must go down after |manager_|.
-  content::TestBrowserThreadBundle thread_bundle_;
-  TestingProfile profile_;
   TestPersonalDataManager manager_;
+  std::unique_ptr<PrefService> pref_service_;
   std::unique_ptr<CountryComboboxModel> model_;
 };
 
@@ -49,8 +43,7 @@
   std::string default_country = model()->GetDefaultCountryCode();
   EXPECT_EQ(manager()->GetDefaultCountryCodeForNewAddress(), default_country);
 
-  AutofillCountry country(default_country,
-                          g_browser_process->GetApplicationLocale());
+  AutofillCountry country(default_country, "en-US");
   EXPECT_EQ(country.name(), model()->GetItemAt(0));
 }
 
@@ -62,9 +55,9 @@
       continue;
 
     std::string country_code = model()->countries()[i]->country_code();
-    std::vector< ::i18n::addressinput::AddressUiComponent> components =
-        ::i18n::addressinput::BuildComponents(
-            country_code, localization, std::string(), &unused);
+    std::vector<::i18n::addressinput::AddressUiComponent> components =
+        ::i18n::addressinput::BuildComponents(country_code, localization,
+                                              std::string(), &unused);
     EXPECT_FALSE(components.empty()) << " for country " << country_code;
   }
 }
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index ff24fce0..addf89f 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -628,7 +628,7 @@
   // Map from field signatures to cached fields.
   std::map<std::string, const AutofillField*> cached_fields;
   for (size_t i = 0; i < cached_form.field_count(); ++i) {
-    const auto& field = cached_form.field(i);
+    auto* const field = cached_form.field(i);
     cached_fields[field->FieldSignatureAsStr()] = field;
   }
 
@@ -681,7 +681,7 @@
   bool did_autofill_all_possible_fields = true;
   bool did_autofill_some_possible_fields = false;
   for (size_t i = 0; i < field_count(); ++i) {
-    const auto& field = this->field(i);
+    auto* const field = this->field(i);
 
     // No further logging for password fields.  Those are primarily related to a
     // different feature code path, and so make more sense to track outside of
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 5cc15a1e..590f814d 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -1815,7 +1815,7 @@
       C -> D
   */
 
-  for (auto& credit_card : GetCreditCards()) {
+  for (auto* credit_card : GetCreditCards()) {
     // If the credit card is not associated with a billing address, skip it.
     if (credit_card->billing_address_id().empty())
       break;
diff --git a/components/bookmarks/browser/typed_count_sorter.cc b/components/bookmarks/browser/typed_count_sorter.cc
index 311f1383..19576106 100644
--- a/components/bookmarks/browser/typed_count_sorter.cc
+++ b/components/bookmarks/browser/typed_count_sorter.cc
@@ -56,7 +56,7 @@
   if (client_->SupportsTypedCountForUrls()) {
     UrlNodeMap url_node_map;
     UrlTypedCountMap url_typed_count_map;
-    for (auto node : matches) {
+    for (auto* node : matches) {
       const GURL& url = node->GetTitledUrlNodeUrl();
       url_node_map.insert(std::make_pair(&url, node));
       url_typed_count_map.insert(std::make_pair(&url, 0));
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index 15886783..9be0f5c 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -200,7 +200,7 @@
   const auto it = component_ids_by_mime_type_.find(mime_type);
   if (it == component_ids_by_mime_type_.end())
     return nullptr;
-  const auto component = GetComponent(it->second);
+  auto* const component = GetComponent(it->second);
   if (!component)
     return nullptr;
   return base::MakeUnique<ComponentInfo>(GetCrxComponentID(*component),
diff --git a/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
index d75f27d..8afc502 100644
--- a/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
+++ b/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
@@ -610,7 +610,7 @@
   if (remote_service_.id.empty()) {
     std::vector<device::BluetoothRemoteGattService*> services =
         bluetooth_device->GetGattServices();
-    for (const auto& service : services)
+    for (auto* service : services)
       if (service->GetUUID() == remote_service_.uuid) {
         remote_service_.id = service->GetIdentifier();
         break;
diff --git a/components/data_use_measurement/core/data_use_measurement.cc b/components/data_use_measurement/core/data_use_measurement.cc
index 85b3f66b..3a80307 100644
--- a/components/data_use_measurement/core/data_use_measurement.cc
+++ b/components/data_use_measurement/core/data_use_measurement.cc
@@ -88,6 +88,16 @@
 {
   DCHECK(ascriber_);
   DCHECK(url_request_classifier_);
+
+#if defined(OS_ANDROID)
+  int64_t bytes = 0;
+  // Query Android traffic stats.
+  if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes))
+    rx_bytes_os_ = bytes;
+
+  if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes))
+    tx_bytes_os_ = bytes;
+#endif
 }
 
 DataUseMeasurement::~DataUseMeasurement(){};
@@ -312,7 +322,10 @@
   if (net::android::traffic_stats::GetCurrentUidRxBytes(&bytes)) {
     if (rx_bytes_os_ != 0) {
       DCHECK_GE(bytes, rx_bytes_os_);
-      UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.OS", bytes - rx_bytes_os_);
+      if (bytes > rx_bytes_os_) {
+        // Do not record samples with value 0.
+        UMA_HISTOGRAM_COUNTS("DataUse.BytesReceived.OS", bytes - rx_bytes_os_);
+      }
     }
     rx_bytes_os_ = bytes;
   }
@@ -320,7 +333,10 @@
   if (net::android::traffic_stats::GetCurrentUidTxBytes(&bytes)) {
     if (tx_bytes_os_ != 0) {
       DCHECK_GE(bytes, tx_bytes_os_);
-      UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.OS", bytes - tx_bytes_os_);
+      if (bytes > tx_bytes_os_) {
+        // Do not record samples with value 0.
+        UMA_HISTOGRAM_COUNTS("DataUse.BytesSent.OS", bytes - tx_bytes_os_);
+      }
     }
     tx_bytes_os_ = bytes;
   }
diff --git a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
index 82edfcbf..5d908c90 100644
--- a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
+++ b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
@@ -22,6 +22,7 @@
 import com.google.protos.ipc.invalidation.Types.ClientType;
 
 import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BuildInfo;
 import org.chromium.base.CollectionUtil;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
@@ -317,12 +318,21 @@
     private void startClient() {
         byte[] clientName = InvalidationClientNameProvider.get().getInvalidatorClientName();
         Intent startIntent = AndroidListener.createStartIntent(this, CLIENT_TYPE, clientName);
+
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to start client");
+            return;
+        }
         startService(startIntent);
         setIsClientStarted(true);
     }
 
     /** Stops the notification client. */
     private void stopClient() {
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to stop client");
+            return;
+        }
         startService(AndroidListener.createStopIntent(this));
         setIsClientStarted(false);
         setClientId(null);
@@ -540,4 +550,9 @@
     private static void setIsClientStarted(boolean isStarted) {
         sIsClientStarted = isStarted;
     }
+
+    private boolean shouldRestrictBackgroundServices() {
+        // Restricts the use of background services when not in foreground. See crbug.com/680812.
+        return BuildInfo.isGreaterThanN() && !isChromeInForeground();
+    }
 }
diff --git a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationService.java b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationService.java
index 92c017a..170681bd 100644
--- a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationService.java
+++ b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationService.java
@@ -10,6 +10,9 @@
 
 import com.google.protos.ipc.invalidation.Types;
 
+import org.chromium.base.ApplicationStatus;
+import org.chromium.base.BuildInfo;
+import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
@@ -29,6 +32,8 @@
 
     private final long mNativeInvalidationServiceAndroid;
 
+    private static final String TAG = "cr_invalidation";
+
     private InvalidationService(Context context, long nativeInvalidationServiceAndroid) {
         mContext = context.getApplicationContext();
         if (mContext == null) {
@@ -71,9 +76,19 @@
                 account, objectSources, objectNames);
         registerIntent.setClass(
                 mContext, InvalidationClientService.getRegisteredClass());
+
+        if (shouldRestrictBackgroundServices()) {
+            Log.e(TAG, "Failed to register objects");
+            return;
+        }
         mContext.startService(registerIntent);
     }
 
+    private boolean shouldRestrictBackgroundServices() {
+        // Restricts the use of background services when not in foreground. See crbug.com/680812.
+        return BuildInfo.isGreaterThanN() && !ApplicationStatus.hasVisibleActivities();
+    }
+
     /**
      * Fetches the Invalidator client name.
      *
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 300bb1d..129f1fe 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -27,6 +27,8 @@
     "drive_metrics_provider_win.cc",
     "enabled_state_provider.cc",
     "enabled_state_provider.h",
+    "environment_recorder.cc",
+    "environment_recorder.h",
     "execution_phase.cc",
     "execution_phase.h",
     "file_metrics_provider.cc",
@@ -73,6 +75,8 @@
     "persisted_logs_metrics_impl.h",
     "stability_metrics_helper.cc",
     "stability_metrics_helper.h",
+    "stability_metrics_provider.cc",
+    "stability_metrics_provider.h",
     "system_memory_stats_recorder.h",
     "system_memory_stats_recorder_linux.cc",
     "system_memory_stats_recorder_win.cc",
@@ -311,6 +315,7 @@
     "daily_event_unittest.cc",
     "data_use_tracker_unittest.cc",
     "drive_metrics_provider_unittest.cc",
+    "environment_recorder_unittest.cc",
     "file_metrics_provider_unittest.cc",
     "histogram_encoder_unittest.cc",
     "machine_id_provider_win_unittest.cc",
@@ -325,6 +330,7 @@
     "profiler/profiler_metrics_provider_unittest.cc",
     "profiler/tracking_synchronizer_unittest.cc",
     "stability_metrics_helper_unittest.cc",
+    "stability_metrics_provider_unittest.cc",
     "ui/screen_info_metrics_provider_unittest.cc",
   ]
 
diff --git a/components/metrics/clean_exit_beacon.cc b/components/metrics/clean_exit_beacon.cc
index 8868e0f..4bca5d1c 100644
--- a/components/metrics/clean_exit_beacon.cc
+++ b/components/metrics/clean_exit_beacon.cc
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "build/build_config.h"
 #include "components/metrics/metrics_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 
 #if defined(OS_WIN)
@@ -62,6 +63,11 @@
 CleanExitBeacon::~CleanExitBeacon() {
 }
 
+// static
+void CleanExitBeacon::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
+}
+
 void CleanExitBeacon::WriteBeaconValue(bool value) {
   local_state_->SetBoolean(prefs::kStabilityExitedCleanly, value);
 
diff --git a/components/metrics/clean_exit_beacon.h b/components/metrics/clean_exit_beacon.h
index 6b896fa1..e863e41e 100644
--- a/components/metrics/clean_exit_beacon.h
+++ b/components/metrics/clean_exit_beacon.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 
+class PrefRegistrySimple;
 class PrefService;
 
 namespace metrics {
@@ -32,6 +33,9 @@
   // Writes the provided beacon value.
   void WriteBeaconValue(bool exited_cleanly);
 
+  // Registers local state prefs used by this class.
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
  private:
   PrefService* const local_state_;
   const bool initial_value_;
diff --git a/components/metrics/environment_recorder.cc b/components/metrics/environment_recorder.cc
new file mode 100644
index 0000000..07ead8c
--- /dev/null
+++ b/components/metrics/environment_recorder.cc
@@ -0,0 +1,96 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/environment_recorder.h"
+
+#include "base/base64.h"
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/proto/system_profile.pb.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace metrics {
+
+namespace {
+
+// Computes a SHA-1 hash of |data| and returns it as a hex string.
+std::string ComputeSHA1(const std::string& data) {
+  const std::string sha1 = base::SHA1HashString(data);
+  return base::HexEncode(sha1.data(), sha1.size());
+}
+
+}  // namespace
+
+EnvironmentRecorder::EnvironmentRecorder(PrefService* local_state)
+    : local_state_(local_state) {}
+
+EnvironmentRecorder::~EnvironmentRecorder() = default;
+
+std::string EnvironmentRecorder::SerializeAndRecordEnvironmentToPrefs(
+    const SystemProfileProto& system_profile) {
+  std::string serialized_system_profile;
+  std::string base64_system_profile;
+  if (system_profile.SerializeToString(&serialized_system_profile)) {
+    // Persist the system profile to disk. In the event of an unclean shutdown,
+    // it will be used as part of the initial stability report.
+    base::Base64Encode(serialized_system_profile, &base64_system_profile);
+    local_state_->SetString(prefs::kStabilitySavedSystemProfile,
+                            base64_system_profile);
+    local_state_->SetString(prefs::kStabilitySavedSystemProfileHash,
+                            ComputeSHA1(serialized_system_profile));
+  }
+
+  return serialized_system_profile;
+}
+
+bool EnvironmentRecorder::LoadEnvironmentFromPrefs(
+    SystemProfileProto* system_profile) {
+  DCHECK(system_profile);
+
+  const std::string base64_system_profile =
+      local_state_->GetString(prefs::kStabilitySavedSystemProfile);
+  if (base64_system_profile.empty())
+    return false;
+  const std::string system_profile_hash =
+      local_state_->GetString(prefs::kStabilitySavedSystemProfileHash);
+
+  std::string serialized_system_profile;
+  return base::Base64Decode(base64_system_profile,
+                            &serialized_system_profile) &&
+         ComputeSHA1(serialized_system_profile) == system_profile_hash &&
+         system_profile->ParseFromString(serialized_system_profile);
+}
+
+void EnvironmentRecorder::ClearEnvironmentFromPrefs() {
+  local_state_->ClearPref(prefs::kStabilitySavedSystemProfile);
+  local_state_->ClearPref(prefs::kStabilitySavedSystemProfileHash);
+}
+
+int64_t EnvironmentRecorder::GetLastBuildtime() {
+  return local_state_->GetInt64(prefs::kStabilityStatsBuildTime);
+}
+
+std::string EnvironmentRecorder::GetLastVersion() {
+  return local_state_->GetString(prefs::kStabilityStatsVersion);
+}
+
+void EnvironmentRecorder::SetBuildtimeAndVersion(int64_t buildtime,
+                                                 const std::string& version) {
+  local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
+  local_state_->SetString(prefs::kStabilityStatsVersion, version);
+}
+
+// static
+void EnvironmentRecorder::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(prefs::kStabilitySavedSystemProfile,
+                               std::string());
+  registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
+                               std::string());
+  registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
+  registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
+}
+
+}  // namespace metrics
diff --git a/components/metrics/environment_recorder.h b/components/metrics/environment_recorder.h
new file mode 100644
index 0000000..0042d2e
--- /dev/null
+++ b/components/metrics/environment_recorder.h
@@ -0,0 +1,59 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_ENVIRONMENT_RECORDER_H_
+#define COMPONENTS_METRICS_ENVIRONMENT_RECORDER_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace metrics {
+
+class SystemProfileProto;
+
+// Stores system profile information to prefs for creating stability logs
+// in the next launch of chrome, and reads data from previous launches.
+class EnvironmentRecorder {
+ public:
+  explicit EnvironmentRecorder(PrefService* local_state);
+  ~EnvironmentRecorder();
+
+  // Serializes the system profile and records it in prefs for the next
+  // session.  Returns the uncompressed serialized proto for passing to crash
+  // reports, or the empty string if the proto can't be serialized.
+  std::string SerializeAndRecordEnvironmentToPrefs(
+      const SystemProfileProto& system_profile);
+
+  // Loads the system_profile data stored in a previous chrome session, and
+  // stores it in the |system_profile| object.
+  // Returns true iff a system profile was successfully read.
+  bool LoadEnvironmentFromPrefs(SystemProfileProto* system_profile);
+
+  // Deletes system profile data from prefs.
+  void ClearEnvironmentFromPrefs();
+
+  // Stores the buildtime of the current binary and version in prefs.
+  void SetBuildtimeAndVersion(int64_t buildtime, const std::string& version);
+
+  // Gets the buildtime stored in prefs.
+  int64_t GetLastBuildtime();
+
+  // Gets the version stored in prefs.
+  std::string GetLastVersion();
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ private:
+  PrefService* local_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(EnvironmentRecorder);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_ENVIRONMENT_RECORDER_H_
diff --git a/components/metrics/environment_recorder_unittest.cc b/components/metrics/environment_recorder_unittest.cc
new file mode 100644
index 0000000..5c2ae8b
--- /dev/null
+++ b/components/metrics/environment_recorder_unittest.cc
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/environment_recorder.h"
+
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/proto/system_profile.pb.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+class EnvironmentRecorderTest : public testing::Test {
+ public:
+  EnvironmentRecorderTest() {
+    EnvironmentRecorder::RegisterPrefs(prefs_.registry());
+  }
+
+  ~EnvironmentRecorderTest() override {}
+
+ protected:
+  TestingPrefServiceSimple prefs_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EnvironmentRecorderTest);
+};
+
+TEST_F(EnvironmentRecorderTest, LoadEnvironmentFromPrefs) {
+  const char* kSystemProfilePref = prefs::kStabilitySavedSystemProfile;
+  const char* kSystemProfileHashPref = prefs::kStabilitySavedSystemProfileHash;
+
+  // The pref value is empty, so loading it from prefs should fail.
+  {
+    EnvironmentRecorder recorder(&prefs_);
+    SystemProfileProto system_profile;
+    EXPECT_FALSE(recorder.LoadEnvironmentFromPrefs(&system_profile));
+    EXPECT_FALSE(system_profile.has_app_version());
+  }
+
+  // Do a RecordEnvironment() call and check whether the pref is recorded.
+  {
+    EnvironmentRecorder recorder(&prefs_);
+    SystemProfileProto system_profile;
+    system_profile.set_app_version("bogus version");
+    std::string serialized_profile =
+        recorder.SerializeAndRecordEnvironmentToPrefs(system_profile);
+    EXPECT_FALSE(serialized_profile.empty());
+    EXPECT_FALSE(prefs_.GetString(kSystemProfilePref).empty());
+    EXPECT_FALSE(prefs_.GetString(kSystemProfileHashPref).empty());
+  }
+
+  // Load it and check that it has the right value.
+  {
+    EnvironmentRecorder recorder(&prefs_);
+    SystemProfileProto system_profile;
+    EXPECT_TRUE(recorder.LoadEnvironmentFromPrefs(&system_profile));
+    EXPECT_EQ("bogus version", system_profile.app_version());
+    // Ensure that the call did not clear the prefs.
+    EXPECT_FALSE(prefs_.GetString(kSystemProfilePref).empty());
+    EXPECT_FALSE(prefs_.GetString(kSystemProfileHashPref).empty());
+  }
+
+  // Ensure that a non-matching hash results in the pref being invalid.
+  {
+    // Set the hash to a bad value.
+    prefs_.SetString(kSystemProfileHashPref, "deadbeef");
+    EnvironmentRecorder recorder(&prefs_);
+    SystemProfileProto system_profile;
+    EXPECT_FALSE(recorder.LoadEnvironmentFromPrefs(&system_profile));
+    EXPECT_FALSE(system_profile.has_app_version());
+  }
+}
+
+}  // namespace metrics
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc
index e2740cb..ac35ce3 100644
--- a/components/metrics/metrics_log.cc
+++ b/components/metrics/metrics_log.cc
@@ -9,19 +9,15 @@
 #include <algorithm>
 #include <string>
 
-#include "base/base64.h"
 #include "base/build_time.h"
 #include "base/cpu.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/metrics/metrics_hashes.h"
-#include "base/sha1.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "components/metrics/environment_recorder.h"
 #include "components/metrics/histogram_encoder.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_provider.h"
@@ -53,12 +49,6 @@
   return id.size() < 16;
 }
 
-// Computes a SHA-1 hash of |data| and returns it as a hex string.
-std::string ComputeSHA1(const std::string& data) {
-  const std::string sha1 = base::SHA1HashString(data);
-  return base::HexEncode(sha1.data(), sha1.size());
-}
-
 void WriteFieldTrials(const std::vector<ActiveGroupId>& field_trial_ids,
                       SystemProfileProto* system_profile) {
   for (std::vector<ActiveGroupId>::const_iterator it =
@@ -109,21 +99,7 @@
 
 // static
 void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
-  registry->RegisterIntegerPref(
-      prefs::kStabilityBreakpadRegistrationSuccess, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
-  registry->RegisterStringPref(prefs::kStabilitySavedSystemProfile,
-                               std::string());
-  registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
-                               std::string());
-  registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0);
-  registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0);
+  EnvironmentRecorder::RegisterPrefs(registry);
 }
 
 // static
@@ -210,20 +186,11 @@
   DCHECK(HasEnvironment());
   DCHECK(!HasStabilityMetrics());
 
-  PrefService* pref = local_state_;
-  DCHECK(pref);
-
-  // Get stability attributes out of Local State, zeroing out stored values.
-  // NOTE: This could lead to some data loss if this report isn't successfully
-  //       sent, but that's true for all the metrics.
-
-  WriteRequiredStabilityAttributes(pref);
-
   // Record recent delta for critical stability metrics.  We can't wait for a
   // restart to gather these, as that delay biases our observation away from
   // users that run happily for a looooong time.  We send increments with each
   // uma log upload, just as we send histogram data.
-  WriteRealtimeStabilityAttributes(pref, incremental_uptime, uptime);
+  WriteRealtimeStabilityAttributes(incremental_uptime, uptime);
 
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
   for (size_t i = 0; i < metrics_providers.size(); ++i) {
@@ -231,71 +198,6 @@
       metrics_providers[i]->ProvideInitialStabilityMetrics(system_profile);
     metrics_providers[i]->ProvideStabilityMetrics(system_profile);
   }
-
-  SystemProfileProto::Stability* stability =
-      system_profile->mutable_stability();
-
-  int incomplete_shutdown_count =
-      pref->GetInteger(prefs::kStabilityIncompleteSessionEndCount);
-  if (incomplete_shutdown_count) {
-    pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
-    stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
-  }
-
-  int breakpad_registration_success_count =
-      pref->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess);
-  if (breakpad_registration_success_count) {
-    pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
-    stability->set_breakpad_registration_success_count(
-        breakpad_registration_success_count);
-  }
-
-  int breakpad_registration_failure_count =
-      pref->GetInteger(prefs::kStabilityBreakpadRegistrationFail);
-  if (breakpad_registration_failure_count) {
-    pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
-    stability->set_breakpad_registration_failure_count(
-        breakpad_registration_failure_count);
-  }
-
-  int debugger_present_count =
-      pref->GetInteger(prefs::kStabilityDebuggerPresent);
-  if (debugger_present_count) {
-    pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
-    stability->set_debugger_present_count(debugger_present_count);
-  }
-
-  int debugger_not_present_count =
-      pref->GetInteger(prefs::kStabilityDebuggerNotPresent);
-  if (debugger_not_present_count) {
-    pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
-    stability->set_debugger_not_present_count(debugger_not_present_count);
-  }
-
-  // Note: only logging the following histograms for non-zero values.
-
-  int deferred_count = pref->GetInteger(prefs::kStabilityDeferredCount);
-  if (deferred_count) {
-    local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
-    UMA_STABILITY_HISTOGRAM_COUNTS_100(
-        "Stability.Internals.InitialStabilityLogDeferredCount", deferred_count);
-  }
-
-  int discard_count = local_state_->GetInteger(prefs::kStabilityDiscardCount);
-  if (discard_count) {
-    local_state_->SetInteger(prefs::kStabilityDiscardCount, 0);
-    UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount",
-                                       discard_count);
-  }
-
-  int version_mismatch_count =
-      local_state_->GetInteger(prefs::kStabilityVersionMismatchCount);
-  if (version_mismatch_count) {
-    local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
-    UMA_STABILITY_HISTOGRAM_COUNTS_100(
-        "Stability.Internals.VersionMismatchCount",
-        version_mismatch_count);
-  }
 }
 
 void MetricsLog::RecordGeneralMetrics(
@@ -344,26 +246,7 @@
   return uma_proto()->system_profile().stability().has_launch_count();
 }
 
-// The server refuses data that doesn't have certain values.  crashcount and
-// launchcount are currently "required" in the "stability" group.
-// TODO(isherman): Stop writing these attributes specially once the migration to
-// protobufs is complete.
-void MetricsLog::WriteRequiredStabilityAttributes(PrefService* pref) {
-  int launch_count = pref->GetInteger(prefs::kStabilityLaunchCount);
-  if (launch_count)
-    pref->SetInteger(prefs::kStabilityLaunchCount, 0);
-  int crash_count = pref->GetInteger(prefs::kStabilityCrashCount);
-  if (crash_count)
-    pref->SetInteger(prefs::kStabilityCrashCount, 0);
-
-  SystemProfileProto::Stability* stability =
-      uma_proto()->mutable_system_profile()->mutable_stability();
-  stability->set_launch_count(launch_count);
-  stability->set_crash_count(crash_count);
-}
-
 void MetricsLog::WriteRealtimeStabilityAttributes(
-    PrefService* pref,
     base::TimeDelta incremental_uptime,
     base::TimeDelta uptime) {
   // Update the stats which are critical for real-time stability monitoring.
@@ -419,41 +302,17 @@
   for (size_t i = 0; i < metrics_providers.size(); ++i)
     metrics_providers[i]->ProvideSystemProfileMetrics(system_profile);
 
-  std::string serialized_system_profile;
-  std::string base64_system_profile;
-  if (system_profile->SerializeToString(&serialized_system_profile)) {
-    // Persist the system profile to disk. In the event of an unclean shutdown,
-    // it will be used as part of the initial stability report.
-    base::Base64Encode(serialized_system_profile, &base64_system_profile);
-    PrefService* local_state = local_state_;
-    local_state->SetString(prefs::kStabilitySavedSystemProfile,
-                           base64_system_profile);
-    local_state->SetString(prefs::kStabilitySavedSystemProfileHash,
-                           ComputeSHA1(serialized_system_profile));
-  }
-
-  return serialized_system_profile;
+  EnvironmentRecorder recorder(local_state_);
+  return recorder.SerializeAndRecordEnvironmentToPrefs(*system_profile);
 }
 
 bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
   DCHECK(app_version);
   app_version->clear();
 
-  PrefService* local_state = local_state_;
-  const std::string base64_system_profile =
-      local_state->GetString(prefs::kStabilitySavedSystemProfile);
-  if (base64_system_profile.empty())
-    return false;
-  const std::string system_profile_hash =
-      local_state->GetString(prefs::kStabilitySavedSystemProfileHash);
-
   SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
-  std::string serialized_system_profile;
-
-  bool success =
-      base::Base64Decode(base64_system_profile, &serialized_system_profile) &&
-      ComputeSHA1(serialized_system_profile) == system_profile_hash &&
-      system_profile->ParseFromString(serialized_system_profile);
+  EnvironmentRecorder recorder(local_state_);
+  bool success = recorder.LoadEnvironmentFromPrefs(system_profile);
   if (success)
     *app_version = system_profile->app_version();
   return success;
diff --git a/components/metrics/metrics_log.h b/components/metrics/metrics_log.h
index 5a01964a..4f28b43 100644
--- a/components/metrics/metrics_log.h
+++ b/components/metrics/metrics_log.h
@@ -19,7 +19,6 @@
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
 
-class PrefRegistrySimple;
 class PrefService;
 
 namespace base {
@@ -173,15 +172,11 @@
   // call to RecordStabilityMetrics().
   bool HasStabilityMetrics() const;
 
-  // Within the stability group, write required attributes.
-  void WriteRequiredStabilityAttributes(PrefService* pref);
-
   // Within the stability group, write attributes that need to be updated asap
   // and can't be delayed until the user decides to restart chromium.
   // Delaying these stats would bias metrics away from happy long lived
   // chromium processes (ones that don't crash, and keep on running).
-  void WriteRealtimeStabilityAttributes(PrefService* pref,
-                                        base::TimeDelta incremental_uptime,
+  void WriteRealtimeStabilityAttributes(base::TimeDelta incremental_uptime,
                                         base::TimeDelta uptime);
 
   // closed_ is true when record has been packed up for sending, and should
diff --git a/components/metrics/metrics_log_unittest.cc b/components/metrics/metrics_log_unittest.cc
index 0d0274a..f1a7792 100644
--- a/components/metrics/metrics_log_unittest.cc
+++ b/components/metrics/metrics_log_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/sys_info.h"
 #include "base/time/time.h"
+#include "components/metrics/environment_recorder.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_state_manager.h"
 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
@@ -103,7 +104,7 @@
 class MetricsLogTest : public testing::Test {
  public:
   MetricsLogTest() {
-    MetricsLog::RegisterPrefs(prefs_.registry());
+    EnvironmentRecorder::RegisterPrefs(prefs_.registry());
     MetricsStateManager::RegisterPrefs(prefs_.registry());
   }
 
@@ -295,83 +296,12 @@
   CheckSystemProfile(log.system_profile());
 
   // Check that the system profile has also been written to prefs.
-  const std::string base64_system_profile =
-      prefs_.GetString(prefs::kStabilitySavedSystemProfile);
-  EXPECT_FALSE(base64_system_profile.empty());
-  std::string serialied_system_profile;
-  EXPECT_TRUE(base::Base64Decode(base64_system_profile,
-                                 &serialied_system_profile));
   SystemProfileProto decoded_system_profile;
-  EXPECT_TRUE(decoded_system_profile.ParseFromString(serialied_system_profile));
+  EnvironmentRecorder recorder(&prefs_);
+  EXPECT_TRUE(recorder.LoadEnvironmentFromPrefs(&decoded_system_profile));
   CheckSystemProfile(decoded_system_profile);
 }
 
-TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
-  const char* kSystemProfilePref = prefs::kStabilitySavedSystemProfile;
-  const char* kSystemProfileHashPref =
-      prefs::kStabilitySavedSystemProfileHash;
-
-  TestMetricsServiceClient client;
-  client.set_version_string("bogus version");
-
-  // The pref value is empty, so loading it from prefs should fail.
-  {
-    TestMetricsLog log(
-        kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
-    std::string app_version;
-    EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
-    EXPECT_TRUE(app_version.empty());
-  }
-
-  // Do a RecordEnvironment() call and check whether the pref is recorded.
-  {
-    TestMetricsLog log(
-        kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
-    log.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
-                          std::vector<variations::ActiveGroupId>(),
-                          kInstallDate, kEnabledDate);
-    EXPECT_FALSE(prefs_.GetString(kSystemProfilePref).empty());
-    EXPECT_FALSE(prefs_.GetString(kSystemProfileHashPref).empty());
-  }
-
-  {
-    TestMetricsLog log(
-        kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
-    std::string app_version;
-    EXPECT_TRUE(log.LoadSavedEnvironmentFromPrefs(&app_version));
-    EXPECT_EQ("bogus version", app_version);
-    // Check some values in the system profile.
-    EXPECT_EQ(kInstallDateExpected, log.system_profile().install_date());
-    EXPECT_EQ(kEnabledDateExpected, log.system_profile().uma_enabled_date());
-    // Ensure that the call did not clear the prefs.
-    EXPECT_FALSE(prefs_.GetString(kSystemProfilePref).empty());
-    EXPECT_FALSE(prefs_.GetString(kSystemProfileHashPref).empty());
-  }
-
-  // Ensure that a non-matching hash results in the pref being invalid.
-  {
-    TestMetricsLog log(
-        kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
-    // Call RecordEnvironment() to record the pref again.
-    log.RecordEnvironment(std::vector<std::unique_ptr<MetricsProvider>>(),
-                          std::vector<variations::ActiveGroupId>(),
-                          kInstallDate, kEnabledDate);
-  }
-
-  {
-    // Set the hash to a bad value.
-    prefs_.SetString(kSystemProfileHashPref, "deadbeef");
-    TestMetricsLog log(
-        kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
-    std::string app_version;
-    EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
-    EXPECT_TRUE(app_version.empty());
-    // Ensure that the prefs are not cleared, even if the call failed.
-    EXPECT_FALSE(prefs_.GetString(kSystemProfilePref).empty());
-    EXPECT_FALSE(prefs_.GetString(kSystemProfileHashPref).empty());
-  }
-}
-
 TEST_F(MetricsLogTest, RecordEnvironmentEnableDefault) {
   TestMetricsServiceClient client;
   TestMetricsLog log_unknown(kClientId, kSessionId, MetricsLog::ONGOING_LOG,
@@ -426,17 +356,6 @@
                         kEnabledDate);
   log.RecordStabilityMetrics(metrics_providers, base::TimeDelta(),
                              base::TimeDelta());
-  const SystemProfileProto_Stability& stability =
-      log.system_profile().stability();
-  // Required metrics:
-  EXPECT_TRUE(stability.has_launch_count());
-  EXPECT_TRUE(stability.has_crash_count());
-  // Initial log metrics: only expected if non-zero.
-  EXPECT_FALSE(stability.has_incomplete_shutdown_count());
-  EXPECT_FALSE(stability.has_breakpad_registration_success_count());
-  EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
-  EXPECT_FALSE(stability.has_debugger_present_count());
-  EXPECT_FALSE(stability.has_debugger_not_present_count());
 
   // The test provider should have been called upon to provide initial
   // stability and regular stability metrics.
@@ -456,17 +375,6 @@
                         kEnabledDate);
   log.RecordStabilityMetrics(metrics_providers, base::TimeDelta(),
                              base::TimeDelta());
-  const SystemProfileProto_Stability& stability =
-      log.system_profile().stability();
-  // Required metrics:
-  EXPECT_TRUE(stability.has_launch_count());
-  EXPECT_TRUE(stability.has_crash_count());
-  // Initial log metrics: only expected if non-zero.
-  EXPECT_FALSE(stability.has_incomplete_shutdown_count());
-  EXPECT_FALSE(stability.has_breakpad_registration_success_count());
-  EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
-  EXPECT_FALSE(stability.has_debugger_present_count());
-  EXPECT_FALSE(stability.has_debugger_not_present_count());
 
   // The test provider should have been called upon to provide regular but not
   // initial stability metrics.
diff --git a/components/metrics/metrics_pref_names.cc b/components/metrics/metrics_pref_names.cc
index c5ad9c6..ea3fd38 100644
--- a/components/metrics/metrics_pref_names.cc
+++ b/components/metrics/metrics_pref_names.cc
@@ -128,19 +128,10 @@
 const char kStabilityIncompleteSessionEndCount[] =
     "user_experience_metrics.stability.incomplete_session_end_count";
 
-// Time when the app was last known to be running, in seconds since
-// the epoch.
-const char kStabilityLastTimestampSec[] =
-    "user_experience_metrics.stability.last_timestamp_sec";
-
 // Number of times the application was launched since last report.
 const char kStabilityLaunchCount[] =
     "user_experience_metrics.stability.launch_count";
 
-// Time when the app was last launched, in seconds since the epoch.
-const char kStabilityLaunchTimeSec[] =
-    "user_experience_metrics.stability.launch_time_sec";
-
 // Number of times a page load event occurred since the last report.
 const char kStabilityPageLoadCount[] =
     "user_experience_metrics.stability.page_load_count";
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h
index df25e38..a918802 100644
--- a/components/metrics/metrics_pref_names.h
+++ b/components/metrics/metrics_pref_names.h
@@ -30,6 +30,8 @@
 extern const char kMetricsReportingEnabledTimestamp[];
 extern const char kMetricsSessionID[];
 extern const char kMetricsLastSeenPrefix[];
+
+// Preferences for recording stability logs.
 extern const char kStabilityBreakpadRegistrationSuccess[];
 extern const char kStabilityBreakpadRegistrationFail[];
 extern const char kStabilityChildProcessCrashCount[];
@@ -44,9 +46,7 @@
 extern const char kStabilityExtensionRendererLaunchCount[];
 extern const char kStabilityExitedCleanly[];
 extern const char kStabilityIncompleteSessionEndCount[];
-extern const char kStabilityLastTimestampSec[];
 extern const char kStabilityLaunchCount[];
-extern const char kStabilityLaunchTimeSec[];
 extern const char kStabilityPageLoadCount[];
 extern const char kStabilityRendererCrashCount[];
 extern const char kStabilityRendererFailedLaunchCount[];
@@ -58,6 +58,8 @@
 extern const char kStabilityStatsBuildTime[];
 extern const char kStabilityStatsVersion[];
 extern const char kStabilityVersionMismatchCount[];
+
+// Preferences for generating metrics at uninstall time.
 extern const char kUninstallLaunchCount[];
 extern const char kUninstallMetricsPageLoadCount[];
 extern const char kUninstallMetricsUptimeSec[];
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index 26c0d9b1..d7b5027 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -148,6 +148,7 @@
 #include "base/tracked_objects.h"
 #include "build/build_config.h"
 #include "components/metrics/data_use_tracker.h"
+#include "components/metrics/environment_recorder.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_log_manager.h"
 #include "components/metrics/metrics_log_uploader.h"
@@ -157,6 +158,7 @@
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/metrics_state_manager.h"
 #include "components/metrics/metrics_upload_scheduler.h"
+#include "components/metrics/stability_metrics_provider.h"
 #include "components/metrics/url_constants.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
@@ -235,19 +237,15 @@
 
 // static
 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
+  CleanExitBeacon::RegisterPrefs(registry);
   MetricsStateManager::RegisterPrefs(registry);
   MetricsLog::RegisterPrefs(registry);
+  StabilityMetricsProvider::RegisterPrefs(registry);
   DataUseTracker::RegisterPrefs(registry);
+  ExecutionPhaseManager::RegisterPrefs(registry);
 
   registry->RegisterInt64Pref(prefs::kInstallDate, 0);
 
-  registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
-  registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
-  registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
-  registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
-  registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
-  ExecutionPhaseManager::RegisterPrefs(registry);
-  registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
   registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
 
   registry->RegisterListPref(prefs::kMetricsInitialLogs);
@@ -284,6 +282,9 @@
   int64_t install_date = local_state_->GetInt64(prefs::kInstallDate);
   if (install_date == 0)
     local_state_->SetInt64(prefs::kInstallDate, base::Time::Now().ToTimeT());
+
+  RegisterMetricsProvider(std::unique_ptr<metrics::MetricsProvider>(
+      new StabilityMetricsProvider(local_state_)));
 }
 
 MetricsService::~MetricsService() {
@@ -505,36 +506,17 @@
 }
 
 void MetricsService::RecordBreakpadRegistration(bool success) {
-  if (!success)
-    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
-  else
-    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
+  StabilityMetricsProvider(local_state_).RecordBreakpadRegistration(success);
 }
 
 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
-  if (!has_debugger)
-    IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
-  else
-    IncrementPrefValue(prefs::kStabilityDebuggerPresent);
+  StabilityMetricsProvider(local_state_)
+      .RecordBreakpadHasDebugger(has_debugger);
 }
 
 void MetricsService::ClearSavedStabilityMetrics() {
   for (auto& provider : metrics_providers_)
     provider->ClearSavedStabilityMetrics();
-
-  // Reset the prefs that are managed by MetricsService/MetricsLog directly.
-  local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
-  local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
-  local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
-  local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
-  local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
-  local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
-  local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
-  local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
-  local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
-  // Note: kStabilityDiscardCount is not cleared as its intent is to measure
-  // the number of times data is discarded, even across versions.
-  local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
 }
 
 void MetricsService::PushExternalLog(const std::string& log) {
@@ -564,19 +546,12 @@
   const int64_t buildtime = MetricsLog::GetBuildTime();
   const std::string version = client_->GetVersionString();
 
-  // Delete deprecated prefs
-  // TODO(holte): Remove these in M58
-  local_state_->ClearPref(prefs::kStabilityLaunchTimeSec);
-  local_state_->ClearPref(prefs::kStabilityLastTimestampSec);
-
   bool version_changed = false;
-  int64_t previous_buildtime =
-      local_state_->GetInt64(prefs::kStabilityStatsBuildTime);
-  std::string previous_version =
-      local_state_->GetString(prefs::kStabilityStatsVersion);
+  EnvironmentRecorder recorder(local_state_);
+  int64_t previous_buildtime = recorder.GetLastBuildtime();
+  std::string previous_version = recorder.GetLastVersion();
   if (previous_buildtime != buildtime || previous_version != version) {
-    local_state_->SetString(prefs::kStabilityStatsVersion, version);
-    local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
+    recorder.SetBuildtimeAndVersion(buildtime, version);
     version_changed = true;
   }
 
@@ -584,8 +559,9 @@
 
   session_id_ = local_state_->GetInteger(prefs::kMetricsSessionID);
 
+  StabilityMetricsProvider provider(local_state_);
   if (!clean_exit_beacon_.exited_cleanly()) {
-    IncrementPrefValue(prefs::kStabilityCrashCount);
+    provider.LogCrash();
     // Reset flag, and wait until we call LogNeedForCleanShutdown() before
     // monitoring.
     clean_exit_beacon_.WriteBeaconValue(true);
@@ -608,7 +584,7 @@
     if (state_manager_->IsMetricsReportingEnabled()) {
       has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
       if (!has_initial_stability_log)
-        IncrementPrefValue(prefs::kStabilityDeferredCount);
+        provider.LogStabilityLogDeferred();
     }
   }
 
@@ -620,7 +596,7 @@
   // normally results in stats being accumulated).
   if (version_changed && !has_initial_stability_log) {
     ClearSavedStabilityMetrics();
-    IncrementPrefValue(prefs::kStabilityDiscardCount);
+    provider.LogStabilityDataDiscarded();
   }
 
   // If the version changed, the system profile is obsolete and needs to be
@@ -630,25 +606,17 @@
   // stability log, an operation that requires the previous version's system
   // profile. At this point, stability metrics pertaining to the previous
   // version have been cleared.
-  if (version_changed) {
-    local_state_->ClearPref(prefs::kStabilitySavedSystemProfile);
-    local_state_->ClearPref(prefs::kStabilitySavedSystemProfileHash);
-  }
+  if (version_changed)
+    recorder.ClearEnvironmentFromPrefs();
 
   // Update session ID.
   ++session_id_;
   local_state_->SetInteger(prefs::kMetricsSessionID, session_id_);
 
-  // Stability bookkeeping
-  IncrementPrefValue(prefs::kStabilityLaunchCount);
-
+  // Notify stability metrics providers about the launch.
+  provider.LogLaunch();
   SetExecutionPhase(ExecutionPhase::START_METRICS_RECORDING, local_state_);
-
-  if (!local_state_->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
-    IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
-    // This is marked false when we get a WM_ENDSESSION.
-    local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
-  }
+  provider.CheckLastSessionEndCompleted();
 
   // Call GetUptimes() for the first time, thus allowing all later calls
   // to record incremental uptimes accurately.
@@ -965,7 +933,7 @@
     return false;
   }
   if (system_profile_app_version != prefs_previous_version)
-    IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
+    StabilityMetricsProvider(local_state_).LogStabilityVersionMismatch();
 
   log_manager_.PauseCurrentLog();
   log_manager_.BeginLoggingWithLog(std::move(initial_stability_log));
@@ -1096,11 +1064,6 @@
   }
 }
 
-void MetricsService::IncrementPrefValue(const char* path) {
-  int value = local_state_->GetInteger(path);
-  local_state_->SetInteger(path, value + 1);
-}
-
 void MetricsService::IncrementLongPrefsValue(const char* path) {
   int64_t value = local_state_->GetInt64(path);
   local_state_->SetInt64(path, value + 1);
@@ -1252,7 +1215,7 @@
   client_->OnLogCleanShutdown();
   clean_exit_beacon_.WriteBeaconValue(true);
   SetExecutionPhase(ExecutionPhase::SHUTDOWN_COMPLETE, local_state_);
-  local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, end_completed);
+  StabilityMetricsProvider(local_state_).MarkSessionEndCompleted(end_completed);
 }
 
 }  // namespace metrics
diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h
index f283b23..42f311f 100644
--- a/components/metrics/metrics_service.h
+++ b/components/metrics/metrics_service.h
@@ -332,9 +332,6 @@
   // Called after transmission completes (either successfully or with failure).
   void OnLogUploadComplete(int response_code);
 
-  // Reads, increments and then sets the specified integer preference.
-  void IncrementPrefValue(const char* path);
-
   // Reads, increments and then sets the specified long preference that is
   // stored as a string.
   void IncrementLongPrefsValue(const char* path);
diff --git a/components/metrics/metrics_service_unittest.cc b/components/metrics/metrics_service_unittest.cc
index f4a264ca..2d5e32fd 100644
--- a/components/metrics/metrics_service_unittest.cc
+++ b/components/metrics/metrics_service_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/metrics/client_info.h"
+#include "components/metrics/environment_recorder.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_state_manager.h"
@@ -212,10 +213,9 @@
 
   // Record stability build time and version from previous session, so that
   // stability metrics (including exited cleanly flag) won't be cleared.
-  GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime,
-                            MetricsLog::GetBuildTime());
-  GetLocalState()->SetString(prefs::kStabilityStatsVersion,
-                             client.GetVersionString());
+  EnvironmentRecorder(GetLocalState())
+      .SetBuildtimeAndVersion(MetricsLog::GetBuildTime(),
+                              client.GetVersionString());
 
   // Set the clean exit flag, as that will otherwise cause a stabilty
   // log to be produced, irrespective provider requests.
@@ -284,10 +284,9 @@
 
   // Record stability build time and version from previous session, so that
   // stability metrics (including exited cleanly flag) won't be cleared.
-  GetLocalState()->SetInt64(prefs::kStabilityStatsBuildTime,
-                            MetricsLog::GetBuildTime());
-  GetLocalState()->SetString(prefs::kStabilityStatsVersion,
-                             client.GetVersionString());
+  EnvironmentRecorder(GetLocalState())
+      .SetBuildtimeAndVersion(MetricsLog::GetBuildTime(),
+                              client.GetVersionString());
 
   GetLocalState()->SetBoolean(prefs::kStabilityExitedCleanly, false);
 
diff --git a/components/metrics/stability_metrics_provider.cc b/components/metrics/stability_metrics_provider.cc
new file mode 100644
index 0000000..a4b5280
--- /dev/null
+++ b/components/metrics/stability_metrics_provider.cc
@@ -0,0 +1,179 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/stability_metrics_provider.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/proto/system_profile.pb.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace metrics {
+
+StabilityMetricsProvider::StabilityMetricsProvider(PrefService* local_state)
+    : local_state_(local_state) {}
+
+StabilityMetricsProvider::~StabilityMetricsProvider() = default;
+
+// static
+void StabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
+  registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
+  registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess,
+                                0);
+  registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0);
+  registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0);
+}
+
+void StabilityMetricsProvider::ClearSavedStabilityMetrics() {
+  local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
+  local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+  local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+  local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+  local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+  local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+  local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
+  local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
+  local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+  // Note: kStabilityDiscardCount is not cleared as its intent is to measure
+  // the number of times data is discarded, even across versions.
+  local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
+}
+
+void StabilityMetricsProvider::ProvideStabilityMetrics(
+    SystemProfileProto* system_profile) {
+  SystemProfileProto::Stability* stability =
+      system_profile->mutable_stability();
+
+  int launch_count = local_state_->GetInteger(prefs::kStabilityLaunchCount);
+  if (launch_count) {
+    local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
+    stability->set_launch_count(launch_count);
+  }
+  int crash_count = local_state_->GetInteger(prefs::kStabilityCrashCount);
+  if (crash_count) {
+    local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
+    stability->set_crash_count(crash_count);
+  }
+
+  int incomplete_shutdown_count =
+      local_state_->GetInteger(prefs::kStabilityIncompleteSessionEndCount);
+  if (incomplete_shutdown_count) {
+    local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+    stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
+  }
+
+  int breakpad_registration_success_count =
+      local_state_->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess);
+  if (breakpad_registration_success_count) {
+    local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+    stability->set_breakpad_registration_success_count(
+        breakpad_registration_success_count);
+  }
+
+  int breakpad_registration_failure_count =
+      local_state_->GetInteger(prefs::kStabilityBreakpadRegistrationFail);
+  if (breakpad_registration_failure_count) {
+    local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+    stability->set_breakpad_registration_failure_count(
+        breakpad_registration_failure_count);
+  }
+
+  int debugger_present_count =
+      local_state_->GetInteger(prefs::kStabilityDebuggerPresent);
+  if (debugger_present_count) {
+    local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+    stability->set_debugger_present_count(debugger_present_count);
+  }
+
+  int debugger_not_present_count =
+      local_state_->GetInteger(prefs::kStabilityDebuggerNotPresent);
+  if (debugger_not_present_count) {
+    local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+    stability->set_debugger_not_present_count(debugger_not_present_count);
+  }
+
+  // Note: only logging the following histograms for non-zero values.
+  int deferred_count = local_state_->GetInteger(prefs::kStabilityDeferredCount);
+  if (deferred_count) {
+    local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+    UMA_STABILITY_HISTOGRAM_COUNTS_100(
+        "Stability.Internals.InitialStabilityLogDeferredCount", deferred_count);
+  }
+
+  int discard_count = local_state_->GetInteger(prefs::kStabilityDiscardCount);
+  if (discard_count) {
+    local_state_->SetInteger(prefs::kStabilityDiscardCount, 0);
+    UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount",
+                                       discard_count);
+  }
+
+  int version_mismatch_count =
+      local_state_->GetInteger(prefs::kStabilityVersionMismatchCount);
+  if (version_mismatch_count) {
+    local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
+    UMA_STABILITY_HISTOGRAM_COUNTS_100(
+        "Stability.Internals.VersionMismatchCount", version_mismatch_count);
+  }
+}
+
+void StabilityMetricsProvider::RecordBreakpadRegistration(bool success) {
+  if (!success)
+    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
+  else
+    IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
+}
+
+void StabilityMetricsProvider::RecordBreakpadHasDebugger(bool has_debugger) {
+  if (!has_debugger)
+    IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
+  else
+    IncrementPrefValue(prefs::kStabilityDebuggerPresent);
+}
+
+void StabilityMetricsProvider::CheckLastSessionEndCompleted() {
+  if (!local_state_->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
+    IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
+    // This is marked false when we get a WM_ENDSESSION.
+    MarkSessionEndCompleted(true);
+  }
+}
+
+void StabilityMetricsProvider::MarkSessionEndCompleted(bool end_completed) {
+  local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, end_completed);
+}
+
+void StabilityMetricsProvider::LogCrash() {
+  IncrementPrefValue(prefs::kStabilityCrashCount);
+}
+
+void StabilityMetricsProvider::LogStabilityLogDeferred() {
+  IncrementPrefValue(prefs::kStabilityDeferredCount);
+}
+
+void StabilityMetricsProvider::LogStabilityDataDiscarded() {
+  IncrementPrefValue(prefs::kStabilityDiscardCount);
+}
+
+void StabilityMetricsProvider::LogLaunch() {
+  IncrementPrefValue(prefs::kStabilityLaunchCount);
+}
+
+void StabilityMetricsProvider::LogStabilityVersionMismatch() {
+  IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
+}
+
+void StabilityMetricsProvider::IncrementPrefValue(const char* path) {
+  int value = local_state_->GetInteger(path);
+  local_state_->SetInteger(path, value + 1);
+}
+
+}  // namespace metrics
diff --git a/components/metrics/stability_metrics_provider.h b/components/metrics/stability_metrics_provider.h
new file mode 100644
index 0000000..4e16ed67
--- /dev/null
+++ b/components/metrics/stability_metrics_provider.h
@@ -0,0 +1,53 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_STABILITY_METRICS_PROVIDER_H_
+#define COMPONENTS_METRICS_STABILITY_METRICS_PROVIDER_H_
+
+#include "components/metrics/metrics_provider.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace metrics {
+
+class SystemProfileProto;
+
+// Stores and loads system information to prefs for stability logs.
+class StabilityMetricsProvider : public MetricsProvider {
+ public:
+  StabilityMetricsProvider(PrefService* local_state);
+  ~StabilityMetricsProvider() override;
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  void RecordBreakpadRegistration(bool success);
+  void RecordBreakpadHasDebugger(bool has_debugger);
+
+  void CheckLastSessionEndCompleted();
+  void MarkSessionEndCompleted(bool end_completed);
+
+  void LogCrash();
+  void LogStabilityLogDeferred();
+  void LogStabilityDataDiscarded();
+  void LogLaunch();
+  void LogStabilityVersionMismatch();
+
+ private:
+  // Increments an Integer pref value specified by |path|.
+  void IncrementPrefValue(const char* path);
+
+  // MetricsProvider:
+  void ClearSavedStabilityMetrics() override;
+  void ProvideStabilityMetrics(
+      SystemProfileProto* system_profile_proto) override;
+
+  PrefService* local_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(StabilityMetricsProvider);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_STABILITY_METRICS_PROVIDER_H_
diff --git a/components/metrics/stability_metrics_provider_unittest.cc b/components/metrics/stability_metrics_provider_unittest.cc
new file mode 100644
index 0000000..7b2cb61
--- /dev/null
+++ b/components/metrics/stability_metrics_provider_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/stability_metrics_provider.h"
+
+#include "components/metrics/proto/system_profile.pb.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+class StabilityMetricsProviderTest : public testing::Test {
+ public:
+  StabilityMetricsProviderTest() {
+    StabilityMetricsProvider::RegisterPrefs(prefs_.registry());
+  }
+
+  ~StabilityMetricsProviderTest() override {}
+
+ protected:
+  TestingPrefServiceSimple prefs_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StabilityMetricsProviderTest);
+};
+
+TEST_F(StabilityMetricsProviderTest, ProvideStabilityMetrics) {
+  StabilityMetricsProvider stability_provider(&prefs_);
+  MetricsProvider* provider = &stability_provider;
+  SystemProfileProto system_profile;
+  provider->ProvideStabilityMetrics(&system_profile);
+
+  const SystemProfileProto_Stability& stability = system_profile.stability();
+  // Initial log metrics: only expected if non-zero.
+  EXPECT_FALSE(stability.has_launch_count());
+  EXPECT_FALSE(stability.has_crash_count());
+  EXPECT_FALSE(stability.has_incomplete_shutdown_count());
+  EXPECT_FALSE(stability.has_breakpad_registration_success_count());
+  EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
+  EXPECT_FALSE(stability.has_debugger_present_count());
+  EXPECT_FALSE(stability.has_debugger_not_present_count());
+}
+
+TEST_F(StabilityMetricsProviderTest, RecordStabilityMetrics) {
+  {
+    StabilityMetricsProvider recorder(&prefs_);
+    recorder.LogLaunch();
+    recorder.LogCrash();
+    recorder.MarkSessionEndCompleted(false);
+    recorder.CheckLastSessionEndCompleted();
+    recorder.RecordBreakpadRegistration(true);
+    recorder.RecordBreakpadRegistration(false);
+    recorder.RecordBreakpadHasDebugger(true);
+    recorder.RecordBreakpadHasDebugger(false);
+  }
+
+  {
+    StabilityMetricsProvider stability_provider(&prefs_);
+    MetricsProvider* provider = &stability_provider;
+    SystemProfileProto system_profile;
+    provider->ProvideStabilityMetrics(&system_profile);
+
+    const SystemProfileProto_Stability& stability = system_profile.stability();
+    // Initial log metrics: only expected if non-zero.
+    EXPECT_EQ(1, stability.launch_count());
+    EXPECT_EQ(1, stability.crash_count());
+    EXPECT_EQ(1, stability.incomplete_shutdown_count());
+    EXPECT_EQ(1, stability.breakpad_registration_success_count());
+    EXPECT_EQ(1, stability.breakpad_registration_failure_count());
+    EXPECT_EQ(1, stability.debugger_present_count());
+    EXPECT_EQ(1, stability.debugger_not_present_count());
+  }
+}
+
+}  // namespace metrics
diff --git a/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index e28cf28..433dd40 100644
--- a/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -433,7 +433,7 @@
   proto.set_score(0.1f);
   proto.set_dismissed(false);
   proto.set_remote_category_id(1);
-  auto source = proto.add_sources();
+  auto* source = proto.add_sources();
   source->set_url("http://cool-suggestions.com/");
   source->set_publisher_name("Great Suggestions Inc.");
   source->set_amp_url("http://cdn.ampproject.org/c/foo/");
diff --git a/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc b/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc
index deb218a..d4ec38e 100644
--- a/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc
+++ b/components/ntp_snippets/remote/scheduling_remote_suggestions_provider.cc
@@ -539,8 +539,8 @@
 
   std::set<TriggerType> enabled_types;
   for (const auto& token : tokens) {
-    auto it = std::find(std::begin(kTriggerTypeNames),
-                        std::end(kTriggerTypeNames), token);
+    auto** it = std::find(std::begin(kTriggerTypeNames),
+                          std::end(kTriggerTypeNames), token);
     if (it == std::end(kTriggerTypeNames)) {
       DLOG(WARNING) << "Failed to parse variation param "
                     << kTriggerTypesParamName << " with string value "
diff --git a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
index e87440e2..43a90e9 100644
--- a/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
+++ b/components/ntp_tiles/webui/ntp_tiles_internals_message_handler.cc
@@ -177,7 +177,7 @@
   }
 
   if (most_visited_sites_->DoesSourceExist(NTPTileSource::POPULAR)) {
-    auto popular_sites = most_visited_sites_->popular_sites();
+    auto* popular_sites = most_visited_sites_->popular_sites();
     value.SetString("popular.url", popular_sites->GetURLToFetch().spec());
     value.SetString("popular.country", popular_sites->GetCountryToFetch());
     value.SetString("popular.version", popular_sites->GetVersionToFetch());
diff --git a/components/omnibox/browser/history_quick_provider_performance_unittest.cc b/components/omnibox/browser/history_quick_provider_performance_unittest.cc
index a682703..f15f305 100644
--- a/components/omnibox/browser/history_quick_provider_performance_unittest.cc
+++ b/components/omnibox/browser/history_quick_provider_performance_unittest.cc
@@ -148,7 +148,7 @@
 void HQPPerfTestOnePopularURL::PrintMeasurements(
     const std::string& trace_name,
     const std::vector<base::TimeDelta>& measurements) {
-  auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
+  auto* test_info = ::testing::UnitTest::GetInstance()->current_test_info();
 
   std::string durations;
   for (const auto& measurement : measurements)
diff --git a/components/password_manager/content/browser/credential_manager_impl.cc b/components/password_manager/content/browser/credential_manager_impl.cc
index 7c01bea..fcd6940a 100644
--- a/components/password_manager/content/browser/credential_manager_impl.cc
+++ b/components/password_manager/content/browser/credential_manager_impl.cc
@@ -104,8 +104,7 @@
     // If this is a federated credential, check it against the federated matches
     // produced by the PasswordFormManager. If a match is found, update it and
     // return.
-    for (const auto& match :
-         form_manager_->form_fetcher()->GetFederatedMatches()) {
+    for (auto* match : form_manager_->form_fetcher()->GetFederatedMatches()) {
       if (match->username_value == form.username_value &&
           match->federation_origin.IsSameOriginWith(form.federation_origin)) {
         form_manager_->Update(*match);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index f6670796..8c6eb9e2 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1288,7 +1288,7 @@
     DCHECK(best_matches_.end() != updated_password_it);
     const base::string16& old_password =
         updated_password_it->second->password_value;
-    for (const auto& not_best_match : not_best_matches_) {
+    for (auto* not_best_match : not_best_matches_) {
       if (not_best_match->username_value ==
               pending_credentials_.username_value &&
           not_best_match->password_value == old_password) {
diff --git a/components/payments/payment_request.cc b/components/payments/payment_request.cc
index 9ea28a8..0ad6167 100644
--- a/components/payments/payment_request.cc
+++ b/components/payments/payment_request.cc
@@ -31,7 +31,8 @@
       manager_(manager),
       binding_(this, std::move(request)),
       selected_shipping_profile_(nullptr),
-      selected_contact_profile_(nullptr) {
+      selected_contact_profile_(nullptr),
+      selected_credit_card_(nullptr) {
   // OnConnectionTerminated will be called when the Mojo pipe is closed. This
   // will happen as a result of many renderer-side events (both successful and
   // erroneous in nature).
@@ -128,20 +129,8 @@
   return contact_profiles_;
 }
 
-autofill::CreditCard* PaymentRequest::GetCurrentlySelectedCreditCard() {
-  // TODO(anthonyvd): Change this code to prioritize server cards and implement
-  // a way to modify this function's return value.
-  const std::vector<autofill::CreditCard*> cards =
-      personal_data_manager()->GetCreditCardsToSuggest();
-
-  auto first_complete_card = std::find_if(
-      cards.begin(),
-      cards.end(),
-      [] (autofill::CreditCard* card) {
-        return card->IsValid();
-  });
-
-  return first_complete_card == cards.end() ? nullptr : *first_complete_card;
+const std::vector<autofill::CreditCard*>& PaymentRequest::credit_cards() {
+  return credit_cards_;
 }
 
 void PaymentRequest::PopulateProfileCache() {
@@ -150,7 +139,7 @@
 
   // PaymentRequest may outlive the Profiles returned by the Data Manager.
   // Thus, we store copies, and return a vector of pointers to these copies
-  // whenever Profiles are requested.
+  // whenever Profiles are requested. The same is true for credit cards.
   for (size_t i = 0; i < profiles.size(); i++) {
     profile_cache_.push_back(
         base::MakeUnique<autofill::AutofillProfile>(*profiles[i]));
@@ -160,6 +149,13 @@
     shipping_profiles_.push_back(profile_cache_[i].get());
     contact_profiles_.push_back(profile_cache_[i].get());
   }
+
+  const std::vector<autofill::CreditCard*>& cards =
+      personal_data_manager()->GetCreditCardsToSuggest();
+  for (autofill::CreditCard* card : cards) {
+    card_cache_.push_back(base::MakeUnique<autofill::CreditCard>(*card));
+    credit_cards_.push_back(card_cache_.back().get());
+  }
 }
 
 void PaymentRequest::SetDefaultProfileSelections() {
@@ -168,6 +164,16 @@
 
   if (!contact_profiles().empty())
     set_selected_contact_profile(contact_profiles()[0]);
+
+  // TODO(anthonyvd): Change this code to prioritize server cards and implement
+  // a way to modify this function's return value.
+  const std::vector<autofill::CreditCard*> cards = credit_cards();
+  auto first_complete_card =
+      std::find_if(cards.begin(), cards.end(),
+                   [](autofill::CreditCard* card) { return card->IsValid(); });
+
+  selected_credit_card_ =
+      first_complete_card == cards.end() ? nullptr : *first_complete_card;
 }
 
 void PaymentRequest::PopulateValidatedMethodData(
diff --git a/components/payments/payment_request.h b/components/payments/payment_request.h
index bde05954..fcb58203 100644
--- a/components/payments/payment_request.h
+++ b/components/payments/payment_request.h
@@ -91,10 +91,12 @@
     selected_contact_profile_ = profile;
   }
 
+  const std::vector<autofill::CreditCard*>& credit_cards();
+
   // Returns the currently selected credit card for this PaymentRequest flow.
   // It's not guaranteed to be complete. Returns nullptr if there is no selected
   // card.
-  autofill::CreditCard* GetCurrentlySelectedCreditCard();
+  autofill::CreditCard* selected_credit_card() { return selected_credit_card_; }
 
   autofill::PersonalDataManager* personal_data_manager() {
     return delegate_->GetPersonalDataManager();
@@ -111,7 +113,8 @@
   // and stores copies of them, owned by this Request, in profile_cache_.
   void PopulateProfileCache();
 
-  // Sets the default values for the selected Shipping and Contact profiles.
+  // Sets the default values for the selected Shipping and Contact profiles, as
+  // well as the selected Credit Card.
   void SetDefaultProfileSelections();
 
   // Validates the |method_data| and fills |supported_card_networks_|.
@@ -137,6 +140,9 @@
   std::vector<autofill::AutofillProfile*> contact_profiles_;
   autofill::AutofillProfile* selected_shipping_profile_;
   autofill::AutofillProfile* selected_contact_profile_;
+  std::vector<std::unique_ptr<autofill::CreditCard>> card_cache_;
+  std::vector<autofill::CreditCard*> credit_cards_;
+  autofill::CreditCard* selected_credit_card_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequest);
 };
diff --git a/components/payments_strings.grdp b/components/payments_strings.grdp
index a1d35c8..77b7791 100644
--- a/components/payments_strings.grdp
+++ b/components/payments_strings.grdp
@@ -184,6 +184,9 @@
   <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported. Shipping is typically used for packages." formatter_data="android_java">
     Unsupported shipping address. Select a different address.
   </message>
+  <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION" desc="Text implying that a user needs to pick a different shipping option, because the currently selected option is not supported. Shipping is typically used for packages." formatter_data="android_java">
+    That shipping option isn’t available. Try a different option.
+  </message>
 
   <!-- Delivery address in web payments API -->
   <message name="IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL" desc="The title for the section of delivery information. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
@@ -201,6 +204,9 @@
   <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS" desc="Text implying that a user needs to pick a different delivery address, because the currently selected address is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
     Unsupported delivery address. Select a different address.
   </message>
+  <message name="IDS_PAYMENTS_UNSUPPORTED_DELIVERY_OPTION" desc="Text implying that a user needs to pick a different delivery option, because the currently selected option is not supported. Delivery is commonly faster than shipping. For example, it might be used for food delivery." formatter_data="android_java">
+    That delivery option isn’t available. Try a different option.
+  </message>
 
   <!-- Pickup address in web payments API -->
   <message name="IDS_PAYMENTS_PICKUP_SUMMARY_LABEL" desc="The title for the section of pickup information. For example, this could be the address for laundry pickup." formatter_data="android_java">
@@ -218,6 +224,9 @@
   <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS" desc="Text implying that a user needs to choose a different pickup address, because the currently selected address is not supported. This address can be used, for example, for laundry pickup." formatter_data="android_java">
     Unsupported pickup address. Select a different address.
   </message>
+  <message name="IDS_PAYMENTS_UNSUPPORTED_PICKUP_OPTION" desc="Text implying that a user needs to choose a different pickup option, because the currently selected option is not supported. This option can be used, for example, for laundry pickup." formatter_data="android_java">
+    That pickup option isn’t available. Try a different option.
+  </message>
   <message name="IDS_PAYMENTS_ANDROID_APP_ERROR" desc="Error message that is shown when an Android payment application fails to start." formatter_data="android_java">
     Unable to launch payment app.
   </message>
diff --git a/components/physical_web_ui_strings.grdp b/components/physical_web_ui_strings.grdp
index cc34d51..cc5e09f 100644
--- a/components/physical_web_ui_strings.grdp
+++ b/components/physical_web_ui_strings.grdp
@@ -3,4 +3,10 @@
   <message name="IDS_PHYSICAL_WEB_UI_TITLE" desc="Title of a built-in page that displays a list of Physical Web URLs (URLs broadcast by nearby devices).">
     Physical Web
   </message>
+  <message name="IDS_PHYSICAL_WEB_UI_EMPTY_MESSAGE" desc="The message displayed in place of a list of nearby URLs when there are no URLs to display.">
+    No Physical Web pages to show
+  </message>
+  <message name="IDS_PHYSICAL_WEB_UI_SCANNING_MESSAGE" desc="The message displayed in place of a list of nearby URLs while still scanning for nearby URLs.">
+    Looking for nearby Physical Web pages
+  </message>
 </grit-part>
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc
index afdcffb0..53cdc09 100644
--- a/components/policy/core/common/policy_service_impl.cc
+++ b/components/policy/core/common/policy_service_impl.cc
@@ -78,7 +78,7 @@
   for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain)
     initialization_complete_[domain] = true;
   providers_ = providers;
-  for (auto provider : providers) {
+  for (auto* provider : providers) {
     provider->AddObserver(this);
     for (int domain = 0; domain < POLICY_DOMAIN_SIZE; ++domain) {
       initialization_complete_[domain] &=
@@ -92,7 +92,7 @@
 
 PolicyServiceImpl::~PolicyServiceImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  for (auto provider : providers_)
+  for (auto* provider : providers_)
     provider->RemoveObserver(this);
 }
 
@@ -147,9 +147,9 @@
   } else {
     // Some providers might invoke OnUpdatePolicy synchronously while handling
     // RefreshPolicies. Mark all as pending before refreshing.
-    for (auto provider : providers_)
+    for (auto* provider : providers_)
       refresh_pending_.insert(provider);
-    for (auto provider : providers_)
+    for (auto* provider : providers_)
       provider->RefreshPolicies();
   }
 }
@@ -188,7 +188,7 @@
   // Merge from each provider in their order of priority.
   const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
   PolicyBundle bundle;
-  for (auto provider : providers_) {
+  for (auto* provider : providers_) {
     PolicyBundle provided_bundle;
     provided_bundle.CopyFrom(provider->policies());
     RemapProxyPolicies(&provided_bundle.Get(chrome_namespace));
@@ -248,7 +248,7 @@
     PolicyDomain policy_domain = static_cast<PolicyDomain>(domain);
 
     bool all_complete = true;
-    for (auto provider : providers_) {
+    for (auto* provider : providers_) {
       if (!provider->IsInitializationComplete(policy_domain)) {
         all_complete = false;
         break;
diff --git a/components/precache/core/precache_fetcher.cc b/components/precache/core/precache_fetcher.cc
index 0bc2e1b..e84c4d5 100644
--- a/components/precache/core/precache_fetcher.cc
+++ b/components/precache/core/precache_fetcher.cc
@@ -486,12 +486,12 @@
       unfinished_work_->add_top_host()->set_hostname(top_host.hostname);
   }
   for (const auto& resource : resources_fetching_) {
-    auto new_resource = unfinished_work_->add_resource();
+    auto* new_resource = unfinished_work_->add_resource();
     new_resource->set_url(resource.url.spec());
     new_resource->set_top_host_name(resource.referrer);
   }
   for (const auto& resource : resources_to_fetch_) {
-    auto new_resource = unfinished_work_->add_resource();
+    auto* new_resource = unfinished_work_->add_resource();
     new_resource->set_url(resource.url.spec());
     new_resource->set_top_host_name(resource.referrer);
   }
diff --git a/components/renderer_context_menu/render_view_context_menu_base.cc b/components/renderer_context_menu/render_view_context_menu_base.cc
index a3e0e50..2b7e0ca 100644
--- a/components/renderer_context_menu/render_view_context_menu_base.cc
+++ b/components/renderer_context_menu/render_view_context_menu_base.cc
@@ -393,11 +393,10 @@
   if (!extra_headers.empty())
     open_url_params.extra_headers = extra_headers;
 
-  WebContents* new_contents = source_web_contents_->OpenURL(open_url_params);
-  if (!new_contents)
-    return;
+  open_url_params.source_render_process_id = render_process_id_;
+  open_url_params.source_render_frame_id = render_frame_id_;
 
-  NotifyURLOpened(url, new_contents);
+  source_web_contents_->OpenURL(open_url_params);
 }
 
 bool RenderViewContextMenuBase::IsCustomItemChecked(int id) const {
diff --git a/components/renderer_context_menu/render_view_context_menu_base.h b/components/renderer_context_menu/render_view_context_menu_base.h
index 84fcfe5..849b29c3 100644
--- a/components/renderer_context_menu/render_view_context_menu_base.h
+++ b/components/renderer_context_menu/render_view_context_menu_base.h
@@ -142,8 +142,6 @@
 
   // Subclasses should send notification.
   virtual void NotifyMenuShown() = 0;
-  virtual void NotifyURLOpened(const GURL& url,
-                               content::WebContents* new_contents) = 0;
 
   // TODO(oshima): Remove this.
   virtual void AppendPlatformEditableItems() {}
diff --git a/components/search_engines/default_search_policy_handler_unittest.cc b/components/search_engines/default_search_policy_handler_unittest.cc
index 6db8390..70d8a83 100644
--- a/components/search_engines/default_search_policy_handler_unittest.cc
+++ b/components/search_engines/default_search_policy_handler_unittest.cc
@@ -167,7 +167,7 @@
   PolicyMap policy;
   BuildDefaultSearchPolicy(&policy);
 
-  for (auto policy_name : kPolicyNamesToCheck) {
+  for (auto* policy_name : kPolicyNamesToCheck) {
     // Check that policy can be successfully applied first.
     UpdateProviderPolicy(policy);
     const base::Value* temp = nullptr;
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index 7bdebd6..231c7aef 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -733,7 +733,7 @@
       "chrome-extension://some-extension", "file:///var/www/index.html"};
   const char* supported_urls[] = {"http://example.test",
                                   "https://example.test"};
-  for (const auto url : unsupported_urls) {
+  for (auto* url : unsupported_urls) {
     SCOPED_TRACE(url);
     RedirectChainMatchPattern expected_pattern = EMPTY;
     NavigateAndExpectActivation(
@@ -742,7 +742,7 @@
             ? ActivationDecision::ACTIVATION_DISABLED
             : ActivationDecision::UNSUPPORTED_SCHEME);
   }
-  for (const auto url : supported_urls) {
+  for (auto* url : supported_urls) {
     SCOPED_TRACE(url);
     RedirectChainMatchPattern expected_pattern =
         test_data.url_matches_activation_list ? NO_REDIRECTS_HIT : EMPTY;
diff --git a/components/subresource_filter/core/common/first_party_origin_unittest.cc b/components/subresource_filter/core/common/first_party_origin_unittest.cc
index 02ba302..b8f02e1 100644
--- a/components/subresource_filter/core/common/first_party_origin_unittest.cc
+++ b/components/subresource_filter/core/common/first_party_origin_unittest.cc
@@ -72,7 +72,7 @@
   };
 
   FirstPartyOrigin first_party(url::Origin(GURL("https://example.com")));
-  for (const auto& url_string : kUrls) {
+  for (auto* url_string : kUrls) {
     GURL url(url_string);
     EXPECT_TRUE(FirstPartyOrigin::IsThirdParty(url, first_party.origin()));
     EXPECT_TRUE(first_party.IsThirdParty(url));
diff --git a/components/subresource_filter/core/common/test_ruleset_creator.cc b/components/subresource_filter/core/common/test_ruleset_creator.cc
index 81aabf8..d87cf1b4 100644
--- a/components/subresource_filter/core/common/test_ruleset_creator.cc
+++ b/components/subresource_filter/core/common/test_ruleset_creator.cc
@@ -41,7 +41,7 @@
     ruleset_writer.AddUrlRule(rule);
   ruleset_writer.Finish();
 
-  auto data = reinterpret_cast<const uint8_t*>(ruleset_contents.data());
+  auto* data = reinterpret_cast<const uint8_t*>(ruleset_contents.data());
   return std::vector<uint8_t>(data, data + ruleset_contents.size());
 }
 
diff --git a/components/toolbar/toolbar_model_impl.cc b/components/toolbar/toolbar_model_impl.cc
index d2041ee..017c5a9c 100644
--- a/components/toolbar/toolbar_model_impl.cc
+++ b/components/toolbar/toolbar_model_impl.cc
@@ -73,7 +73,7 @@
 
 const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
-  const auto icon_override = delegate_->GetVectorIconOverride();
+  auto* const icon_override = delegate_->GetVectorIconOverride();
   if (icon_override)
     return *icon_override;
 
diff --git a/components/tracing/test/proto_zero_generation_unittest.cc b/components/tracing/test/proto_zero_generation_unittest.cc
index f34b71b..75c4b210 100644
--- a/components/tracing/test/proto_zero_generation_unittest.cc
+++ b/components/tracing/test/proto_zero_generation_unittest.cc
@@ -67,7 +67,7 @@
 };
 
 TEST_F(ProtoZeroConformanceTest, SimpleFieldsNoNesting) {
-  auto msg = CreateMessage<pbtest::EveryField>();
+  auto* msg = CreateMessage<pbtest::EveryField>();
 
   msg->set_field_int32(-1);
   msg->set_field_int64(-333123456789ll);
@@ -126,7 +126,7 @@
 }
 
 TEST_F(ProtoZeroConformanceTest, NestedMessages) {
-  auto msg_a = CreateMessage<pbtest::NestedA>();
+  auto* msg_a = CreateMessage<pbtest::NestedA>();
 
   pbtest::NestedA::NestedB* msg_b = msg_a->add_repeated_a();
   pbtest::NestedA::NestedB::NestedC* msg_c = msg_b->set_value_b();
diff --git a/components/update_client/update_response.cc b/components/update_client/update_response.cc
index f9eefe8..7f621298 100644
--- a/components/update_client/update_response.cc
+++ b/components/update_client/update_response.cc
@@ -302,7 +302,7 @@
   static const char* attrs[] = {UpdateResponse::Result::kCohort,
                                 UpdateResponse::Result::kCohortHint,
                                 UpdateResponse::Result::kCohortName};
-  for (const auto& attr : attrs) {
+  for (auto* attr : attrs) {
     auto value = GetAttributePtr(app, attr);
     if (value)
       result->cohort_attrs.insert({attr, *value});
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 51ca75f..968260b 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1928,6 +1928,8 @@
       "compositor/gpu_process_transport_factory.h",
       "compositor/gpu_surfaceless_browser_compositor_output_surface.cc",
       "compositor/gpu_surfaceless_browser_compositor_output_surface.h",
+      "compositor/gpu_vsync_begin_frame_source.cc",
+      "compositor/gpu_vsync_begin_frame_source.h",
       "compositor/image_transport_factory.cc",
       "compositor/image_transport_factory.h",
       "compositor/offscreen_browser_compositor_output_surface.cc",
diff --git a/content/browser/accessibility/ax_platform_position.cc b/content/browser/accessibility/ax_platform_position.cc
index 9b90de31..3c8c460c 100644
--- a/content/browser/accessibility/ax_platform_position.cc
+++ b/content/browser/accessibility/ax_platform_position.cc
@@ -87,7 +87,7 @@
     return nullptr;
   }
 
-  auto manager = BrowserAccessibilityManager::FromID(tree_id);
+  auto* manager = BrowserAccessibilityManager::FromID(tree_id);
   if (!manager)
     return nullptr;
   return manager->GetFromID(node_id);
diff --git a/content/browser/android/OWNERS b/content/browser/android/OWNERS
index 70bfe8db..482db7f 100644
--- a/content/browser/android/OWNERS
+++ b/content/browser/android/OWNERS
@@ -1,3 +1,5 @@
 skyostil@chromium.org
 tedchoc@chromium.org
 yfriedman@chromium.org
+
+# COMPONENT: Content>WebApps
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index 41f7930..b1f3ee5 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -966,22 +966,20 @@
                                : rwhv->OnTouchEvent(event);
 }
 
-jboolean ContentViewCoreImpl::SendMouseEvent(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    jlong time_ms,
-    jint android_action,
-    jfloat x,
-    jfloat y,
-    jint pointer_id,
-    jfloat pressure,
-    jfloat orientation,
-    jfloat tilt,
-    jint android_changed_button,
-    jint android_button_state,
-    jint android_meta_state,
-    jint android_tool_type) {
-
+jboolean ContentViewCoreImpl::SendMouseEvent(JNIEnv* env,
+                                             const JavaParamRef<jobject>& obj,
+                                             jlong time_ms,
+                                             jint android_action,
+                                             jfloat x,
+                                             jfloat y,
+                                             jint pointer_id,
+                                             jfloat pressure,
+                                             jfloat orientation,
+                                             jfloat tilt,
+                                             jint android_action_button,
+                                             jint android_button_state,
+                                             jint android_meta_state,
+                                             jint android_tool_type) {
   RenderWidgetHostViewAndroid* rwhv = GetRenderWidgetHostViewAndroid();
   if (!rwhv)
     return false;
@@ -1012,7 +1010,7 @@
 
   // Note: This relies on identical button enum values in MotionEvent and
   // MotionEventAndroid.
-  rwhv->SendMouseEvent(motion_event, android_changed_button);
+  rwhv->SendMouseEvent(motion_event, android_action_button);
 
   return true;
 }
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index 603fd441..1241f11 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -130,7 +130,7 @@
                           jfloat pressure,
                           jfloat orientation,
                           jfloat tilt,
-                          jint android_changed_button,
+                          jint android_action_button,
                           jint android_button_state,
                           jint android_meta_state,
                           jint tool_type);
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
index 8ad8384..d663726 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -42,6 +42,14 @@
       UpdateVSyncParametersCallback());
 }
 
+void GpuBrowserCompositorOutputSurface::SetNeedsVSync(bool needs_vsync) {
+#if defined(OS_WIN)
+  GetCommandBufferProxy()->SetNeedsVSync(needs_vsync);
+#else
+  NOTREACHED();
+#endif  // defined(OS_WIN)
+}
+
 void GpuBrowserCompositorOutputSurface::OnGpuSwapBuffersCompleted(
     const std::vector<ui::LatencyInfo>& latency_info,
     gfx::SwapResult result,
@@ -96,22 +104,23 @@
     cc::OutputSurfaceFrame frame) {
   GetCommandBufferProxy()->SetLatencyInfo(frame.latency_info);
 
-  gfx::Rect swap_rect = frame.sub_buffer_rect;
   gfx::Size surface_size = frame.size;
   if (reflector_) {
-    if (swap_rect == gfx::Rect(surface_size)) {
+    if (frame.sub_buffer_rect) {
+      reflector_texture_->CopyTextureSubImage(*frame.sub_buffer_rect);
+      reflector_->OnSourcePostSubBuffer(*frame.sub_buffer_rect, surface_size);
+    } else {
       reflector_texture_->CopyTextureFullImage(surface_size);
       reflector_->OnSourceSwapBuffers(surface_size);
-    } else {
-      reflector_texture_->CopyTextureSubImage(swap_rect);
-      reflector_->OnSourcePostSubBuffer(swap_rect, surface_size);
     }
   }
 
-  if (swap_rect == gfx::Rect(frame.size))
+  if (frame.sub_buffer_rect) {
+    context_provider_->ContextSupport()->PartialSwapBuffers(
+        *frame.sub_buffer_rect);
+  } else {
     context_provider_->ContextSupport()->Swap();
-  else
-    context_provider_->ContextSupport()->PartialSwapBuffers(swap_rect);
+  }
 }
 
 uint32_t GpuBrowserCompositorOutputSurface::GetFramebufferCopyTextureFormat() {
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.h b/content/browser/compositor/gpu_browser_compositor_output_surface.h
index c2505264..09fd1ef8 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
 #include "content/browser/compositor/browser_compositor_output_surface.h"
+#include "content/browser/compositor/gpu_vsync_begin_frame_source.h"
 #include "ui/gfx/swap_result.h"
 
 namespace display_compositor {
@@ -33,8 +34,8 @@
 // Adapts a WebGraphicsContext3DCommandBufferImpl into a
 // cc::OutputSurface that also handles vsync parameter updates
 // arriving from the GPU process.
-class GpuBrowserCompositorOutputSurface
-    : public BrowserCompositorOutputSurface {
+class GpuBrowserCompositorOutputSurface : public BrowserCompositorOutputSurface,
+                                          public GpuVSyncControl {
  public:
   GpuBrowserCompositorOutputSurface(
       scoped_refptr<ui::ContextProviderCommandBuffer> context,
@@ -76,6 +77,9 @@
   unsigned GetOverlayTextureId() const override;
   bool SurfaceIsSuspendForRecycle() const override;
 
+  // GpuVSyncControl implementation.
+  void SetNeedsVSync(bool needs_vsync) override;
+
  protected:
   gpu::CommandBufferProxyImpl* GetCommandBufferProxy();
 
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index ffe7e05..50a66bb 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -58,6 +58,7 @@
 #include "ui/display/types/display_snapshot.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/switches.h"
+#include "ui/gl/gl_switches.h"
 
 #if defined(USE_AURA)
 #include "content/browser/compositor/mus_browser_compositor_output_surface.h"
@@ -66,6 +67,7 @@
 #endif
 
 #if defined(OS_WIN)
+#include "base/win/windows_version.h"
 #include "components/display_compositor/compositor_overlay_candidate_validator_win.h"
 #include "content/browser/compositor/software_output_device_win.h"
 #include "ui/gfx/win/rendering_window_manager.h"
@@ -111,6 +113,17 @@
   return service_manager::ServiceManagerIsRemote();
 }
 
+bool IsGpuVSyncSignalSupported() {
+#if defined(OS_WIN)
+  // TODO(stanisc): http://crbug.com/467617 Limit to Windows 8+ for now because
+  // of locking issue caused by waiting for VSync on Win7.
+  return base::win::GetVersion() >= base::win::VERSION_WIN8 &&
+         base::FeatureList::IsEnabled(features::kD3DVsync);
+#else
+  return false;
+#endif  // defined(OS_WIN)
+}
+
 scoped_refptr<ui::ContextProviderCommandBuffer> CreateContextCommon(
     scoped_refptr<gpu::GpuChannelHost> gpu_channel_host,
     gpu::SurfaceHandle surface_handle,
@@ -171,7 +184,10 @@
 struct GpuProcessTransportFactory::PerCompositorData {
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   BrowserCompositorOutputSurface* display_output_surface = nullptr;
-  std::unique_ptr<cc::SyntheticBeginFrameSource> begin_frame_source;
+  // Either |synthetic_begin_frame_source| or |gpu_vsync_begin_frame_source| is
+  // valid but not both at the same time.
+  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source;
+  std::unique_ptr<GpuVSyncBeginFrameSource> gpu_vsync_begin_frame_source;
   ReflectorImpl* reflector = nullptr;
   std::unique_ptr<cc::Display> display;
   bool output_is_secure = false;
@@ -464,20 +480,10 @@
     }
   }
 
-  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source;
-  if (!compositor->GetRendererSettings().disable_display_vsync) {
-    synthetic_begin_frame_source.reset(new cc::DelayBasedBeginFrameSource(
-        base::MakeUnique<cc::DelayBasedTimeSource>(
-            compositor->task_runner().get())));
-  } else {
-    synthetic_begin_frame_source.reset(new cc::BackToBackBeginFrameSource(
-        base::MakeUnique<cc::DelayBasedTimeSource>(
-            compositor->task_runner().get())));
-  }
-  cc::BeginFrameSource* begin_frame_source = synthetic_begin_frame_source.get();
-
   BrowserCompositorOutputSurface::UpdateVSyncParametersCallback vsync_callback =
       base::Bind(&ui::Compositor::SetDisplayVSyncParameters, compositor);
+  cc::BeginFrameSource* begin_frame_source = nullptr;
+  GpuVSyncControl* gpu_vsync_control = nullptr;
 
   std::unique_ptr<BrowserCompositorOutputSurface> display_output_surface;
 #if defined(ENABLE_VULKAN)
@@ -517,13 +523,15 @@
             CreateOverlayCandidateValidator(compositor->widget()),
             GetGpuMemoryBufferManager());
 #else
-        display_output_surface =
+        auto gpu_output_surface =
             base::MakeUnique<GpuSurfacelessBrowserCompositorOutputSurface>(
                 context_provider, data->surface_handle, vsync_callback,
                 CreateOverlayCandidateValidator(compositor->widget()),
                 GL_TEXTURE_2D, GL_RGB,
                 display::DisplaySnapshot::PrimaryFormat(),
                 GetGpuMemoryBufferManager());
+        gpu_vsync_control = gpu_output_surface.get();
+        display_output_surface = std::move(gpu_output_surface);
 #endif
       } else {
         std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
@@ -535,22 +543,22 @@
           validator = CreateOverlayCandidateValidator(compositor->widget());
 #endif
         if (!use_mus) {
-          display_output_surface =
+          auto gpu_output_surface =
               base::MakeUnique<GpuBrowserCompositorOutputSurface>(
                   context_provider, vsync_callback, std::move(validator));
+          gpu_vsync_control = gpu_output_surface.get();
+          display_output_surface = std::move(gpu_output_surface);
         } else {
 #if defined(USE_AURA)
-          std::unique_ptr<MusBrowserCompositorOutputSurface> mus_output_surface;
           aura::WindowTreeHost* host =
               aura::WindowTreeHost::GetForAcceleratedWidget(
                   compositor->widget());
-          mus_output_surface =
+          auto mus_output_surface =
               base::MakeUnique<MusBrowserCompositorOutputSurface>(
                   host->window(), context_provider, GetGpuMemoryBufferManager(),
                   vsync_callback, std::move(validator));
           // We use the ExternalBeginFrameSource provided by the output surface
           // instead of our own synthetic one.
-          synthetic_begin_frame_source.reset();
           begin_frame_source = mus_output_surface->GetBeginFrameSource();
           DCHECK(begin_frame_source);
           display_output_surface = std::move(mus_output_surface);
@@ -562,7 +570,31 @@
     }
   }
 
-  data->display_output_surface = display_output_surface.get();
+  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source;
+  std::unique_ptr<GpuVSyncBeginFrameSource> gpu_vsync_begin_frame_source;
+
+  if (!begin_frame_source) {
+    if (!compositor->GetRendererSettings().disable_display_vsync) {
+      if (gpu_vsync_control && IsGpuVSyncSignalSupported()) {
+        gpu_vsync_begin_frame_source =
+            base::MakeUnique<GpuVSyncBeginFrameSource>(gpu_vsync_control);
+        begin_frame_source = gpu_vsync_begin_frame_source.get();
+      } else {
+        synthetic_begin_frame_source =
+            base::MakeUnique<cc::DelayBasedBeginFrameSource>(
+                base::MakeUnique<cc::DelayBasedTimeSource>(
+                    compositor->task_runner().get()));
+        begin_frame_source = synthetic_begin_frame_source.get();
+      }
+    } else {
+      synthetic_begin_frame_source =
+          base::MakeUnique<cc::BackToBackBeginFrameSource>(
+              base::MakeUnique<cc::DelayBasedTimeSource>(
+                  compositor->task_runner().get()));
+      begin_frame_source = synthetic_begin_frame_source.get();
+    }
+  }
+
   if (data->reflector)
     data->reflector->OnSourceSurfaceReady(data->display_output_surface);
 
@@ -582,9 +614,10 @@
       begin_frame_source, std::move(display_output_surface),
       std::move(scheduler), base::MakeUnique<cc::TextureMailboxDeleter>(
                                 compositor->task_runner().get()));
-  // Note that we are careful not to destroy a prior |data->begin_frame_source|
+  // Note that we are careful not to destroy prior BeginFrameSource objects
   // until we have reset |data->display|.
-  data->begin_frame_source = std::move(synthetic_begin_frame_source);
+  data->synthetic_begin_frame_source = std::move(synthetic_begin_frame_source);
+  data->gpu_vsync_begin_frame_source = std::move(gpu_vsync_begin_frame_source);
 
   // The |delegated_output_surface| is given back to the compositor, it
   // delegates to the Display as its root surface. Importantly, it shares the
@@ -742,8 +775,8 @@
     return;
   PerCompositorData* data = it->second.get();
   DCHECK(data);
-  if (data->begin_frame_source)
-    data->begin_frame_source->SetAuthoritativeVSyncInterval(interval);
+  if (data->synthetic_begin_frame_source)
+    data->synthetic_begin_frame_source->SetAuthoritativeVSyncInterval(interval);
 }
 
 void GpuProcessTransportFactory::SetDisplayVSyncParameters(
@@ -755,8 +788,12 @@
     return;
   PerCompositorData* data = it->second.get();
   DCHECK(data);
-  if (data->begin_frame_source)
-    data->begin_frame_source->OnUpdateVSyncParameters(timebase, interval);
+  if (data->synthetic_begin_frame_source) {
+    data->synthetic_begin_frame_source->OnUpdateVSyncParameters(timebase,
+                                                                interval);
+  } else if (data->gpu_vsync_begin_frame_source) {
+    data->gpu_vsync_begin_frame_source->OnVSync(timebase, interval);
+  }
 }
 
 void GpuProcessTransportFactory::SetOutputIsSecure(ui::Compositor* compositor,
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
index a6e74153..e0464b67 100644
--- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -73,7 +73,8 @@
   // TODO(ccameron): What if a swap comes again before OnGpuSwapBuffersCompleted
   // happens, we'd see the wrong swap size there?
   swap_size_ = reshape_size_;
-  buffer_queue_->SwapBuffers(frame.sub_buffer_rect);
+  buffer_queue_->SwapBuffers(frame.sub_buffer_rect ? *frame.sub_buffer_rect
+                                                   : gfx::Rect(swap_size_));
   GpuBrowserCompositorOutputSurface::SwapBuffers(std::move(frame));
 }
 
diff --git a/content/browser/compositor/gpu_vsync_begin_frame_source.cc b/content/browser/compositor/gpu_vsync_begin_frame_source.cc
new file mode 100644
index 0000000..f941410
--- /dev/null
+++ b/content/browser/compositor/gpu_vsync_begin_frame_source.cc
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/compositor/gpu_vsync_begin_frame_source.h"
+
+namespace content {
+
+GpuVSyncBeginFrameSource::GpuVSyncBeginFrameSource(
+    GpuVSyncControl* vsync_control)
+    : cc::ExternalBeginFrameSource(this),
+      vsync_control_(vsync_control),
+      needs_begin_frames_(false),
+      next_sequence_number_(cc::BeginFrameArgs::kStartingFrameNumber) {
+  DCHECK(vsync_control);
+}
+
+GpuVSyncBeginFrameSource::~GpuVSyncBeginFrameSource() = default;
+
+void GpuVSyncBeginFrameSource::OnVSync(base::TimeTicks timestamp,
+                                       base::TimeDelta interval) {
+  if (!needs_begin_frames_)
+    return;
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks deadline = now.SnappedToNextTick(timestamp, interval);
+
+  TRACE_EVENT1("cc", "GpuVSyncBeginFrameSource::OnVSync", "latency",
+               (now - timestamp).ToInternalValue());
+
+  next_sequence_number_++;
+  OnBeginFrame(cc::BeginFrameArgs::Create(
+      BEGINFRAME_FROM_HERE, source_id(), next_sequence_number_, timestamp,
+      deadline, interval, cc::BeginFrameArgs::NORMAL));
+}
+
+void GpuVSyncBeginFrameSource::OnNeedsBeginFrames(bool needs_begin_frames) {
+  needs_begin_frames_ = needs_begin_frames;
+  vsync_control_->SetNeedsVSync(needs_begin_frames);
+}
+
+void GpuVSyncBeginFrameSource::OnDidFinishFrame(const cc::BeginFrameAck& ack) {}
+
+}  // namespace content
diff --git a/content/browser/compositor/gpu_vsync_begin_frame_source.h b/content/browser/compositor/gpu_vsync_begin_frame_source.h
new file mode 100644
index 0000000..a701f98
--- /dev/null
+++ b/content/browser/compositor/gpu_vsync_begin_frame_source.h
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_COMPOSITOR_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
+#define CONTENT_BROWSER_COMPOSITOR_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "cc/scheduler/begin_frame_source.h"
+
+namespace content {
+
+// This class is used to control VSync production on GPU side.
+class GpuVSyncControl {
+ public:
+  virtual void SetNeedsVSync(bool needs_vsync) = 0;
+};
+
+// This is a type of ExternalBeginFrameSource where VSync signals are
+// generated externally on GPU side.
+class GpuVSyncBeginFrameSource : public cc::ExternalBeginFrameSource,
+                                 cc::ExternalBeginFrameSourceClient {
+ public:
+  explicit GpuVSyncBeginFrameSource(GpuVSyncControl* vsync_control);
+  ~GpuVSyncBeginFrameSource() override;
+
+  // cc::ExternalBeginFrameSourceClient implementation.
+  void OnNeedsBeginFrames(bool needs_begin_frames) override;
+  void OnDidFinishFrame(const cc::BeginFrameAck& ack) override;
+
+  void OnVSync(base::TimeTicks timestamp, base::TimeDelta interval);
+
+ private:
+  GpuVSyncControl* const vsync_control_;
+  bool needs_begin_frames_;
+  uint64_t next_sequence_number_;
+
+  DISALLOW_COPY_AND_ASSIGN(GpuVSyncBeginFrameSource);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_COMPOSITOR_GPU_VSYNC_BEGIN_FRAME_SOURCE_H_
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
index 8c7581c..bf2f877 100644
--- a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -136,13 +136,12 @@
     cc::OutputSurfaceFrame frame) {
   gfx::Size surface_size = frame.size;
   DCHECK(surface_size == reshape_size_);
-  gfx::Rect swap_rect = frame.sub_buffer_rect;
 
   if (reflector_) {
-    if (swap_rect == gfx::Rect(surface_size))
-      reflector_->OnSourceSwapBuffers(surface_size);
+    if (frame.sub_buffer_rect)
+      reflector_->OnSourcePostSubBuffer(*frame.sub_buffer_rect, surface_size);
     else
-      reflector_->OnSourcePostSubBuffer(swap_rect, surface_size);
+      reflector_->OnSourceSwapBuffers(surface_size);
   }
 
   // TODO(oshima): sync with the reflector's SwapBuffersComplete
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index fbd7c4a..90b18f1 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -504,7 +504,7 @@
 void RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
   session->SetFallThroughForNotFound(true);
   session->SetRenderFrameHost(handlers_frame_host_);
-  if (!frame_tree_node_->parent()) {
+  if (frame_tree_node_ && !frame_tree_node_->parent()) {
     session->AddHandler(base::WrapUnique(new protocol::EmulationHandler()));
     session->AddHandler(base::WrapUnique(new protocol::PageHandler()));
     session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
@@ -521,7 +521,7 @@
   session->AddHandler(base::WrapUnique(new protocol::TargetHandler()));
   session->AddHandler(base::WrapUnique(new protocol::TracingHandler(
       protocol::TracingHandler::Renderer,
-      frame_tree_node_->frame_tree_node_id(),
+      frame_tree_node_ ? frame_tree_node_->frame_tree_node_id() : 0,
       GetIOContext())));
 
   if (current_)
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc
index 22e0a15c..c693078 100644
--- a/content/browser/frame_host/debug_urls.cc
+++ b/content/browser/frame_host/debug_urls.cc
@@ -212,7 +212,8 @@
   if (url.SchemeIs(url::kJavaScriptScheme))
     return true;
 
-  return url == kChromeUIBadCastCrashURL ||
+  return url == kChromeUICheckCrashURL ||
+         url == kChromeUIBadCastCrashURL ||
          url == kChromeUICrashURL ||
          url == kChromeUIDumpURL ||
          url == kChromeUIKillURL ||
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index c3b0abb..12676d4 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -526,6 +526,11 @@
   }
 }
 
+WebContents* InterstitialPageImpl::OpenURL(const OpenURLParams& params) {
+  NOTREACHED();
+  return nullptr;
+}
+
 RendererPreferences InterstitialPageImpl::GetRendererPrefs(
     BrowserContext* browser_context) const {
   delegate_->OverrideRendererPrefs(&renderer_preferences_);
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index aaf77bb5..19361d6 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -95,6 +95,9 @@
       RenderViewHost* render_view_host,
       const FrameHostMsg_DidCommitProvisionalLoad_Params& params);
 
+  // NavigatorDelegate implementation.
+  WebContents* OpenURL(const OpenURLParams& params) override;
+
  protected:
   // NotificationObserver method:
   void Observe(int type,
diff --git a/content/browser/frame_host/navigator_delegate.h b/content/browser/frame_host/navigator_delegate.h
index 101a929..c3db7d1 100644
--- a/content/browser/frame_host/navigator_delegate.h
+++ b/content/browser/frame_host/navigator_delegate.h
@@ -94,9 +94,8 @@
                                                 ReloadType reload_type) {}
 
   // Opens a URL with the given parameters. See PageNavigator::OpenURL, which
-  // this forwards to.
-  virtual void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
-                              const OpenURLParams& params) {}
+  // this is an alias of.
+  virtual WebContents* OpenURL(const OpenURLParams& params) = 0;
 
   // Returns whether to continue a navigation that needs to transfer to a
   // different process between the load start and commit.
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 72bbe28..07f3cc9 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -798,6 +798,9 @@
   // RequestOpenURL and go through RequestTransferURL instead.
   params.source_site_instance = current_site_instance;
 
+  params.source_render_frame_id = render_frame_host->GetRoutingID();
+  params.source_render_process_id = render_frame_host->GetProcess()->GetID();
+
   if (render_frame_host->web_ui()) {
     // Note that we hide the referrer for Web UI pages. We don't really want
     // web sites to see a referrer of "chrome://blah" (and some chrome: URLs
@@ -814,7 +817,7 @@
       &params.referrer);
 
   if (delegate_)
-    delegate_->RequestOpenURL(render_frame_host, params);
+    delegate_->OpenURL(params);
 }
 
 void NavigatorImpl::RequestTransferURL(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 9677e350..ce81fb1 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/containers/hash_tables.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/lazy_instance.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
@@ -1354,12 +1353,6 @@
 void RenderFrameHostImpl::SetNavigationHandle(
     std::unique_ptr<NavigationHandleImpl> navigation_handle) {
   navigation_handle_ = std::move(navigation_handle);
-
-  // TODO(clamy): Remove this debug code once we understand better how we get to
-  // the point of attempting to transfer a navigation from a RFH that is no
-  // longer active.
-  if (navigation_handle_ && !is_active())
-    base::debug::DumpWithoutCrashing();
 }
 
 std::unique_ptr<NavigationHandleImpl>
diff --git a/content/browser/indexed_db/indexed_db_transaction_coordinator.cc b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
index 51ae028..83acd3e 100644
--- a/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
+++ b/content/browser/indexed_db/indexed_db_transaction_coordinator.cc
@@ -106,7 +106,7 @@
   // data. ("Version change" transactions are exclusive, but handled by the
   // connection sequencing in IndexedDBDatabase.)
   std::set<int64_t> locked_scope;
-  for (const auto& transaction : started_transactions_) {
+  for (auto* transaction : started_transactions_) {
     if (transaction->mode() == blink::WebIDBTransactionModeReadWrite) {
       // Started read/write transactions have exclusive access to the object
       // stores within their scopes.
diff --git a/content/browser/loader/resource_loader.cc b/content/browser/loader/resource_loader.cc
index 0a76d9c..7c707c09 100644
--- a/content/browser/loader/resource_loader.cc
+++ b/content/browser/loader/resource_loader.cc
@@ -113,8 +113,8 @@
           request->ssl_info().cert->os_cert_handle(), &encoded);
       DCHECK(rv);
       response->head.certificate.push_back(encoded);
-      for (auto& cert :
-               request->ssl_info().cert->GetIntermediateCertificates()) {
+      for (auto* cert :
+           request->ssl_info().cert->GetIntermediateCertificates()) {
         rv = net::X509Certificate::GetDEREncoded(cert, &encoded);
         DCHECK(rv);
         response->head.certificate.push_back(encoded);
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 6d68cf1c..5f8c5743 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -13,6 +13,7 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/supports_user_data.h"
@@ -39,6 +40,16 @@
 const base::Feature kPrioritySupportedRequestsDelayable{
     "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// In the event that many resource requests are started quickly, this feature
+// will periodically yield (e.g., delaying starting of requests) by posting a
+// task and waiting for the task to run to resume. This allows other
+// operations that rely on the IO thread (e.g., already running network
+// requests) to make progress.
+const base::Feature kNetworkSchedulerYielding{
+    "NetworkSchedulerYielding", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kMaxRequestsBeforeYieldingParam[] = "MaxRequestsBeforeYieldingParam";
+const int kMaxRequestsBeforeYieldingDefault = 5;
+
 enum StartMode {
   START_SYNC,
   START_ASYNC
@@ -61,6 +72,7 @@
   CLIENT_KILL,
   SPDY_PROXY_DETECTED,
   REQUEST_REPRIORITIZED,
+  START_WAS_YIELDED,
 };
 
 const char* RequestStartTriggerString(RequestStartTrigger trigger) {
@@ -79,6 +91,8 @@
       return "SPDY_PROXY_DETECTED";
     case RequestStartTrigger::REQUEST_REPRIORITIZED:
       return "REQUEST_REPRIORITIZED";
+    case RequestStartTrigger::START_WAS_YIELDED:
+      return "START_WAS_YIELDED";
   }
   NOTREACHED();
   return "Unknown";
@@ -348,7 +362,9 @@
 // Each client represents a tab.
 class ResourceScheduler::Client {
  public:
-  explicit Client(bool priority_requests_delayable)
+  Client(bool priority_requests_delayable,
+         bool yielding_scheduler_enabled,
+         int max_requests_before_yielding)
       : is_loaded_(false),
         has_html_body_(false),
         using_spdy_proxy_(false),
@@ -356,6 +372,10 @@
         total_layout_blocking_count_(0),
         priority_requests_delayable_(priority_requests_delayable),
         has_pending_start_task_(false),
+        started_requests_since_yielding_(0),
+        did_scheduler_yield_(false),
+        yielding_scheduler_enabled_(yielding_scheduler_enabled),
+        max_requests_before_yielding_(max_requests_before_yielding),
         weak_ptr_factory_(this) {}
 
   ~Client() {}
@@ -363,11 +383,14 @@
   void ScheduleRequest(net::URLRequest* url_request,
                        ScheduledResourceRequest* request) {
     SetRequestAttributes(request, DetermineRequestAttributes(request));
-    if (ShouldStartRequest(request) == START_REQUEST) {
+    ShouldStartReqResult should_start = ShouldStartRequest(request);
+    if (should_start == START_REQUEST) {
       // New requests can be started synchronously without issue.
       StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
     } else {
       pending_requests_.Insert(request);
+      if (should_start == YIELD_SCHEDULER)
+        did_scheduler_yield_ = true;
     }
   }
 
@@ -464,6 +487,7 @@
     DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
     DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
     START_REQUEST,
+    YIELD_SCHEDULER
   };
 
   void InsertInFlightRequest(ScheduledResourceRequest* request) {
@@ -603,6 +627,17 @@
   void StartRequest(ScheduledResourceRequest* request,
                     StartMode start_mode,
                     RequestStartTrigger trigger) {
+    started_requests_since_yielding_ += 1;
+    if (started_requests_since_yielding_ == 1) {
+      // This is the first started request since last yielding. Post a task to
+      // reset the counter and start any yielded tasks if necessary. We post
+      // this now instead of when we first yield so that if there is a pause
+      // between requests the counter is reset.
+      base::ThreadTaskRunnerHandle::Get()->PostTask(
+          FROM_HERE,
+          base::Bind(&Client::ResumeIfYielded, weak_ptr_factory_.GetWeakPtr()));
+    }
+
     // Only log on requests that were blocked by the ResourceScheduler.
     if (start_mode == START_ASYNC) {
       DCHECK_NE(RequestStartTrigger::NONE, trigger);
@@ -666,7 +701,7 @@
 
     if (!priority_requests_delayable_) {
       if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
-        return START_REQUEST;
+        return ShouldStartOrYieldRequest();
 
       url::SchemeHostPort scheme_host_port(url_request.url());
 
@@ -677,12 +712,12 @@
       // crbug.com/164101. Also, theoretically we should not count a
       // request-priority capable request against the delayable requests limit.
       if (http_server_properties.SupportsRequestPriority(scheme_host_port))
-        return START_REQUEST;
+        return ShouldStartOrYieldRequest();
     }
 
     // Non-delayable requests.
     if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
-      return START_REQUEST;
+      return ShouldStartOrYieldRequest();
 
     if (in_flight_delayable_count_ >= kMaxNumDelayableRequestsPerClient)
       return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
@@ -717,7 +752,7 @@
       }
     }
 
-    return START_REQUEST;
+    return ShouldStartOrYieldRequest();
   }
 
   // It is common for a burst of messages to come from the renderer which
@@ -738,6 +773,27 @@
                               weak_ptr_factory_.GetWeakPtr(), trigger));
   }
 
+  void ResumeIfYielded() {
+    bool yielded = did_scheduler_yield_;
+    started_requests_since_yielding_ = 0;
+    did_scheduler_yield_ = false;
+
+    if (yielded)
+      LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
+  }
+
+  // For a request that is ready to start, return START_REQUEST if the
+  // scheduler doesn't need to yield, else YIELD_SCHEDULER.
+  ShouldStartReqResult ShouldStartOrYieldRequest() const {
+    DCHECK_GE(started_requests_since_yielding_, 0);
+
+    if (!yielding_scheduler_enabled_ ||
+        started_requests_since_yielding_ < max_requests_before_yielding_) {
+      return START_REQUEST;
+    }
+    return YIELD_SCHEDULER;
+  }
+
   void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
     // We iterate through all the pending requests, starting with the highest
     // priority one. For each entry, one of three things can happen:
@@ -769,6 +825,9 @@
       } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
         ++request_iter;
         continue;
+      } else if (query_result == YIELD_SCHEDULER) {
+        did_scheduler_yield_ = true;
+        break;
       } else {
         DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
         break;
@@ -794,12 +853,32 @@
 
   bool has_pending_start_task_;
 
+  // The number of started requests since the last ResumeIfYielded task was
+  // run.
+  int started_requests_since_yielding_;
+
+  // If the scheduler had to yield the start of a request since the last
+  // ResumeIfYielded task was run.
+  bool did_scheduler_yield_;
+
+  // Whether or not to periodically yield when starting lots of requests.
+  bool yielding_scheduler_enabled_;
+
+  // The number of requests that can start before yielding.
+  int max_requests_before_yielding_;
+
   base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
 };
 
 ResourceScheduler::ResourceScheduler()
     : priority_requests_delayable_(
-          base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)) {}
+          base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)),
+      yielding_scheduler_enabled_(
+          base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
+      max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
+          kNetworkSchedulerYielding,
+          kMaxRequestsBeforeYieldingParam,
+          kMaxRequestsBeforeYieldingDefault)) {}
 
 ResourceScheduler::~ResourceScheduler() {
   DCHECK(unowned_requests_.empty());
@@ -856,7 +935,9 @@
   ClientId client_id = MakeClientId(child_id, route_id);
   DCHECK(!base::ContainsKey(client_map_, client_id));
 
-  Client* client = new Client(priority_requests_delayable_);
+  Client* client =
+      new Client(priority_requests_delayable_, yielding_scheduler_enabled_,
+                 max_requests_before_yielding_);
   client_map_[client_id] = client;
 }
 
diff --git a/content/browser/loader/resource_scheduler.h b/content/browser/loader/resource_scheduler.h
index 76b455c4..bcb3213a3 100644
--- a/content/browser/loader/resource_scheduler.h
+++ b/content/browser/loader/resource_scheduler.h
@@ -140,6 +140,11 @@
   // be delayed.
   bool priority_requests_delayable_;
 
+  // True if the scheduler should yield between several successive calls to
+  // start resource requests.
+  bool yielding_scheduler_enabled_;
+  int max_requests_before_yielding_;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceScheduler);
 };
 
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index fb88161..52f77cda 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -9,8 +9,11 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_param_associator.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/timer/mock_timer.h"
 #include "base/timer/timer.h"
@@ -48,6 +51,9 @@
 const char kPrioritySupportedRequestsDelayable[] =
     "PrioritySupportedRequestsDelayable";
 
+const char kNetworkSchedulerYielding[] = "NetworkSchedulerYielding";
+const int kMaxRequestsBeforeYielding = 5;  // sync with .cc.
+
 class TestRequest : public ResourceThrottle::Delegate {
  public:
   TestRequest(std::unique_ptr<net::URLRequest> url_request,
@@ -317,6 +323,117 @@
   EXPECT_TRUE(lowest2->started());
 }
 
+TEST_F(ResourceSchedulerTest, SchedulerYieldsWithFeatureEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+  InitializeScheduler();
+
+  // Use spdy so that we don't throttle.
+  http_server_properties_.SetSupportsSpdy(
+      url::SchemeHostPort("https", "spdyhost", 443), true);
+
+  // Add enough async requests that the last one should yield.
+  std::vector<std::unique_ptr<TestRequest>> requests;
+  for (int i = 0; i < kMaxRequestsBeforeYielding + 1; ++i)
+    requests.push_back(NewRequest("http://host/higher", net::HIGHEST));
+
+  // Verify that the number of requests before yielding started.
+  for (int i = 0; i < kMaxRequestsBeforeYielding; ++i)
+    EXPECT_TRUE(requests[i]->started());
+
+  // The next async request should have yielded.
+  EXPECT_FALSE(requests[kMaxRequestsBeforeYielding]->started());
+
+  // Verify that with time the yielded request eventually runs.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(requests[kMaxRequestsBeforeYielding]->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldForSyncRequests) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+  InitializeScheduler();
+
+  // Use spdy so that we don't throttle.
+  http_server_properties_.SetSupportsSpdy(
+      url::SchemeHostPort("https", "spdyhost", 443), true);
+
+  // Add enough async requests that the last one should yield.
+  std::vector<std::unique_ptr<TestRequest>> requests;
+  for (int i = 0; i < kMaxRequestsBeforeYielding + 1; ++i)
+    requests.push_back(NewRequest("http://host/higher", net::HIGHEST));
+
+  // Add a sync requests.
+  requests.push_back(NewSyncRequest("http://host/higher", net::HIGHEST));
+
+  // Verify that the number of requests before yielding started.
+  for (int i = 0; i < kMaxRequestsBeforeYielding; ++i)
+    EXPECT_TRUE(requests[i]->started());
+
+  // The next async request should have yielded.
+  EXPECT_FALSE(requests[kMaxRequestsBeforeYielding]->started());
+
+  // The next sync request should have started even though async is yielding.
+  EXPECT_TRUE(requests[kMaxRequestsBeforeYielding + 1]->started());
+
+  // Verify that with time the yielded request eventually runs.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(requests[kMaxRequestsBeforeYielding]->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldForAlternativeSchemes) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+  InitializeScheduler();
+
+  // Use spdy so that we don't throttle.
+  http_server_properties_.SetSupportsSpdy(
+      url::SchemeHostPort("https", "spdyhost", 443), true);
+
+  // Add enough async requests that the last one should yield.
+  std::vector<std::unique_ptr<TestRequest>> requests;
+  for (int i = 0; i < kMaxRequestsBeforeYielding + 1; ++i)
+    requests.push_back(NewRequest("http://host/higher", net::HIGHEST));
+
+  // Add a non-http request.
+  requests.push_back(NewRequest("zzz://host/higher", net::HIGHEST));
+
+  // Verify that the number of requests before yielding started.
+  for (int i = 0; i < kMaxRequestsBeforeYielding; ++i)
+    EXPECT_TRUE(requests[i]->started());
+
+  // The next async request should have yielded.
+  EXPECT_FALSE(requests[kMaxRequestsBeforeYielding]->started());
+
+  // The non-http(s) request should have started even though async is
+  // yielding.
+  EXPECT_TRUE(requests[kMaxRequestsBeforeYielding + 1]->started());
+
+  // Verify that with time the yielded request eventually runs.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(requests[kMaxRequestsBeforeYielding]->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldWithFeatureDisabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
+  InitializeScheduler();
+
+  // Use spdy so that we don't throttle.
+  http_server_properties_.SetSupportsSpdy(
+      url::SchemeHostPort("https", "spdyhost", 443), true);
+
+  // Add enough async requests that the last one would yield if yielding were
+  // enabled.
+  std::vector<std::unique_ptr<TestRequest>> requests;
+  for (int i = 0; i < kMaxRequestsBeforeYielding + 1; ++i)
+    requests.push_back(NewRequest("http://host/higher", net::HIGHEST));
+
+  // Verify that none of the requests yield.
+  for (int i = 0; i < kMaxRequestsBeforeYielding + 1; ++i)
+    EXPECT_TRUE(requests[i]->started());
+}
+
 TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
   base::test::ScopedFeatureList scoped_feature_list;
   scoped_feature_list.InitFromCommandLine("",
@@ -459,6 +576,11 @@
 }
 
 TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
+  // The yielding feature will sometimes yield requests before they get a
+  // chance to start, which conflicts this test. So disable the feature.
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
+
   // We only load low priority resources if there's a body.
   scheduler()->OnWillInsertBody(kChildId, kRouteId);
 
diff --git a/content/browser/media/session/audio_focus_manager.cc b/content/browser/media/session/audio_focus_manager.cc
index 48f6dcce..92cee28 100644
--- a/content/browser/media/session/audio_focus_manager.cc
+++ b/content/browser/media/session/audio_focus_manager.cc
@@ -34,11 +34,11 @@
   // up the relation between AudioFocusManager and MediaSessionImpl.
   // See https://crbug.com/651069
   if (type == AudioFocusType::GainTransientMayDuck) {
-    for (const auto old_session : audio_focus_stack_) {
+    for (auto* old_session : audio_focus_stack_) {
       old_session->StartDucking();
     }
   } else {
-    for (const auto old_session : audio_focus_stack_) {
+    for (auto* old_session : audio_focus_stack_) {
       if (old_session->IsActive()) {
         if (old_session->HasPepper())
           old_session->StartDucking();
diff --git a/content/browser/memory/memory_coordinator_impl_unittest.cc b/content/browser/memory/memory_coordinator_impl_unittest.cc
index 63edb99..a0e1b31 100644
--- a/content/browser/memory/memory_coordinator_impl_unittest.cc
+++ b/content/browser/memory/memory_coordinator_impl_unittest.cc
@@ -199,7 +199,7 @@
 }
 
 TEST_F(MemoryCoordinatorImplTest, SetMemoryStateFailsInvalidState) {
-  auto cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
+  auto* cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
 
   EXPECT_FALSE(
       coordinator_->SetChildMemoryState(1, MemoryState::UNKNOWN));
@@ -207,7 +207,7 @@
 }
 
 TEST_F(MemoryCoordinatorImplTest, SetMemoryStateFailsInvalidRenderer) {
-  auto cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
+  auto* cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
 
   EXPECT_FALSE(
       coordinator_->SetChildMemoryState(2, MemoryState::THROTTLED));
@@ -215,7 +215,7 @@
 }
 
 TEST_F(MemoryCoordinatorImplTest, SetMemoryStateNotDeliveredNop) {
-  auto cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
+  auto* cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
 
   EXPECT_FALSE(
       coordinator_->SetChildMemoryState(2, MemoryState::NORMAL));
@@ -223,8 +223,8 @@
 }
 
 TEST_F(MemoryCoordinatorImplTest, SetMemoryStateDelivered) {
-  auto cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
-  auto cmc2 = coordinator_->CreateChildMemoryCoordinator(2);
+  auto* cmc1 = coordinator_->CreateChildMemoryCoordinator(1);
+  auto* cmc2 = coordinator_->CreateChildMemoryCoordinator(2);
 
   EXPECT_TRUE(
       coordinator_->SetChildMemoryState(1, MemoryState::THROTTLED));
@@ -248,7 +248,7 @@
 }
 
 TEST_F(MemoryCoordinatorImplTest, SetChildMemoryState) {
-  auto cmc = coordinator_->CreateChildMemoryCoordinator(1);
+  auto* cmc = coordinator_->CreateChildMemoryCoordinator(1);
   auto iter = coordinator_->children().find(1);
   auto* render_process_host = coordinator_->GetMockRenderProcessHost(1);
   ASSERT_TRUE(iter != coordinator_->children().end());
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 49abcb2..eda8fc5 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -157,10 +157,10 @@
 
   void SwapBuffers(cc::OutputSurfaceFrame frame) override {
     GetCommandBufferProxy()->SetLatencyInfo(frame.latency_info);
-    if (frame.sub_buffer_rect.IsEmpty()) {
+    if (frame.sub_buffer_rect) {
+      DCHECK(frame.sub_buffer_rect->IsEmpty());
       context_provider_->ContextSupport()->CommitOverlayPlanes();
     } else {
-      DCHECK(frame.sub_buffer_rect == gfx::Rect(frame.size));
       context_provider_->ContextSupport()->Swap();
     }
   }
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc
index 3a7d18b..0c852a3 100644
--- a/content/browser/renderer_host/ime_adapter_android.cc
+++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -14,11 +14,8 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "content/browser/frame_host/frame_tree.h"
-#include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
-#include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
 #include "content/common/input_messages.h"
@@ -110,6 +107,7 @@
 
 ImeAdapterAndroid::ImeAdapterAndroid(RenderWidgetHostViewAndroid* rwhva)
     : rwhva_(rwhva) {
+  DCHECK(rwhva_);
 }
 
 ImeAdapterAndroid::~ImeAdapterAndroid() {
@@ -142,7 +140,7 @@
                                          const JavaParamRef<jobject>& text,
                                          const JavaParamRef<jstring>& text_str,
                                          int relative_cursor_pos) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* rwhi = GetFocusedWidget();
   if (!rwhi)
     return;
 
@@ -172,7 +170,7 @@
                                    const JavaParamRef<jobject>& text,
                                    const JavaParamRef<jstring>& text_str,
                                    int relative_cursor_pos) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* rwhi = GetFocusedWidget();
   if (!rwhi)
     return;
 
@@ -195,7 +193,7 @@
 
 void ImeAdapterAndroid::FinishComposingText(JNIEnv* env,
                                             const JavaParamRef<jobject>&) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* rwhi = GetFocusedWidget();
   if (!rwhi)
     return;
 
@@ -288,7 +286,7 @@
 bool ImeAdapterAndroid::RequestTextInputStateUpdate(
     JNIEnv* env,
     const JavaParamRef<jobject>&) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* rwhi = GetFocusedWidget();
   if (!rwhi)
     return false;
   rwhi->Send(new InputMsg_RequestTextInputStateUpdate(rwhi->GetRoutingID()));
@@ -300,7 +298,7 @@
     const base::android::JavaParamRef<jobject>& obj,
     bool immediate_request,
     bool monitor_request) {
-  RenderWidgetHostImpl* rwhi = GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* rwhi = GetFocusedWidget();
   if (!rwhi)
     return;
   rwhi->Send(new InputMsg_RequestCompositionUpdate(
@@ -312,36 +310,25 @@
   java_ime_adapter_.reset();
 }
 
-RenderWidgetHostImpl* ImeAdapterAndroid::GetRenderWidgetHostImpl() {
+RenderWidgetHostImpl* ImeAdapterAndroid::GetFocusedWidget() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(rwhva_);
-  RenderWidgetHost* rwh = rwhva_->GetRenderWidgetHost();
-  if (!rwh)
-    return nullptr;
-
-  return RenderWidgetHostImpl::From(rwh);
+  return rwhva_->GetFocusedWidget();
 }
 
 RenderFrameHost* ImeAdapterAndroid::GetFocusedFrame() {
-  RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
-  if (!rwh)
-    return nullptr;
-  RenderViewHost* rvh = RenderViewHost::From(rwh);
-  if (!rvh)
-    return nullptr;
-  FrameTreeNode* focused_frame =
-      rvh->GetDelegate()->GetFrameTree()->GetFocusedFrame();
-  if (!focused_frame)
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  // We get the focused frame from the WebContents of the page. Although
+  // |rwhva_->GetFocusedWidget()| does a similar thing, there is no direct way
+  // to get a RenderFrameHost from its RWH.
+  RenderWidgetHostImpl* rwh =
+      RenderWidgetHostImpl::From(rwhva_->GetRenderWidgetHost());
+  if (!rwh || !rwh->delegate())
     return nullptr;
 
-  return focused_frame->current_frame_host();
-}
+  if (auto* contents = rwh->delegate()->GetAsWebContents())
+    return contents->GetFocusedFrame();
 
-WebContents* ImeAdapterAndroid::GetWebContents() {
-  RenderWidgetHostImpl* rwh = GetRenderWidgetHostImpl();
-  if (!rwh)
-    return nullptr;
-  return WebContents::FromRenderViewHost(RenderViewHost::From(rwh));
+  return nullptr;
 }
 
 std::vector<blink::WebCompositionUnderline>
diff --git a/content/browser/renderer_host/ime_adapter_android.h b/content/browser/renderer_host/ime_adapter_android.h
index 57610c066..288f4402 100644
--- a/content/browser/renderer_host/ime_adapter_android.h
+++ b/content/browser/renderer_host/ime_adapter_android.h
@@ -11,6 +11,7 @@
 
 #include "base/android/jni_weak_ref.h"
 #include "base/strings/string16.h"
+#include "content/common/content_export.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace blink {
@@ -24,14 +25,13 @@
 class RenderFrameHost;
 class RenderWidgetHostImpl;
 class RenderWidgetHostViewAndroid;
-class WebContents;
 
 // This class is in charge of dispatching key events from the java side
 // and forward to renderer along with input method results via
 // corresponding host view.
 // Ownership of these objects remains on the native side (see
 // RenderWidgetHostViewAndroid).
-class ImeAdapterAndroid {
+class CONTENT_EXPORT ImeAdapterAndroid {
  public:
   explicit ImeAdapterAndroid(RenderWidgetHostViewAndroid* rwhva);
   ~ImeAdapterAndroid();
@@ -86,10 +86,14 @@
   void FocusedNodeChanged(bool is_editable_node);
   void SetCharacterBounds(const std::vector<gfx::RectF>& rects);
 
+  base::android::ScopedJavaLocalRef<jobject> java_ime_adapter_for_testing(
+      JNIEnv* env) {
+    return java_ime_adapter_.get(env);
+  }
+
  private:
-  RenderWidgetHostImpl* GetRenderWidgetHostImpl();
+  RenderWidgetHostImpl* GetFocusedWidget();
   RenderFrameHost* GetFocusedFrame();
-  WebContents* GetWebContents();
   std::vector<blink::WebCompositionUnderline> GetUnderlinesFromSpans(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
diff --git a/content/browser/renderer_host/input/web_input_event_builders_android.cc b/content/browser/renderer_host/input/web_input_event_builders_android.cc
index 9bdd73f..059192e 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_android.cc
+++ b/content/browser/renderer_host/input/web_input_event_builders_android.cc
@@ -10,6 +10,7 @@
 #include "ui/events/android/key_event_utils.h"
 #include "ui/events/android/motion_event_android.h"
 #include "ui/events/blink/blink_event_util.h"
+#include "ui/events/event_constants.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
 #include "ui/events/keycodes/keyboard_code_conversion.h"
@@ -110,20 +111,18 @@
   return result;
 }
 
-WebMouseEvent WebMouseEventBuilder::Build(
-      WebInputEvent::Type type,
-      double time_sec,
-      int window_x,
-      int window_y,
-      int modifiers,
-      int click_count,
-      int pointer_id,
-      float pressure,
-      float orientation_rad,
-      float tilt_rad,
-      int changed_button,
-      int tool_type) {
-
+WebMouseEvent WebMouseEventBuilder::Build(WebInputEvent::Type type,
+                                          double time_sec,
+                                          int window_x,
+                                          int window_y,
+                                          int modifiers,
+                                          int click_count,
+                                          int pointer_id,
+                                          float pressure,
+                                          float orientation_rad,
+                                          float tilt_rad,
+                                          int action_button,
+                                          int tool_type) {
   DCHECK(WebInputEvent::isMouseEventType(type));
   WebMouseEvent result(type, ui::EventFlagsToWebEventModifiers(modifiers),
                        time_sec);
@@ -134,14 +133,23 @@
   result.windowY = window_y;
   result.clickCount = click_count;
 
-  ui::SetWebPointerPropertiesFromMotionEventData(
-      result,
-      pointer_id,
-      pressure,
-      orientation_rad,
-      tilt_rad,
-      changed_button,
-      tool_type);
+  int button = action_button;
+  // For events other than MouseDown/Up, action_button is not defined. So we are
+  // determining |button| value from |modifiers| as is done in other platforms.
+  if (type != WebInputEvent::MouseDown && type != WebInputEvent::MouseUp) {
+    if (modifiers & ui::EF_LEFT_MOUSE_BUTTON)
+      button = ui::MotionEvent::BUTTON_PRIMARY;
+    else if (modifiers & ui::EF_MIDDLE_MOUSE_BUTTON)
+      button = ui::MotionEvent::BUTTON_TERTIARY;
+    else if (modifiers & ui::EF_RIGHT_MOUSE_BUTTON)
+      button = ui::MotionEvent::BUTTON_SECONDARY;
+    else
+      button = 0;
+  }
+
+  ui::SetWebPointerPropertiesFromMotionEventData(result, pointer_id, pressure,
+                                                 orientation_rad, tilt_rad,
+                                                 button, tool_type);
 
   return result;
 }
diff --git a/content/browser/renderer_host/input/web_input_event_builders_android.h b/content/browser/renderer_host/input/web_input_event_builders_android.h
index 6860d70..8dded19c 100644
--- a/content/browser/renderer_host/input/web_input_event_builders_android.h
+++ b/content/browser/renderer_host/input/web_input_event_builders_android.h
@@ -18,19 +18,18 @@
 
 class WebMouseEventBuilder {
  public:
-  static blink::WebMouseEvent Build(
-      blink::WebInputEvent::Type type,
-      double time_sec,
-      int window_x,
-      int window_y,
-      int modifiers,
-      int click_count,
-      int pointer_id,
-      float pressure,
-      float orientation_rad,
-      float tilt_rad,
-      int changed_button,
-      int tool_type);
+  static blink::WebMouseEvent Build(blink::WebInputEvent::Type type,
+                                    double time_sec,
+                                    int window_x,
+                                    int window_y,
+                                    int modifiers,
+                                    int click_count,
+                                    int pointer_id,
+                                    float pressure,
+                                    float orientation_rad,
+                                    float tilt_rad,
+                                    int action_button,
+                                    int tool_type);
 };
 
 class WebMouseWheelEventBuilder {
diff --git a/content/browser/renderer_host/media/media_capture_devices_impl.cc b/content/browser/renderer_host/media/media_capture_devices_impl.cc
index 9847d95..10825692 100644
--- a/content/browser/renderer_host/media/media_capture_devices_impl.cc
+++ b/content/browser/renderer_host/media/media_capture_devices_impl.cc
@@ -51,6 +51,33 @@
   return video_devices_;
 }
 
+void MediaCaptureDevicesImpl::AddVideoCaptureObserver(
+    media::VideoCaptureObserver* observer) {
+  MediaStreamManager* media_stream_manager =
+      BrowserMainLoop::GetInstance()->media_stream_manager();
+  if (media_stream_manager != nullptr) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&MediaStreamManager::AddVideoCaptureObserver,
+                   base::Unretained(media_stream_manager), observer));
+  } else {
+    DVLOG(3) << "media_stream_manager is null.";
+  }
+}
+
+void MediaCaptureDevicesImpl::RemoveAllVideoCaptureObservers() {
+  MediaStreamManager* media_stream_manager =
+      BrowserMainLoop::GetInstance()->media_stream_manager();
+  if (media_stream_manager != nullptr) {
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&MediaStreamManager::RemoveAllVideoCaptureObservers,
+                   base::Unretained(media_stream_manager)));
+  } else {
+    DVLOG(3) << "media_stream_manager is null.";
+  }
+}
+
 void MediaCaptureDevicesImpl::OnAudioCaptureDevicesChanged(
     const MediaStreamDevices& devices) {
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
diff --git a/content/browser/renderer_host/media/media_capture_devices_impl.h b/content/browser/renderer_host/media/media_capture_devices_impl.h
index 28d155c..d251ab59d 100644
--- a/content/browser/renderer_host/media/media_capture_devices_impl.h
+++ b/content/browser/renderer_host/media/media_capture_devices_impl.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "content/public/browser/media_capture_devices.h"
+#include "media/base/video_facing.h"
 
 namespace content {
 
@@ -18,6 +19,8 @@
   // Overriden from MediaCaptureDevices
   const MediaStreamDevices& GetAudioCaptureDevices() override;
   const MediaStreamDevices& GetVideoCaptureDevices() override;
+  void AddVideoCaptureObserver(media::VideoCaptureObserver* observer) override;
+  void RemoveAllVideoCaptureObservers() override;
 
   // Called by MediaStreamManager to notify the change of media capture
   // devices, these 2 methods are called in IO thread.
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index e8d7f7de..2910ecd 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -520,7 +520,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(IsValidMediaDeviceType(type));
 
-  for (const auto& subscriber : device_change_subscribers_[type]) {
+  for (auto* subscriber : device_change_subscribers_[type]) {
     subscriber->OnDevicesChanged(type, snapshot);
   }
 }
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 1665fe3..12d5f829 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -450,6 +450,21 @@
   return media_devices_manager_.get();
 }
 
+void MediaStreamManager::AddVideoCaptureObserver(
+    media::VideoCaptureObserver* capture_observer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (video_capture_manager_) {
+    video_capture_manager_->AddVideoCaptureObserver(capture_observer);
+  }
+}
+
+void MediaStreamManager::RemoveAllVideoCaptureObservers() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (video_capture_manager_) {
+    video_capture_manager_->RemoveAllVideoCaptureObservers();
+  }
+}
+
 std::string MediaStreamManager::MakeMediaAccessRequest(
     int render_process_id,
     int render_frame_id,
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 6b4c3c45..d152fe1 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -45,6 +45,7 @@
 #include "content/common/media/media_devices.h"
 #include "content/common/media/media_stream_options.h"
 #include "content/public/browser/media_request_state.h"
+#include "media/base/video_facing.h"
 
 namespace media {
 class AudioManager;
@@ -97,6 +98,16 @@
   // Used to access MediaDevicesManager.
   MediaDevicesManager* media_devices_manager();
 
+  // AddVideoCaptureObserver() and RemoveAllVideoCaptureObservers() must be
+  // called after InitializeDeviceManagersOnIOThread() and before
+  // WillDestroyCurrentMessageLoop(). They can be called more than once and it's
+  // ok to not call at all if the client is not interested in receiving
+  // media::VideoCaptureObserver callbacks.
+  // The methods must be called on BrowserThread::IO threads. The callbacks of
+  // media::VideoCaptureObserver also arrive on BrowserThread::IO threads.
+  void AddVideoCaptureObserver(media::VideoCaptureObserver* capture_observer);
+  void RemoveAllVideoCaptureObservers();
+
   // Creates a new media access request which is identified by a unique string
   // that's returned to the caller. This will trigger the infobar and ask users
   // for access to the device. |render_process_id| and |render_frame_id| are
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 44094c7..651aef8 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -34,6 +34,7 @@
 #include "content/public/common/media_stream_request.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
+#include "media/base/video_facing.h"
 #include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
 #include "media/capture/video/video_capture_device.h"
@@ -339,6 +340,18 @@
   DCHECK(device_start_queue_.empty());
 }
 
+void VideoCaptureManager::AddVideoCaptureObserver(
+    media::VideoCaptureObserver* observer) {
+  DCHECK(observer);
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  capture_observers_.AddObserver(observer);
+}
+
+void VideoCaptureManager::RemoveAllVideoCaptureObservers() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  capture_observers_.Clear();
+}
+
 void VideoCaptureManager::RegisterListener(
     MediaStreamProviderListener* listener) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -468,6 +481,12 @@
     }
   }
 
+  const DeviceInfo* device_info = GetDeviceInfoById(entry->id);
+  if (device_info != nullptr) {
+    for (auto& observer : capture_observers_)
+      observer.OnVideoCaptureStopped(device_info->descriptor.facing);
+  }
+
   DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id
            << " serial_id = " << entry->serial_id << ".";
   entry->video_capture_controller.OnLog(
@@ -524,6 +543,9 @@
                                found->descriptor.GetNameAndModel().c_str(),
                                found->descriptor.GetCaptureApiTypeString()));
 
+        for (auto& observer : capture_observers_)
+          observer.OnVideoCaptureStarted(found->descriptor.facing);
+
         start_capture_function =
             base::Bind(&VideoCaptureManager::DoStartDeviceCaptureOnDeviceThread,
                        this, found->descriptor, request->params(),
diff --git a/content/browser/renderer_host/media/video_capture_manager.h b/content/browser/renderer_host/media/video_capture_manager.h
index 569910d0..a1d96a1 100644
--- a/content/browser/renderer_host/media/video_capture_manager.h
+++ b/content/browser/renderer_host/media/video_capture_manager.h
@@ -21,6 +21,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/observer_list.h"
 #include "base/process/process_handle.h"
 #include "base/threading/thread_checker.h"
 #include "base/timer/elapsed_timer.h"
@@ -29,6 +30,7 @@
 #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
 #include "content/common/content_export.h"
 #include "content/common/media/media_stream_options.h"
+#include "media/base/video_facing.h"
 #include "media/capture/video/video_capture_device.h"
 #include "media/capture/video/video_capture_device_factory.h"
 #include "media/capture/video_capture_types.h"
@@ -54,6 +56,16 @@
       std::unique_ptr<media::VideoCaptureDeviceFactory> factory,
       scoped_refptr<base::SingleThreadTaskRunner> device_task_runner);
 
+  // AddVideoCaptureObserver() can be called only before any devices are opened.
+  // RemoveAllVideoCaptureObservers() can be called only after all devices
+  // are closed.
+  // They can be called more than once and it's ok to not call at all if the
+  // client is not interested in receiving media::VideoCaptureObserver callacks.
+  // This methods can be called on whatever thread. The callbacks of
+  // media::VideoCaptureObserver arrive on browser IO thread.
+  void AddVideoCaptureObserver(media::VideoCaptureObserver* observer);
+  void RemoveAllVideoCaptureObservers();
+
   // Implements MediaStreamProvider.
   void RegisterListener(MediaStreamProviderListener* listener) override;
   void UnregisterListener() override;
@@ -341,6 +353,8 @@
   std::unique_ptr<media::VideoCaptureDeviceFactory>
       video_capture_device_factory_;
 
+  base::ObserverList<media::VideoCaptureObserver> capture_observers_;
+
   // Local cache of the enumerated video capture devices' names and capture
   // supported formats. A snapshot of the current devices and their capabilities
   // is composed in VideoCaptureDeviceFactory::EnumerateDeviceNames() and
diff --git a/content/browser/renderer_host/media/video_capture_manager_unittest.cc b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
index 8525a34..e5e8e82 100644
--- a/content/browser/renderer_host/media/video_capture_manager_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_manager_unittest.cc
@@ -94,6 +94,9 @@
     DISALLOW_COPY_AND_ASSIGN(WrappedDevice);
   };
 
+  static const media::VideoFacingMode DEFAULT_FACING =
+      media::VideoFacingMode::MEDIA_VIDEO_FACING_USER;
+
   WrappedDeviceFactory() : FakeVideoCaptureDeviceFactory() {}
   ~WrappedDeviceFactory() final {}
 
@@ -103,6 +106,16 @@
         FakeVideoCaptureDeviceFactory::CreateDevice(device_descriptor), this);
   }
 
+  void GetDeviceDescriptors(
+      media::VideoCaptureDeviceDescriptors* device_descriptors) override {
+    media::FakeVideoCaptureDeviceFactory::GetDeviceDescriptors(
+        device_descriptors);
+    for (auto& descriptor : *device_descriptors) {
+      if (descriptor.facing == media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE)
+        descriptor.facing = DEFAULT_FACING;
+    }
+  }
+
   MOCK_METHOD0(WillSuspendDevice, void());
   MOCK_METHOD0(WillResumeDevice, void());
 
@@ -150,6 +163,13 @@
   void OnGotControllerCallback(VideoCaptureControllerID) {}
 };
 
+// Input argument for testing AddVideoCaptureObserver().
+class MockVideoCaptureObserver : public media::VideoCaptureObserver {
+ public:
+  MOCK_METHOD1(OnVideoCaptureStarted, void(media::VideoFacingMode));
+  MOCK_METHOD1(OnVideoCaptureStopped, void(media::VideoFacingMode));
+};
+
 }  // namespace
 
 // Test class
@@ -331,6 +351,27 @@
   vcm_->UnregisterListener();
 }
 
+TEST_F(VideoCaptureManagerTest, AddObserver) {
+  InSequence s;
+  MockVideoCaptureObserver observer;
+  vcm_->AddVideoCaptureObserver(&observer);
+
+  EXPECT_CALL(observer,
+              OnVideoCaptureStarted(WrappedDeviceFactory::DEFAULT_FACING));
+  EXPECT_CALL(observer,
+              OnVideoCaptureStopped(WrappedDeviceFactory::DEFAULT_FACING));
+
+  int video_session_id = vcm_->Open(devices_.front());
+  VideoCaptureControllerID client_id = StartClient(video_session_id, true);
+
+  StopClient(client_id);
+  vcm_->Close(video_session_id);
+
+  // Wait to check callbacks before removing the listener.
+  base::RunLoop().RunUntilIdle();
+  vcm_->UnregisterListener();
+}
+
 // Open the same device twice.
 TEST_F(VideoCaptureManagerTest, OpenTwice) {
   InSequence s;
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 1f226d8..ffa31e6b 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -483,7 +483,7 @@
 
   gfx::Point transformed_point;
   // Send MouseLeaves.
-  for (auto view : exited_views) {
+  for (auto* view : exited_views) {
     blink::WebMouseEvent mouse_leave(*event);
     mouse_leave.setType(blink::WebInputEvent::MouseLeave);
     // There is a chance of a race if the last target has recently created a
@@ -512,7 +512,7 @@
   }
 
   // Send MouseMoves to trigger MouseEnter handlers.
-  for (auto view : entered_views) {
+  for (auto* view : entered_views) {
     if (view == target)
       continue;
     blink::WebMouseEvent mouse_enter(*event);
@@ -702,7 +702,7 @@
     // TODO(wjmaclean,kenrb,tdresser): When scroll latching lands, we can
     // revisit how this code should work.
     // https://crbug.com/526463
-    auto rwhi =
+    auto* rwhi =
         static_cast<RenderWidgetHostImpl*>(root_view->GetRenderWidgetHost());
     // If the root view is the current gesture target, then we explicitly don't
     // send a GestureScrollBegin, as by the time we see GesturePinchBegin there
@@ -720,7 +720,7 @@
       in_touchscreen_gesture_pinch_ = false;
       // If the root view wasn't already receiving the gesture stream, then we
       // need to wrap the diverted pinch events in a GestureScrollBegin/End.
-      auto rwhi =
+      auto* rwhi =
           static_cast<RenderWidgetHostImpl*>(root_view->GetRenderWidgetHost());
       if (root_view != touchscreen_gesture_target_.target &&
           gesture_pinch_did_send_scroll_begin_ &&
diff --git a/content/browser/renderer_host/render_widget_host_unittest.cc b/content/browser/renderer_host/render_widget_host_unittest.cc
index 005ab9ca..972f340 100644
--- a/content/browser/renderer_host/render_widget_host_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_unittest.cc
@@ -814,7 +814,7 @@
   screen_info.orientation_angle = 0;
   screen_info.orientation_type = SCREEN_ORIENTATION_VALUES_PORTRAIT_PRIMARY;
 
-  auto host_delegate =
+  auto* host_delegate =
       static_cast<MockRenderWidgetHostDelegate*>(host_->delegate());
 
   host_delegate->SetScreenInfo(screen_info);
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 3d1d70d..260407d6 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1592,7 +1592,7 @@
 
 void RenderWidgetHostViewAndroid::SendMouseEvent(
     const ui::MotionEventAndroid& motion_event,
-    int changed_button) {
+    int action_button) {
   blink::WebInputEvent::Type webMouseEventType =
       ui::ToWebMouseEventType(motion_event.GetAction());
 
@@ -1607,7 +1607,7 @@
       motion_event.GetPressure(0),
       motion_event.GetOrientation(0),
       motion_event.GetTilt(0),
-      changed_button,
+      action_button,
       motion_event.GetToolType(0));
 
   if (host_)
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index a52a7a1..9ac9184 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -198,7 +198,7 @@
   void SetContentViewCore(ContentViewCoreImpl* content_view_core);
   SkColor GetCachedBackgroundColor() const;
   void SendKeyEvent(const NativeWebKeyboardEvent& event);
-  void SendMouseEvent(const ui::MotionEventAndroid&, int changed_button);
+  void SendMouseEvent(const ui::MotionEventAndroid&, int action_button);
   void SendMouseWheelEvent(const blink::WebMouseWheelEvent& event);
   void SendGestureEvent(const blink::WebGestureEvent& event);
 
@@ -250,6 +250,8 @@
   void OnTextSelectionChanged(TextInputManager* text_input_manager,
                               RenderWidgetHostViewBase* updated_view) override;
 
+  ImeAdapterAndroid* ime_adapter_for_testing() { return &ime_adapter_android_; }
+
  private:
   void RunAckCallbacks();
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
index 36665017..5dcdbe3 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -1593,7 +1593,7 @@
   // which sends a ViewMsg_Resize::ID message to the renderer.
   EXPECT_EQ(1u, sink_->message_count());
   EXPECT_EQ(ViewMsg_Resize::ID, sink_->GetMessageAt(0)->type());
-  auto view_delegate = static_cast<MockRenderWidgetHostDelegate*>(
+  auto* view_delegate = static_cast<MockRenderWidgetHostDelegate*>(
       static_cast<RenderWidgetHostImpl*>(view_->GetRenderWidgetHost())
           ->delegate());
   EXPECT_EQ(2.0f, view_delegate->get_last_device_scale_factor());
diff --git a/content/browser/service_worker/foreign_fetch_request_handler.cc b/content/browser/service_worker/foreign_fetch_request_handler.cc
index da962d6..58675b0 100644
--- a/content/browser/service_worker/foreign_fetch_request_handler.cc
+++ b/content/browser/service_worker/foreign_fetch_request_handler.cc
@@ -259,7 +259,7 @@
     return;
   }
 
-  auto request_info = ResourceRequestInfo::ForRequest(job->request());
+  auto* request_info = ResourceRequestInfo::ForRequest(job->request());
   base::Callback<WebContents*(void)> web_contents_getter;
   if (request_info)
     web_contents_getter = request_info->GetWebContentsGetterForRequest();
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 00bbf733..2d497d5 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -93,6 +93,14 @@
 #include "ui/base/test/scoped_preferred_scroller_style_mac.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "content/browser/renderer_host/ime_adapter_android.h"
+#include "content/browser/renderer_host/render_widget_host_view_android.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -9410,4 +9418,135 @@
   EXPECT_TRUE(result);
 }
 
+#if defined(OS_ANDROID)
+class TextSelectionObserver : public TextInputManager::Observer {
+ public:
+  explicit TextSelectionObserver(TextInputManager* text_input_manager)
+      : text_input_manager_(text_input_manager) {
+    text_input_manager->AddObserver(this);
+  }
+
+  ~TextSelectionObserver() { text_input_manager_->RemoveObserver(this); }
+
+  void WaitForSelectedText(const std::string& expected_text) {
+    if (last_selected_text_ == expected_text)
+      return;
+    expected_text_ = expected_text;
+    loop_runner_ = new MessageLoopRunner();
+    loop_runner_->Run();
+  }
+
+ private:
+  void OnTextSelectionChanged(TextInputManager* text_input_manager,
+                              RenderWidgetHostViewBase* updated_view) override {
+    base::string16 text;
+    if (text_input_manager->GetTextSelection(updated_view)
+            ->GetSelectedText(&text)) {
+      last_selected_text_ = base::UTF16ToUTF8(text);
+      if (last_selected_text_ == expected_text_ && loop_runner_)
+        loop_runner_->Quit();
+    }
+  }
+  TextInputManager* const text_input_manager_;
+  std::string last_selected_text_;
+  std::string expected_text_;
+  scoped_refptr<MessageLoopRunner> loop_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(TextSelectionObserver);
+};
+
+class SitePerProcessAndroidImeTest : public SitePerProcessBrowserTest {
+ public:
+  SitePerProcessAndroidImeTest() : SitePerProcessBrowserTest() {}
+  ~SitePerProcessAndroidImeTest() override {}
+
+ protected:
+  ImeAdapterAndroid* ime_adapter() {
+    return static_cast<RenderWidgetHostViewAndroid*>(
+               web_contents()->GetRenderWidgetHostView())
+        ->ime_adapter_for_testing();
+  }
+
+  std::string GetInputValue(RenderFrameHostImpl* frame) {
+    std::string result;
+    EXPECT_TRUE(ExecuteScriptAndExtractString(
+        frame, "window.domAutomationController.send(input.value);", &result));
+    return result;
+  }
+
+  void FocusInputInFrame(RenderFrameHostImpl* frame) {
+    ASSERT_TRUE(ExecuteScript(frame, "window.focus(); input.focus();"));
+  }
+
+  // Creates a page with multiple (nested) OOPIFs and populates all of them
+  // with an <input> element along with the required handlers for the test.
+  void LoadPage() {
+    ASSERT_TRUE(NavigateToURL(
+        shell(),
+        GURL(embedded_test_server()->GetURL(
+            "a.com", "/cross_site_iframe_factory.html?a(b,c(a(b)))"))));
+    FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+    frames_.push_back(root->current_frame_host());
+    frames_.push_back(root->child_at(0)->current_frame_host());
+    frames_.push_back(root->child_at(1)->current_frame_host());
+    frames_.push_back(root->child_at(1)->child_at(0)->current_frame_host());
+    frames_.push_back(
+        root->child_at(1)->child_at(0)->child_at(0)->current_frame_host());
+
+    // Adds an <input> to frame and sets up a handler for |window.oninput|. When
+    // the input event is fired (by changing the value of <input> element), the
+    // handler will select all the text so that the corresponding text selection
+    // update on the browser side notifies the test about input insertion.
+    std::string add_input_script =
+        "var input = document.createElement('input');"
+        "document.body.appendChild(input);"
+        "window.oninput = function() {"
+        "  input.select();"
+        "};";
+
+    for (auto* frame : frames_)
+      ASSERT_TRUE(ExecuteScript(frame, add_input_script));
+  }
+
+  // This methods tries to commit |text| by simulating a native call from Java.
+  void CommitText(const char* text) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+
+    // A valid caller is needed for ImeAdapterAndroid::GetUnderlinesFromSpans.
+    base::android::ScopedJavaLocalRef<jobject> caller =
+        ime_adapter()->java_ime_adapter_for_testing(env);
+
+    // Input string from Java side.
+    base::android::ScopedJavaLocalRef<jstring> jtext =
+        base::android::ConvertUTF8ToJavaString(env, text);
+
+    // Simulating a native call from Java side.
+    ime_adapter()->CommitText(
+        env, base::android::JavaParamRef<jobject>(env, caller.obj()),
+        base::android::JavaParamRef<jobject>(env, jtext.obj()),
+        base::android::JavaParamRef<jstring>(env, jtext.obj()), 0);
+  }
+
+  std::vector<RenderFrameHostImpl*> frames_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SitePerProcessAndroidImeTest);
+};
+
+// This test verifies that committing text will be applied on the focused
+// RenderWidgetHost.
+IN_PROC_BROWSER_TEST_F(SitePerProcessAndroidImeTest,
+                       CommitTextForFocusedWidget) {
+  LoadPage();
+  TextSelectionObserver selection_observer(
+      web_contents()->GetTextInputManager());
+  for (size_t index = 0; index < frames_.size(); ++index) {
+    std::string text = base::StringPrintf("text%zu", index);
+    FocusInputInFrame(frames_[index]);
+    CommitText(text.c_str());
+    selection_observer.WaitForSelectedText(text);
+  }
+}
+#endif  // OS_ANDROID
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 2daf76a0..244b5d4 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -930,7 +930,7 @@
 
 RenderWidgetHostView* WebContentsImpl::GetFullscreenRenderWidgetHostView()
     const {
-  if (auto widget_host = GetFullscreenRenderWidgetHost())
+  if (auto* widget_host = GetFullscreenRenderWidgetHost())
     return widget_host->GetView();
   return nullptr;
 }
@@ -2587,6 +2587,24 @@
     return NULL;
 
   WebContents* new_contents = delegate_->OpenURLFromTab(this, params);
+
+  RenderFrameHost* source_render_frame_host = RenderFrameHost::FromID(
+      params.source_render_process_id, params.source_render_frame_id);
+
+  if (source_render_frame_host && params.source_site_instance) {
+    CHECK_EQ(source_render_frame_host->GetSiteInstance(),
+             params.source_site_instance.get());
+  }
+
+  if (new_contents && source_render_frame_host && new_contents != this) {
+    for (auto& observer : observers_) {
+      observer.DidOpenRequestedURL(new_contents, source_render_frame_host,
+                                   params.url, params.referrer,
+                                   params.disposition, params.transition,
+                                   params.started_from_context_menu);
+    }
+  }
+
   return new_contents;
 }
 
@@ -3380,25 +3398,6 @@
     observer.DidStartNavigationToPendingEntry(url, reload_type);
 }
 
-void WebContentsImpl::RequestOpenURL(RenderFrameHostImpl* render_frame_host,
-                                     const OpenURLParams& params) {
-  // OpenURL can blow away the source RFH. Use the process/frame routing ID as a
-  // weak pointer of sorts.
-  const int32_t process_id = render_frame_host->GetProcess()->GetID();
-  const int32_t frame_id = render_frame_host->GetRoutingID();
-
-  WebContents* new_contents = OpenURL(params);
-
-  if (new_contents && RenderFrameHost::FromID(process_id, frame_id)) {
-    // Notify observers.
-    for (auto& observer : observers_) {
-      observer.DidOpenRequestedURL(new_contents, render_frame_host, params.url,
-                                   params.referrer, params.disposition,
-                                   params.transition);
-    }
-  }
-}
-
 bool WebContentsImpl::ShouldTransferNavigation(bool is_main_frame_navigation) {
   if (!delegate_)
     return true;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index c325f5a..813e35e 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -599,8 +599,6 @@
   void NotifyChangedNavigationState(InvalidateTypes changed_flags) override;
   void DidStartNavigationToPendingEntry(const GURL& url,
                                         ReloadType reload_type) override;
-  void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
-                      const OpenURLParams& params) override;
   bool ShouldTransferNavigation(bool is_main_frame_navigation) override;
   bool ShouldPreserveAbortedURLs() override;
   void DidStartLoading(FrameTreeNode* frame_tree_node,
diff --git a/content/browser/web_contents/web_contents_view_child_frame.cc b/content/browser/web_contents/web_contents_view_child_frame.cc
index 60b0f56b..74a587a9 100644
--- a/content/browser/web_contents/web_contents_view_child_frame.cc
+++ b/content/browser/web_contents/web_contents_view_child_frame.cc
@@ -152,7 +152,7 @@
 }
 
 void WebContentsViewChildFrame::UpdateDragCursor(WebDragOperation operation) {
-  if (auto view = GetOuterDelegateView())
+  if (auto* view = GetOuterDelegateView())
     view->UpdateDragCursor(operation);
 }
 
@@ -187,7 +187,7 @@
     const gfx::Vector2d& image_offset,
     const DragEventSourceInfo& event_info,
     RenderWidgetHostImpl* source_rwh) {
-  if (auto view = GetOuterDelegateView()) {
+  if (auto* view = GetOuterDelegateView()) {
     view->StartDragging(
         drop_data, ops, image, image_offset, event_info, source_rwh);
   } else {
diff --git a/content/browser/websockets/websocket_manager.cc b/content/browser/websockets/websocket_manager.cc
index 4d0e743c..87ef048 100644
--- a/content/browser/websockets/websocket_manager.cc
+++ b/content/browser/websockets/websocket_manager.cc
@@ -115,7 +115,7 @@
   if (!context_destroyed_ && url_request_context_getter_)
     url_request_context_getter_->RemoveObserver(this);
 
-  for (auto impl : impls_) {
+  for (auto* impl : impls_) {
     impl->GoAway();
     delete impl;
   }
@@ -225,7 +225,7 @@
 void WebSocketManager::OnContextShuttingDown() {
   context_destroyed_ = true;
   url_request_context_getter_ = nullptr;
-  for (const auto& impl : impls_) {
+  for (auto* impl : impls_) {
     impl->GoAway();
     delete impl;
   }
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index 904cb26..c888f8c 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -21,7 +21,7 @@
                           content::NUM_MEDIA_TYPES - 1)
 
 IPC_ENUM_TRAITS_MAX_VALUE(media::VideoFacingMode,
-                          media::NUM_MEDIA_VIDEO_FACING_MODE - 1)
+                          media::NUM_MEDIA_VIDEO_FACING_MODES - 1)
 
 IPC_ENUM_TRAITS_MAX_VALUE(content::MediaStreamRequestResult,
                           content::NUM_MEDIA_REQUEST_RESULTS - 1)
diff --git a/content/common/url_schemes.cc b/content/common/url_schemes.cc
index e2a9a2e..29a3c85 100644
--- a/content/common/url_schemes.cc
+++ b/content/common/url_schemes.cc
@@ -79,7 +79,7 @@
   // Combine the default savable schemes with the additional ones given.
   delete savable_schemes;
   savable_schemes = new std::vector<std::string>;
-  for (auto& default_scheme : kDefaultSavableSchemes)
+  for (auto* default_scheme : kDefaultSavableSchemes)
     savable_schemes->push_back(default_scheme);
   savable_schemes->insert(savable_schemes->end(),
                           schemes.savable_schemes.begin(),
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 843b399..ac344eb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -40,6 +40,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
 
+import org.chromium.base.CommandLine;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ObserverList.RewindableIterator;
 import org.chromium.base.TraceEvent;
@@ -59,6 +60,7 @@
 import org.chromium.content.browser.input.SelectPopupDialog;
 import org.chromium.content.browser.input.SelectPopupDropdown;
 import org.chromium.content.browser.input.SelectPopupItem;
+import org.chromium.content.common.ContentSwitches;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
 import org.chromium.content_public.browser.ActionModeCallbackHelper;
@@ -353,6 +355,9 @@
     private float mCurrentTouchOffsetX;
     private float mCurrentTouchOffsetY;
 
+    // True if we want to disable Android native event batching and use compositor event queue.
+    private boolean mShouldRequestUnbufferedDispatch;
+
     // Whether the ContentViewCore requires the WebContents to be fullscreen in order to lock the
     // screen orientation.
     private boolean mFullscreenRequiredForOrientationLock = true;
@@ -584,6 +589,9 @@
         mSelectionPopupController.setContainerView(getContainerView());
 
         mWebContentsObserver = new ContentViewWebContentsObserver(this);
+
+        mShouldRequestUnbufferedDispatch = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                && CommandLine.getInstance().hasSwitch(ContentSwitches.REQUEST_UNBUFFERED_DISPATCH);
     }
 
     /**
@@ -996,6 +1004,9 @@
             int eventAction = event.getActionMasked();
 
             if (eventAction == MotionEvent.ACTION_DOWN) {
+                if (mShouldRequestUnbufferedDispatch) {
+                    requestUnbufferedDispatch(event);
+                }
                 cancelRequestToScrollFocusedEditableNodeIntoView();
             }
 
@@ -2457,6 +2468,11 @@
         viewNode.asyncCommit();
     }
 
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private void requestUnbufferedDispatch(MotionEvent touchDownEvent) {
+        mContainerView.requestUnbufferedDispatch(touchDownEvent);
+    }
+
     @TargetApi(Build.VERSION_CODES.KITKAT)
     @Override
     public void onSystemCaptioningChanged(TextTrackSettings settings) {
@@ -2762,7 +2778,7 @@
 
     private native int nativeSendMouseEvent(long nativeContentViewCoreImpl, long timeMs, int action,
             float x, float y, int pointerId, float pressure, float orientaton, float tilt,
-            int changedButton, int buttonState, int metaState, int toolType);
+            int actionButton, int buttonState, int metaState, int toolType);
 
     private native int nativeSendMouseWheelEvent(long nativeContentViewCoreImpl, long timeMs,
             float x, float y, float ticksX, float ticksY, float pixelsPerTick);
diff --git a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java
index a356d08..528f6df 100644
--- a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java
+++ b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java
@@ -78,6 +78,9 @@
     public static final String USE_FAKE_DEVICE_FOR_MEDIA_STREAM =
             "use-fake-device-for-media-stream";
 
+    // Disable motion event batching through View.requestUnbufferedDispatch().
+    public static final String REQUEST_UNBUFFERED_DISPATCH = "request-unbuffered-dispatch";
+
     // Prevent instantiation.
     private ContentSwitches() {}
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java
index 3ecf1a2..4a6fa245 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentDetectionTestBase.java
@@ -67,7 +67,7 @@
                 callbackHelperContainer.getOnStartContentIntentHelper();
         int currentCallCount = onStartContentIntentHelper.getCallCount();
 
-        DOMUtils.clickNode(this, getContentViewCore(), id);
+        DOMUtils.clickNode(getContentViewCore(), id);
 
         onStartContentIntentHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
                 TimeUnit.SECONDS);
@@ -87,7 +87,7 @@
                 callbackHelperContainer.getOnPageFinishedHelper();
         int currentCallCount = onPageFinishedHelper.getCallCount();
 
-        DOMUtils.clickNode(this, getContentViewCore(), id);
+        DOMUtils.clickNode(getContentViewCore(), id);
 
         onPageFinishedHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_SECONDS,
                 TimeUnit.SECONDS);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index 95126f44..4e061d8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -62,7 +62,7 @@
     public void testSelectionClearedAfterLossOfFocus() throws Throwable {
         requestFocusOnUiThread(true);
 
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
 
         requestFocusOnUiThread(false);
@@ -80,7 +80,7 @@
     public void testSelectionPreservedAfterLossOfFocusIfRequested() throws Throwable {
         requestFocusOnUiThread(true);
 
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
 
@@ -103,7 +103,7 @@
     @Feature({"TextSelection"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectionPreservedAfterReshown() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
 
@@ -120,7 +120,7 @@
     @Feature({"TextSelection"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectionPreservedAfterReattached() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
 
@@ -140,9 +140,9 @@
     @DisabledTest(message = "https://crbug.com/592428")
     public void testPastePopupNotShownOnLongPressingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         waitForPastePopupStatus(false);
     }
@@ -151,9 +151,9 @@
     @Feature({"TextInput"})
     public void testPastePopupClearedOnTappingEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
-        DOMUtils.clickNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.clickNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(false);
     }
 
@@ -161,9 +161,9 @@
     @Feature({"TextInput"})
     public void testPastePopupClearedOnTappingNonEmptyInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
-        DOMUtils.clickNode(this, mContentViewCore, "input_text");
+        DOMUtils.clickNode(mContentViewCore, "input_text");
         waitForPastePopupStatus(false);
     }
 
@@ -171,9 +171,9 @@
     @Feature({"TextInput"})
     public void testPastePopupClearedOnTappingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
-        DOMUtils.clickNode(this, mContentViewCore, "plain_text_2");
+        DOMUtils.clickNode(mContentViewCore, "plain_text_2");
         waitForPastePopupStatus(false);
     }
 
@@ -181,9 +181,9 @@
     @Feature({"TextInput"})
     public void testPastePopupClearedOnLongPressingOutsideInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_2");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_2");
         waitForPastePopupStatus(false);
     }
 
@@ -191,10 +191,10 @@
     @Feature({"TextInput"})
     public void testPastePopupNotShownOnLongPressingDisabledInput() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
         waitForInsertion(true);
-        DOMUtils.longPressNode(this, mContentViewCore, "disabled_text");
+        DOMUtils.longPressNode(mContentViewCore, "disabled_text");
         waitForPastePopupStatus(false);
         waitForInsertion(false);
     }
@@ -206,7 +206,7 @@
     @DisabledTest(message = "https://crbug.com/592428")
     public void testPastePopupDismissedOnDestroy() throws Throwable {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "empty_input_text");
+        DOMUtils.longPressNode(mContentViewCore, "empty_input_text");
         waitForPastePopupStatus(true);
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
@@ -221,7 +221,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testActionBarConfiguredCorrectlyForInput() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -233,7 +233,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testActionBarConfiguredCorrectlyForPassword() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -245,7 +245,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testActionBarConfiguredCorrectlyForPlainText() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -257,7 +257,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testActionBarConfiguredCorrectlyForTextArea() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -269,7 +269,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPlainTextCopy() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -281,7 +281,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarInputCopy() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -293,13 +293,13 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPasswordCopy() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarCopy();
         waitForClipboardContents(mContentViewCore.getContext(), "SamplePlainTextOne");
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -313,7 +313,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarTextAreaCopy() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -326,7 +326,7 @@
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPlainTextCut() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText(), "SamplePlainTextOne");
@@ -343,7 +343,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarInputCut() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText(), "SampleInputText");
@@ -360,7 +360,7 @@
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPasswordCut() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -376,7 +376,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarTextAreaCut() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText(), "SampleTextArea");
@@ -392,7 +392,7 @@
     @Feature({"TextSelection"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPlainTextSelectAll() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -405,7 +405,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarInputSelectAll() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -419,7 +419,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPasswordSelectAll() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -432,7 +432,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarTextAreaSelectAll() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -460,7 +460,7 @@
      */
     @DisabledTest(message = "http://crbug.com/606942")
     public void testCursorPositionAfterHidingActionMode() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
@@ -484,12 +484,12 @@
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarPlainTextPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarPaste();
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text_1");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         // Paste option won't be available for plain text.
@@ -504,7 +504,7 @@
         copyStringToClipboard("SampleTextToCopy");
 
         // Select the input field.
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
 
@@ -515,7 +515,7 @@
         assertFalse(mSelectionPopupController.hasSelection());
 
         // Ensure the new text matches the pasted text.
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals("SampleTextToCopy", mSelectionPopupController.getSelectedText());
@@ -530,7 +530,7 @@
         copyStringToClipboard("SamplePassword2");
 
         // Select the password field.
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText().length(),
@@ -546,7 +546,7 @@
         // Ensure the new text matches the pasted text. Note that we can't
         // actually compare strings as password field selections only provide
         // a placeholder with the correct length.
-        DOMUtils.longPressNode(this, mContentViewCore, "password");
+        DOMUtils.longPressNode(mContentViewCore, "password");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText().length(),
@@ -558,13 +558,13 @@
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarTextAreaPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
         selectActionBarPaste();
-        DOMUtils.clickNode(this, mContentViewCore, "plain_text_1");
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.clickNode(mContentViewCore, "plain_text_1");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertEquals(mSelectionPopupController.getSelectedText(), "SampleTextToCopy");
@@ -574,7 +574,7 @@
     @Feature({"TextInput"})
     @DisabledTest(message = "crbug.com/592428")
     public void testSelectActionBarSearchAndShareLaunchesNewTask() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         waitForSelectActionBarVisible(true);
         assertTrue(mSelectionPopupController.hasSelection());
         assertTrue(mSelectionPopupController.isActionModeValid());
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
index bf6c9db..a2ad3824 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewPopupZoomerTest.java
@@ -98,7 +98,7 @@
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
 
         // Once clicked, the popup should show up.
-        DOMUtils.clickNode(this, viewCore, "clickme");
+        DOMUtils.clickNode(viewCore, "clickme");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, true));
 
         // The shown popup should have valid dimensions eventually.
@@ -119,7 +119,7 @@
         final ViewGroup view = viewCore.getContainerView();
 
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, false));
-        DOMUtils.clickNode(this, viewCore, "clickme");
+        DOMUtils.clickNode(viewCore, "clickme");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria(view, true));
         sendKeys(KeyEvent.KEYCODE_BACK);
         // When device key is pressed, popup zoomer should hide if already showing.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
index c935edd..497299d 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/GestureDetectorResetTest.java
@@ -78,7 +78,7 @@
                 "test", "not clicked"));
 
         // Click the button.
-        DOMUtils.clickNode(this, contentViewCore, "button");
+        DOMUtils.clickNode(contentViewCore, "button");
 
         // After the click, the text on the page should say "clicked".
         CriteriaHelper.pollInstrumentationThread(new NodeContentsIsEqualToCriteria(
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
index 4b56c75..642f5666 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/VideoFullscreenOrientationLockTest.java
@@ -139,7 +139,7 @@
         DOMUtils.waitForMediaPlay(getWebContents(), VIDEO_ID);
 
         // Trigger requestFullscreen() via a click on a button.
-        assertTrue(DOMUtils.clickNode(this, getContentViewCore(), "fullscreen"));
+        assertTrue(DOMUtils.clickNode(getContentViewCore(), "fullscreen"));
         waitForContentsFullscreenState(true);
 
         // Should be landscape now, `waitForLandscapeOrientation` will throw otherwise.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index c129157c..41f43d8b 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -110,7 +110,7 @@
 
         mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
         DOMUtils.waitForNonZeroNodeBounds(mWebContents, "input_text");
-        boolean result = DOMUtils.clickNode(this, mContentViewCore, "input_text");
+        boolean result = DOMUtils.clickNode(mContentViewCore, "input_text");
 
         assertEquals("Failed to dispatch touch event.", true, result);
         assertWaitForKeyboardStatus(true);
@@ -148,7 +148,7 @@
         fullyLoadUrl(UrlUtils.getIsolatedTestFileUrl(INPUT_FORM_HTML));
         assertWaitForKeyboardStatus(false);
 
-        DOMUtils.clickNode(this, mContentViewCore, "input_text");
+        DOMUtils.clickNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
 
         // Hide keyboard when navigating.
@@ -257,7 +257,7 @@
         waitAndVerifyUpdateSelection(2, 3, 3, 2, 3);
 
         // Unexpected selection change occurs, e.g., the user clicks on an area.
-        DOMUtils.clickNode(this, mContentViewCore, "textarea");
+        DOMUtils.clickNode(mContentViewCore, "textarea");
         waitAndVerifyUpdateSelection(3, 5, 5, 2, 3);
         // Keyboard app finishes composition. We emulate this in TestInputMethodManagerWrapper.
         waitAndVerifyUpdateSelection(4, 5, 5, -1, -1);
@@ -452,7 +452,7 @@
         commitText("hello", 1);
         waitAndVerifyUpdateSelection(0, 5, 5, -1, -1);
         restartInput();
-        DOMUtils.clickNode(this, mContentViewCore, "input_text");
+        DOMUtils.clickNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
 
         assertEquals(5, mConnectionFactory.getOutAttrs().initialSelStart);
@@ -577,7 +577,7 @@
         waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
 
         // Select 'text' part.
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
 
         assertWaitForSelectActionBarStatus(true);
 
@@ -593,7 +593,7 @@
     public void testImeNotDismissedAfterCutSelection() throws Exception {
         commitText("Sample Text", 1);
         waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(true);
         assertWaitForKeyboardStatus(true);
         cut();
@@ -605,20 +605,20 @@
     @Feature({"TextInput"})
     public void testImeNotShownOnLongPressingEmptyInput() throws Exception {
         DOMUtils.focusNode(mWebContents, "input_radio");
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(false);
         commitText("Sample Text", 1);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
     }
 
     @SmallTest
     @Feature({"TextInput"})
     public void testSelectActionBarShownOnLongPressingInput() throws Exception {
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(false);
         commitText("Sample Text", 1);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(true);
     }
 
@@ -628,7 +628,7 @@
         assertWaitForSelectActionBarStatus(false);
         setComposingText("Sample Text", 1);
         waitAndVerifyUpdateSelection(0, 11, 11, 0, 11);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
 
         assertWaitForSelectActionBarStatus(true);
 
@@ -650,14 +650,14 @@
         commitText("Sample Text", 1);
 
         int showCount = mInputMethodManagerWrapper.getShowSoftInputCounter();
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(true);
         assertEquals(showCount + 1, mInputMethodManagerWrapper.getShowSoftInputCounter());
 
         // Now long press again. Selection region remains the same, but the logic
         // should trigger IME to show up. Note that Android does not provide show /
         // hide status of IME, so we will just check whether showIme() has been triggered.
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         final int newCount = showCount + 2;
         CriteriaHelper.pollUiThread(Criteria.equals(newCount, new Callable<Integer>() {
             @Override
@@ -738,10 +738,10 @@
     @Feature({"TextInput"})
     public void testSelectActionBarClearedOnTappingInput() throws Exception {
         commitText("Sample Text", 1);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
         assertWaitForSelectActionBarStatus(true);
-        DOMUtils.clickNode(this, mContentViewCore, "input_text");
+        DOMUtils.clickNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(false);
     }
 
@@ -749,10 +749,10 @@
     @Feature({"TextInput"})
     public void testSelectActionBarClearedOnTappingOutsideInput() throws Exception {
         commitText("Sample Text", 1);
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
         assertWaitForSelectActionBarStatus(true);
-        DOMUtils.clickNode(this, mContentViewCore, "input_radio");
+        DOMUtils.clickNode(mContentViewCore, "input_radio");
         assertWaitForKeyboardStatus(false);
         assertWaitForSelectActionBarStatus(false);
     }
@@ -761,9 +761,9 @@
     @Feature({"TextInput"})
     public void testImeNotShownOnLongPressingDifferentEmptyInputs() throws Exception {
         DOMUtils.focusNode(mWebContents, "input_radio");
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(false);
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         assertWaitForKeyboardStatus(false);
     }
 
@@ -783,11 +783,11 @@
         commitText("Sample Text", 1);
         waitAndVerifyUpdateSelection(2, 11, 11, -1, -1);
 
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForKeyboardStatus(true);
         assertWaitForSelectActionBarStatus(true);
 
-        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        DOMUtils.longPressNode(mContentViewCore, "textarea");
         assertWaitForKeyboardStatus(true);
     }
 
@@ -1215,7 +1215,7 @@
         waitAndVerifyUpdateSelection(2, 0, 0, -1, -1);
         assertTextsAroundCursor("", null, "");
 
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
@@ -1240,7 +1240,7 @@
         commitText("Sample Text", 1);
         waitAndVerifyUpdateSelection(0, 11, 11, -1, -1);
 
-        DOMUtils.longPressNode(this, mContentViewCore, "input_text");
+        DOMUtils.longPressNode(mContentViewCore, "input_text");
         assertWaitForSelectActionBarStatus(true);
 
         setComposingText("h", 1);
@@ -1251,7 +1251,7 @@
     @SmallTest
     @Feature({"TextInput"})
     public void testTextHandlesPreservedWithDpadNavigation() throws Throwable {
-        DOMUtils.longPressNode(this, mContentViewCore, "plain_text");
+        DOMUtils.longPressNode(mContentViewCore, "plain_text");
         assertWaitForSelectActionBarStatus(true);
         assertTrue(mSelectionPopupController.hasSelection());
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
index 98dc29a..380b99f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
@@ -87,7 +87,7 @@
         final OnPageFinishedHelper onPageFinishedHelper = viewClient.getOnPageFinishedHelper();
 
         // Once clicked, the popup should show up.
-        DOMUtils.clickNode(this, viewCore, "select");
+        DOMUtils.clickNode(viewCore, "select");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
 
         // Reload the test page.
@@ -106,7 +106,7 @@
         CriteriaHelper.pollInstrumentationThread(new PopupHiddenCriteria());
 
         // Click the select and wait for the popup to show.
-        DOMUtils.clickNode(this, viewCore, "select");
+        DOMUtils.clickNode(viewCore, "select");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
     }
 }
diff --git a/content/public/browser/media_capture_devices.h b/content/public/browser/media_capture_devices.h
index 925fff6..9ed92c2a 100644
--- a/content/public/browser/media_capture_devices.h
+++ b/content/public/browser/media_capture_devices.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_MEDIA_CAPTURE_DEVICES_H_
 
 #include "content/public/common/media_stream_request.h"
+#include "media/base/video_facing.h"
 
 namespace content {
 
@@ -20,6 +21,10 @@
   virtual const MediaStreamDevices& GetAudioCaptureDevices() = 0;
   virtual const MediaStreamDevices& GetVideoCaptureDevices() = 0;
 
+  virtual void AddVideoCaptureObserver(
+      media::VideoCaptureObserver* observer) = 0;
+  virtual void RemoveAllVideoCaptureObservers() = 0;
+
  private:
   // This interface should only be implemented inside content.
   friend class MediaCaptureDevicesImpl;
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index 945c96e..eb9e6a8 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -15,8 +15,10 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/global_request_id.h"
 #include "content/public/browser/site_instance.h"
+#include "content/public/common/child_process_host.h"
 #include "content/public/common/referrer.h"
 #include "content/public/common/resource_request_body.h"
+#include "ipc/ipc_message.h"
 #include "ui/base/page_transition_types.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
@@ -71,6 +73,12 @@
   // The browser-global FrameTreeNode ID or -1 to indicate the main frame.
   int frame_tree_node_id;
 
+  // Routing id of the source RenderFrameHost.
+  int source_render_frame_id = MSG_ROUTING_NONE;
+
+  // Process id of the source RenderFrameHost.
+  int source_render_process_id = ChildProcessHost::kInvalidUniqueID;
+
   // The disposition requested by the navigation source.
   WindowOpenDisposition disposition;
 
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index df27b290..374ad4b8 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -274,7 +274,8 @@
                                    const GURL& url,
                                    const Referrer& referrer,
                                    WindowOpenDisposition disposition,
-                                   ui::PageTransition transition) {}
+                                   ui::PageTransition transition,
+                                   bool started_from_context_menu) {}
 
   // This method is invoked when the renderer process has completed its first
   // paint after a non-empty layout.
diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc
index bd9d6147..067355d4 100644
--- a/content/public/common/url_constants.cc
+++ b/content/public/common/url_constants.cc
@@ -46,6 +46,7 @@
 const char kChromeUIWebRTCInternalsHost[] = "webrtc-internals";
 
 const char kChromeUIBadCastCrashURL[] = "chrome://badcastcrash/";
+const char kChromeUICheckCrashURL[] = "chrome://checkcrash/";
 const char kChromeUIBrowserCrashURL[] = "chrome://inducebrowsercrashforrealz/";
 const char kChromeUIBrowserUIHang[] = "chrome://uithreadhang/";
 const char kChromeUICrashURL[] = "chrome://crash/";
diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h
index cda43044..561265d 100644
--- a/content/public/common/url_constants.h
+++ b/content/public/common/url_constants.h
@@ -55,6 +55,7 @@
 
 // Full about URLs (including schemes).
 CONTENT_EXPORT extern const char kChromeUIBadCastCrashURL[];
+CONTENT_EXPORT extern const char kChromeUICheckCrashURL[];
 CONTENT_EXPORT extern const char kChromeUIBrowserCrashURL[];
 CONTENT_EXPORT extern const char kChromeUIBrowserUIHang[];
 CONTENT_EXPORT extern const char kChromeUICrashURL[];
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
index 48e2f95..1d87d5c 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/DOMUtils.java
@@ -7,7 +7,6 @@
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
 import android.graphics.Rect;
-import android.test.ActivityInstrumentationTestCase2;
 import android.util.JsonReader;
 
 import junit.framework.Assert;
@@ -225,12 +224,10 @@
 
     /**
      * Click a DOM node by its id, scrolling it into view first.
-     * @param activityTestCase The ActivityInstrumentationTestCase2 to instrument.
      * @param viewCore The ContentViewCore in which the node lives.
      * @param nodeId The id of the node.
      */
-    public static boolean clickNode(ActivityInstrumentationTestCase2 activityTestCase,
-            final ContentViewCore viewCore, String nodeId)
+    public static boolean clickNode(final ContentViewCore viewCore, String nodeId)
             throws InterruptedException, TimeoutException {
         scrollNodeIntoView(viewCore.getWebContents(), nodeId);
         int[] clickTarget = getClickTargetForNode(viewCore, nodeId);
@@ -240,12 +237,10 @@
 
     /**
      * Click a DOM node returned by JS code, scrolling it into view first.
-     * @param activityTestCase The ActivityInstrumentationTestCase2 to instrument.
      * @param viewCore The ContentViewCore in which the node lives.
      * @param jsCode The JS code to find the node.
      */
-    public static void clickNodeByJs(ActivityInstrumentationTestCase2 activityTestCase,
-            final ContentViewCore viewCore, String jsCode)
+    public static void clickNodeByJs(final ContentViewCore viewCore, String jsCode)
             throws InterruptedException, TimeoutException {
         scrollNodeIntoViewByJs(viewCore.getWebContents(), jsCode);
         int[] clickTarget = getClickTargetForNodeByJs(viewCore, jsCode);
@@ -266,28 +261,24 @@
 
     /**
      * Long-press a DOM node by its id, scrolling it into view first.
-     * @param activityTestCase The ActivityInstrumentationTestCase2 to instrument.
      * @param viewCore The ContentViewCore in which the node lives.
      * @param nodeId The id of the node.
      */
-    public static void longPressNode(ActivityInstrumentationTestCase2 activityTestCase,
-            final ContentViewCore viewCore, String nodeId)
+    public static void longPressNode(final ContentViewCore viewCore, String nodeId)
             throws InterruptedException, TimeoutException {
         scrollNodeIntoView(viewCore.getWebContents(), nodeId);
         String jsCode = "document.getElementById('" + nodeId + "')";
-        longPressNodeByJs(activityTestCase, viewCore, jsCode);
+        longPressNodeByJs(viewCore, jsCode);
     }
 
     /**
      * Long-press a DOM node by its id.
      * <p>Note that content view should be located in the current position for a foreseeable
      * amount of time because this involves sleep to simulate touch to long press transition.
-     * @param activityTestCase The ActivityInstrumentationTestCase2 to instrument.
      * @param viewCore The ContentViewCore in which the node lives.
      * @param nodeId The id of the node.
      */
-    public static void longPressNodeByJs(ActivityInstrumentationTestCase2 activityTestCase,
-            final ContentViewCore viewCore, String jsCode)
+    public static void longPressNodeByJs(final ContentViewCore viewCore, String jsCode)
             throws InterruptedException, TimeoutException {
         int[] clickTarget = getClickTargetForNodeByJs(viewCore, jsCode);
         TouchCommon.longPressView(viewCore.getContainerView(), clickTarget[0], clickTarget[1]);
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index a5fa46e..70b0c78 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -607,12 +607,6 @@
       "media/media_stream_video_track.h",
       "media/peer_connection_tracker.cc",
       "media/peer_connection_tracker.h",
-      "media/recorder/audio_track_recorder.cc",
-      "media/recorder/audio_track_recorder.h",
-      "media/recorder/media_recorder_handler.cc",
-      "media/recorder/media_recorder_handler.h",
-      "media/recorder/video_track_recorder.cc",
-      "media/recorder/video_track_recorder.h",
       "media/remote_media_stream_impl.cc",
       "media/remote_media_stream_impl.h",
       "media/rtc_certificate.cc",
@@ -674,6 +668,12 @@
       "media/webrtc_logging.h",
       "media/webrtc_uma_histograms.cc",
       "media/webrtc_uma_histograms.h",
+      "media_recorder/audio_track_recorder.cc",
+      "media_recorder/audio_track_recorder.h",
+      "media_recorder/media_recorder_handler.cc",
+      "media_recorder/media_recorder_handler.h",
+      "media_recorder/video_track_recorder.cc",
+      "media_recorder/video_track_recorder.h",
       "p2p/empty_network_manager.cc",
       "p2p/empty_network_manager.h",
       "p2p/filtering_network_manager.cc",
diff --git a/content/renderer/image_downloader/image_downloader_base.cc b/content/renderer/image_downloader/image_downloader_base.cc
index e1aa9f5..fffdeb3e 100644
--- a/content/renderer/image_downloader/image_downloader_base.cc
+++ b/content/renderer/image_downloader/image_downloader_base.cc
@@ -123,7 +123,7 @@
 }
 
 void ImageDownloaderBase::OnDestruct() {
-  for (auto fetchers : image_fetchers_) {
+  for (auto* fetchers : image_fetchers_) {
     // Will run callbacks with an empty image vector.
     fetchers->OnRenderFrameDestruct();
   }
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc
index b629b40..d7337c6 100644
--- a/content/renderer/input/main_thread_event_queue.cc
+++ b/content/renderer/input/main_thread_event_queue.cc
@@ -42,13 +42,16 @@
 EventWithDispatchType::~EventWithDispatchType() {}
 
 void EventWithDispatchType::CoalesceWith(const EventWithDispatchType& other) {
-  if (other.dispatch_type_ == DISPATCH_TYPE_BLOCKING) {
+  // If this event was blocking push the event id to the blocking
+  // list before updating the dispatch_type of this event.
+  if (dispatch_type_ == DISPATCH_TYPE_BLOCKING) {
     blocking_coalesced_event_ids_.push_back(
-        ui::WebInputEventTraits::GetUniqueTouchEventId(other.event()));
+        ui::WebInputEventTraits::GetUniqueTouchEventId(event()));
   } else {
     non_blocking_coalesced_count_++;
   }
   ScopedWebInputEventWithLatencyInfo::CoalesceWith(other);
+  dispatch_type_ = other.dispatch_type_;
   last_coalesced_timestamp_ = base::TimeTicks::Now();
 }
 
diff --git a/content/renderer/input/main_thread_event_queue_unittest.cc b/content/renderer/input/main_thread_event_queue_unittest.cc
index cda96df..2cdd7c4 100644
--- a/content/renderer/input/main_thread_event_queue_unittest.cc
+++ b/content/renderer/input/main_thread_event_queue_unittest.cc
@@ -343,8 +343,13 @@
 
   EXPECT_EQ(0u, event_queue().size());
   EXPECT_EQ(2u, additional_acked_events_.size());
-  EXPECT_EQ(kEvents[2].uniqueTouchEventId, additional_acked_events_.at(0));
-  EXPECT_EQ(kEvents[3].uniqueTouchEventId, additional_acked_events_.at(1));
+  EXPECT_EQ(kEvents[1].uniqueTouchEventId, additional_acked_events_.at(0));
+  EXPECT_EQ(kEvents[2].uniqueTouchEventId, additional_acked_events_.at(1));
+
+  const WebTouchEvent* last_touch_event =
+      static_cast<const WebTouchEvent*>(handled_events_.at(1).eventPointer());
+  EXPECT_EQ(kEvents[3].uniqueTouchEventId,
+            last_touch_event->uniqueTouchEventId);
 
   HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
   HandleEvent(kEvents[2], INPUT_EVENT_ACK_STATE_SET_NON_BLOCKING);
@@ -532,14 +537,14 @@
   EXPECT_FALSE(main_task_runner_->HasPendingTask());
   EXPECT_EQ(0u, event_queue().size());
 
-  // Send a continuous input event (ack required) and then
-  // a discrete event. The events should coalesce together
+  // Send a discrete input event and then a continuous
+  // (ack required)  event. The events should coalesce together
   // and a post task should be on the queue at the end.
-  HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
   EXPECT_EQ(1u, event_queue().size());
   EXPECT_FALSE(main_task_runner_->HasPendingTask());
   EXPECT_TRUE(needs_main_frame_);
-  HandleEvent(kEvents[1], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
+  HandleEvent(kEvents[0], INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
   EXPECT_EQ(1u, event_queue().size());
   EXPECT_FALSE(main_task_runner_->HasPendingTask());
   EXPECT_TRUE(needs_main_frame_);
diff --git a/content/renderer/media/DEPS b/content/renderer/media/DEPS
index 3702908..3dfd058 100644
--- a/content/renderer/media/DEPS
+++ b/content/renderer/media/DEPS
@@ -1,7 +1,4 @@
 include_rules = [
-  "+third_party/libvpx",
   "+third_party/libyuv",
-  '+third_party/openh264/src/codec/api/svc',
-  '+third_party/opus',
   '+third_party/webrtc_overrides',
 ]
diff --git a/content/renderer/media_recorder/DEPS b/content/renderer/media_recorder/DEPS
new file mode 100644
index 0000000..59fe857
--- /dev/null
+++ b/content/renderer/media_recorder/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+  "+third_party/libvpx",
+  "+third_party/libyuv",
+  '+third_party/openh264/src/codec/api/svc',
+  '+third_party/opus',
+]
diff --git a/content/renderer/media/recorder/OWNERS b/content/renderer/media_recorder/OWNERS
similarity index 100%
rename from content/renderer/media/recorder/OWNERS
rename to content/renderer/media_recorder/OWNERS
diff --git a/content/renderer/media/recorder/audio_track_recorder.cc b/content/renderer/media_recorder/audio_track_recorder.cc
similarity index 99%
rename from content/renderer/media/recorder/audio_track_recorder.cc
rename to content/renderer/media_recorder/audio_track_recorder.cc
index 874c78c..9f7fc67 100644
--- a/content/renderer/media/recorder/audio_track_recorder.cc
+++ b/content/renderer/media_recorder/audio_track_recorder.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 "content/renderer/media/recorder/audio_track_recorder.h"
+#include "content/renderer/media_recorder/audio_track_recorder.h"
 
 #include <stdint.h>
 #include <utility>
diff --git a/content/renderer/media/recorder/audio_track_recorder.h b/content/renderer/media_recorder/audio_track_recorder.h
similarity index 100%
rename from content/renderer/media/recorder/audio_track_recorder.h
rename to content/renderer/media_recorder/audio_track_recorder.h
diff --git a/content/renderer/media/recorder/audio_track_recorder_unittest.cc b/content/renderer/media_recorder/audio_track_recorder_unittest.cc
similarity index 99%
rename from content/renderer/media/recorder/audio_track_recorder_unittest.cc
rename to content/renderer/media_recorder/audio_track_recorder_unittest.cc
index b7c9bea2b..6929364c 100644
--- a/content/renderer/media/recorder/audio_track_recorder_unittest.cc
+++ b/content/renderer/media_recorder/audio_track_recorder_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/recorder/audio_track_recorder.h"
+#include "content/renderer/media_recorder/audio_track_recorder.h"
 
 #include <stdint.h>
 
diff --git a/content/renderer/media/recorder/media_recorder_handler.cc b/content/renderer/media_recorder/media_recorder_handler.cc
similarity index 98%
rename from content/renderer/media/recorder/media_recorder_handler.cc
rename to content/renderer/media_recorder/media_recorder_handler.cc
index 9fcd2b9c..1055b153 100644
--- a/content/renderer/media/recorder/media_recorder_handler.cc
+++ b/content/renderer/media_recorder/media_recorder_handler.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 "content/renderer/media/recorder/media_recorder_handler.h"
+#include "content/renderer/media_recorder/media_recorder_handler.h"
 
 #include <utility>
 
@@ -14,8 +14,8 @@
 #include "base/strings/string_util.h"
 #include "content/renderer/media/media_stream_audio_track.h"
 #include "content/renderer/media/media_stream_track.h"
-#include "content/renderer/media/recorder/audio_track_recorder.h"
 #include "content/renderer/media/webrtc_uma_histograms.h"
+#include "content/renderer/media_recorder/audio_track_recorder.h"
 #include "media/base/audio_bus.h"
 #include "media/base/audio_parameters.h"
 #include "media/base/bind_to_current_loop.h"
@@ -98,7 +98,7 @@
       video ? arraysize(kVideoCodecs) : arraysize(kAudioCodecs);
 
   std::vector<std::string> codecs_list;
-  media::ParseCodecString(web_codecs.utf8(), &codecs_list, true /* strip */);
+  media::SplitCodecsToVector(web_codecs.utf8(), &codecs_list, true /* strip */);
   for (const auto& codec : codecs_list) {
     auto* const* found = std::find_if(
         &codecs[0], &codecs[codecs_count], [&codec](const char* name) {
diff --git a/content/renderer/media/recorder/media_recorder_handler.h b/content/renderer/media_recorder/media_recorder_handler.h
similarity index 98%
rename from content/renderer/media/recorder/media_recorder_handler.h
rename to content/renderer/media_recorder/media_recorder_handler.h
index d7cf39da..30a7637 100644
--- a/content/renderer/media/recorder/media_recorder_handler.h
+++ b/content/renderer/media_recorder/media_recorder_handler.h
@@ -13,7 +13,7 @@
 #include "base/strings/string_piece.h"
 #include "base/threading/thread_checker.h"
 #include "content/common/content_export.h"
-#include "content/renderer/media/recorder/video_track_recorder.h"
+#include "content/renderer/media_recorder/video_track_recorder.h"
 #include "third_party/WebKit/public/platform/WebMediaRecorderHandler.h"
 #include "third_party/WebKit/public/platform/WebMediaStream.h"
 
diff --git a/content/renderer/media/recorder/media_recorder_handler_unittest.cc b/content/renderer/media_recorder/media_recorder_handler_unittest.cc
similarity index 99%
rename from content/renderer/media/recorder/media_recorder_handler_unittest.cc
rename to content/renderer/media_recorder/media_recorder_handler_unittest.cc
index fa90e65..f0be4d1 100644
--- a/content/renderer/media/recorder/media_recorder_handler_unittest.cc
+++ b/content/renderer/media_recorder/media_recorder_handler_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/time/time.h"
 #include "content/child/child_process.h"
 #include "content/renderer/media/mock_media_stream_registry.h"
-#include "content/renderer/media/recorder/media_recorder_handler.h"
+#include "content/renderer/media_recorder/media_recorder_handler.h"
 #include "media/audio/simple_sources.h"
 #include "media/base/audio_bus.h"
 #include "media/base/video_frame.h"
diff --git a/content/renderer/media/recorder/video_track_recorder.cc b/content/renderer/media_recorder/video_track_recorder.cc
similarity index 99%
rename from content/renderer/media/recorder/video_track_recorder.cc
rename to content/renderer/media_recorder/video_track_recorder.cc
index a792511..d699e7e 100644
--- a/content/renderer/media/recorder/video_track_recorder.cc
+++ b/content/renderer/media_recorder/video_track_recorder.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 "content/renderer/media/recorder/video_track_recorder.h"
+#include "content/renderer/media_recorder/video_track_recorder.h"
 
 #include <utility>
 
diff --git a/content/renderer/media/recorder/video_track_recorder.h b/content/renderer/media_recorder/video_track_recorder.h
similarity index 100%
rename from content/renderer/media/recorder/video_track_recorder.h
rename to content/renderer/media_recorder/video_track_recorder.h
diff --git a/content/renderer/media/recorder/video_track_recorder_unittest.cc b/content/renderer/media_recorder/video_track_recorder_unittest.cc
similarity index 98%
rename from content/renderer/media/recorder/video_track_recorder_unittest.cc
rename to content/renderer/media_recorder/video_track_recorder_unittest.cc
index 3eb455e..3440bd7d 100644
--- a/content/renderer/media/recorder/video_track_recorder_unittest.cc
+++ b/content/renderer/media_recorder/video_track_recorder_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/media/recorder/video_track_recorder.h"
+#include "content/renderer/media_recorder/video_track_recorder.h"
 
 #include <stddef.h>
 
diff --git a/content/renderer/presentation/presentation_dispatcher_unittest.cc b/content/renderer/presentation/presentation_dispatcher_unittest.cc
index 5cf22a0..8cf4429 100644
--- a/content/renderer/presentation/presentation_dispatcher_unittest.cc
+++ b/content/renderer/presentation/presentation_dispatcher_unittest.cc
@@ -716,7 +716,7 @@
 
   // Set up |availability_set_| and |listening_status_|
   base::RunLoop run_loop;
-  for (auto& mock_observer : mock_observers_) {
+  for (auto* mock_observer : mock_observers_) {
     client()->getAvailability(
         mock_observer->urls(),
         base::MakeUnique<WebPresentationAvailabilityCallbacks>());
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 632baad..c224627 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -549,6 +549,11 @@
         << "Intentionally exhausting renderer memory because user navigated to "
         << url.spec();
     ExhaustMemory();
+  } else if (url == kChromeUICheckCrashURL) {
+    LOG(ERROR)
+        << "Intentionally causing CHECK because user navigated to "
+        << url.spec();
+    CHECK(false);
   }
 
 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index ed61cd8..40c87d7 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -60,9 +60,9 @@
 #include "content/renderer/media/capturefromelement/html_audio_element_capturer_source.h"
 #include "content/renderer/media/capturefromelement/html_video_element_capturer_source.h"
 #include "content/renderer/media/image_capture_frame_grabber.h"
-#include "content/renderer/media/recorder/media_recorder_handler.h"
 #include "content/renderer/media/renderer_webaudiodevice_impl.h"
 #include "content/renderer/media/renderer_webmidiaccessor_impl.h"
+#include "content/renderer/media_recorder/media_recorder_handler.h"
 #include "content/renderer/mojo/blink_interface_provider_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/renderer_clipboard_delegate.h"
diff --git a/content/renderer/scheduler/OWNERS b/content/renderer/scheduler/OWNERS
index 6dc4cb4..9bf4416 100644
--- a/content/renderer/scheduler/OWNERS
+++ b/content/renderer/scheduler/OWNERS
@@ -1,3 +1,6 @@
 alexclarke@chromium.org
 rmcilroy@chromium.org
 skyostil@chromium.org
+
+# TEAM: scheduler-dev@chromium.org
+# COMPONENT: Blink>Scheduling
diff --git a/content/shell/test_runner/mock_web_speech_recognizer.cc b/content/shell/test_runner/mock_web_speech_recognizer.cc
index 062f0e26..56c35ae 100644
--- a/content/shell/test_runner/mock_web_speech_recognizer.cc
+++ b/content/shell/test_runner/mock_web_speech_recognizer.cc
@@ -319,7 +319,7 @@
 }
 
 bool MockWebSpeechRecognizer::HasPendingNewContextTasks() const {
-  for (const auto& task : task_queue_) {
+  for (auto* task : task_queue_) {
     if (task->isNewContextTask())
       return true;
   }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index bb8c09f..db2a88e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1592,9 +1592,6 @@
       "../renderer/media/mock_media_stream_video_source.cc",
       "../renderer/media/mock_media_stream_video_source.h",
       "../renderer/media/peer_connection_tracker_unittest.cc",
-      "../renderer/media/recorder/audio_track_recorder_unittest.cc",
-      "../renderer/media/recorder/media_recorder_handler_unittest.cc",
-      "../renderer/media/recorder/video_track_recorder_unittest.cc",
       "../renderer/media/rtc_data_channel_handler_unittest.cc",
       "../renderer/media/rtc_peer_connection_handler_unittest.cc",
       "../renderer/media/speech_recognition_audio_sink_unittest.cc",
@@ -1611,6 +1608,9 @@
       "../renderer/media/webrtc_audio_renderer_unittest.cc",
       "../renderer/media/webrtc_local_audio_source_provider_unittest.cc",
       "../renderer/media/webrtc_uma_histograms_unittest.cc",
+      "../renderer/media_recorder/audio_track_recorder_unittest.cc",
+      "../renderer/media_recorder/media_recorder_handler_unittest.cc",
+      "../renderer/media_recorder/video_track_recorder_unittest.cc",
       "../renderer/p2p/filtering_network_manager_unittest.cc",
       "../renderer/p2p/ipc_network_manager_unittest.cc",
       "//third_party/webrtc/base/task_queue_unittest.cc",
@@ -1637,9 +1637,9 @@
 
     if (is_chromecast) {
       sources -= [
-        "../renderer/media/recorder/audio_track_recorder_unittest.cc",
-        "../renderer/media/recorder/media_recorder_handler_unittest.cc",
-        "../renderer/media/recorder/video_track_recorder_unittest.cc",
+        "../renderer/media_recorder/audio_track_recorder_unittest.cc",
+        "../renderer/media_recorder/media_recorder_handler_unittest.cc",
+        "../renderer/media_recorder/video_track_recorder_unittest.cc",
       ]
     }
   }
diff --git a/content/test/gpu/gpu_tests/context_lost_integration_test.py b/content/test/gpu/gpu_tests/context_lost_integration_test.py
index 3c97ca5..670f850 100644
--- a/content/test/gpu/gpu_tests/context_lost_integration_test.py
+++ b/content/test/gpu/gpu_tests/context_lost_integration_test.py
@@ -97,8 +97,8 @@
     return context_lost_expectations.ContextLostExpectations()
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, ContextLostIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, ContextLostIntegrationTest).SetUpProcess()
     cls.CustomizeOptions()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartBrowser()
diff --git a/content/test/gpu/gpu_tests/depth_capture_integration_test.py b/content/test/gpu/gpu_tests/depth_capture_integration_test.py
index b2a40b7..9f3b6693 100644
--- a/content/test/gpu/gpu_tests/depth_capture_integration_test.py
+++ b/content/test/gpu/gpu_tests/depth_capture_integration_test.py
@@ -88,8 +88,8 @@
     return depth_capture_expectations.DepthCaptureExpectations()
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, DepthCaptureIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, DepthCaptureIntegrationTest).SetUpProcess()
     cls.CustomizeOptions()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartBrowser()
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
index 4946255..2c924f66 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test_unittest.py
@@ -3,240 +3,104 @@
 # found in the LICENSE file.
 
 import json
-import logging
-import mock
 import os
+import shutil
 import tempfile
 import unittest
 
-from telemetry.testing import fakes
 from telemetry.testing import browser_test_runner
 
-import gpu_project_config
+from gpu_tests import path_util
 
-from gpu_tests import gpu_integration_test
-from gpu_tests import gpu_test_expectations
-
-class SimpleIntegrationUnittest(gpu_integration_test.GpuIntegrationTest):
-  # Must be class-scoped since instances aren't reused across runs.
-  _num_flaky_runs_to_fail = 2
-
-  _num_browser_starts = 0
-
-  @classmethod
-  def Name(cls):
-    return 'simple_integration_unittest'
-
-  def setUp(self):
-    super(SimpleIntegrationUnittest, self).setUp()
-
-  @classmethod
-  def setUpClass(cls):
-    finder_options = fakes.CreateBrowserFinderOptions()
-    finder_options.browser_options.platform = fakes.FakeLinuxPlatform()
-    finder_options.output_formats = ['none']
-    finder_options.suppress_gtest_report = True
-    finder_options.output_dir = None
-    finder_options.upload_bucket = 'public'
-    finder_options.upload_results = False
-    cls._finder_options = finder_options
-    cls.platform = None
-    cls.browser = None
-    cls.SetBrowserOptions(cls._finder_options)
-    cls.StartBrowser()
-
-  @classmethod
-  def GenerateGpuTests(cls, options):
-    yield ('expected_failure', 'failure.html', ())
-    yield ('expected_flaky', 'flaky.html', ())
-    yield ('expected_skip', 'failure.html', ())
-    yield ('unexpected_failure', 'failure.html', ())
-    yield ('unexpected_error', 'error.html', ())
-
-  @classmethod
-  def _CreateExpectations(cls):
-    expectations = gpu_test_expectations.GpuTestExpectations()
-    expectations.Fail('expected_failure')
-    expectations.Flaky('expected_flaky', max_num_retries=3)
-    expectations.Skip('expected_skip')
-    return expectations
-
-  @classmethod
-  def StartBrowser(cls):
-    super(SimpleIntegrationUnittest, cls).StartBrowser()
-    cls._num_browser_starts += 1
-
-  def RunActualGpuTest(self, file_path, *args):
-    logging.warn('Running ' + file_path)
-    if file_path == 'failure.html':
-      self.fail('Expected failure')
-    elif file_path == 'flaky.html':
-      if self.__class__._num_flaky_runs_to_fail > 0:
-        self.__class__._num_flaky_runs_to_fail -= 1
-        self.fail('Expected flaky failure')
-    elif file_path == 'error.html':
-      raise Exception('Expected exception')
-
-
-class BrowserStartFailureIntegrationUnittest(
-  gpu_integration_test.GpuIntegrationTest):
-
-  _num_browser_crashes = 0
-  _num_browser_starts = 0
-
-  @classmethod
-  def setUpClass(cls):
-    cls._fake_browser_options = \
-        fakes.CreateBrowserFinderOptions(execute_on_startup=cls.CrashOnStart)
-    cls._fake_browser_options.browser_options.platform = \
-        fakes.FakeLinuxPlatform()
-    cls._fake_browser_options.output_formats = ['none']
-    cls._fake_browser_options.suppress_gtest_report = True
-    cls._fake_browser_options.output_dir = None
-    cls._fake_browser_options .upload_bucket = 'public'
-    cls._fake_browser_options .upload_results = False
-    cls._finder_options = cls._fake_browser_options
-    cls.platform = None
-    cls.browser = None
-    cls.SetBrowserOptions(cls._finder_options)
-    cls.StartBrowser()
-
-  @classmethod
-  def _CreateExpectations(cls):
-    return gpu_test_expectations.GpuTestExpectations()
-
-  @classmethod
-  def CrashOnStart(cls):
-    cls._num_browser_starts += 1
-    if cls._num_browser_crashes < 2:
-      cls._num_browser_crashes += 1
-      raise
-
-  @classmethod
-  def Name(cls):
-    return 'browser_start_failure_integration_unittest'
-
-  @classmethod
-  def GenerateGpuTests(cls, options):
-    # This test causes the browser to try and restart the browser 3 times.
-    yield ('restart', 'restart.html', ())
-
-  def RunActualGpuTest(self, file_path, *args):
-    # The logic of this test is run when the browser starts, it fails twice
-    # and then succeeds on the third time so we are just testing that this
-    # is successful based on the parameters.
-    pass
-
-
-class BrowserCrashAfterStartIntegrationUnittest(
-  gpu_integration_test.GpuIntegrationTest):
-
-  _num_browser_crashes = 0
-  _num_browser_starts = 0
-
-  @classmethod
-  def setUpClass(cls):
-    cls._fake_browser_options = fakes.CreateBrowserFinderOptions(
-      execute_after_browser_creation=cls.CrashAfterStart)
-    cls._fake_browser_options.browser_options.platform = \
-        fakes.FakeLinuxPlatform()
-    cls._fake_browser_options.output_formats = ['none']
-    cls._fake_browser_options.suppress_gtest_report = True
-    cls._fake_browser_options.output_dir = None
-    cls._fake_browser_options .upload_bucket = 'public'
-    cls._fake_browser_options .upload_results = False
-    cls._finder_options = cls._fake_browser_options
-    cls.platform = None
-    cls.browser = None
-    cls.SetBrowserOptions(cls._finder_options)
-    cls.StartBrowser()
-
-  @classmethod
-  def _CreateExpectations(cls):
-    return gpu_test_expectations.GpuTestExpectations()
-
-  @classmethod
-  def CrashAfterStart(cls, browser):
-    cls._num_browser_starts += 1
-    if cls._num_browser_crashes < 2:
-      cls._num_browser_crashes += 1
-      # This simulates the first tab's renderer process crashing upon
-      # startup. The try/catch forces the GpuIntegrationTest's first
-      # fetch of this tab to fail. crbug.com/682819
-      try:
-        browser.tabs[0].Navigate('chrome://crash')
-      except Exception:
-        pass
-
-  @classmethod
-  def Name(cls):
-    return 'browser_crash_after_start_integration_unittest'
-
-  @classmethod
-  def GenerateGpuTests(cls, options):
-    # This test causes the browser to try and restart the browser 3 times.
-    yield ('restart', 'restart.html', ())
-
-  def RunActualGpuTest(self, file_path, *args):
-    # The logic of this test is run when the browser starts, it fails twice
-    # and then succeeds on the third time so we are just testing that this
-    # is successful based on the parameters.
-    pass
+path_util.AddDirToPathIfNeeded(path_util.GetChromiumSrcDir(), 'tools', 'perf')
+from chrome_telemetry_build import chromium_config
 
 
 class GpuIntegrationTestUnittest(unittest.TestCase):
-  @mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
-  def testSimpleIntegrationUnittest(self, mockInitDependencyManager):
+  def setUp(self):
+    self._test_state = {}
+
+  def testSimpleIntegrationTest(self):
     self._RunIntegrationTest(
-      'simple_integration_unittest', [
-        'unexpected_error',
-        'unexpected_failure'
-      ], [
-        'expected_failure',
-        'expected_flaky',
-      ])
+      'simple_integration_unittest',
+      ['unittest_data.integration_tests.SimpleTest.unexpected_error',
+       'unittest_data.integration_tests.SimpleTest.unexpected_failure'],
+      ['unittest_data.integration_tests.SimpleTest.expected_flaky',
+       'unittest_data.integration_tests.SimpleTest.expected_failure'],
+      ['unittest_data.integration_tests.SimpleTest.expected_skip'])
     # It might be nice to be more precise about the order of operations
     # with these browser restarts, but this is at least a start.
-    self.assertEquals(SimpleIntegrationUnittest._num_browser_starts, 6)
+    self.assertEquals(self._test_state['num_browser_starts'], 6)
 
-  @mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
-  def testIntegrationUnittestWithBrowserFailure(
-      self, mockInitDependencyManager):
+  def testIntegrationTesttWithBrowserFailure(self):
     self._RunIntegrationTest(
-      'browser_start_failure_integration_unittest', [], ['restart'])
-    self.assertEquals( \
-      BrowserStartFailureIntegrationUnittest._num_browser_crashes, 2)
-    self.assertEquals( \
-      BrowserStartFailureIntegrationUnittest._num_browser_starts, 3)
+      'browser_start_failure_integration_unittest', [],
+      ['unittest_data.integration_tests.BrowserStartFailureTest.restart'],
+      [])
+    self.assertEquals(self._test_state['num_browser_crashes'], 2)
+    self.assertEquals(self._test_state['num_browser_starts'], 3)
 
-  @mock.patch('telemetry.internal.util.binary_manager.InitDependencyManager')
-  def testIntegrationUnittestWithBrowserCrashUponStart(
-      self, mockInitDependencyManager):
+  def testIntegrationTestWithBrowserCrashUponStart(self):
     self._RunIntegrationTest(
-      'browser_crash_after_start_integration_unittest', [], ['restart'])
-    self.assertEquals( \
-      BrowserCrashAfterStartIntegrationUnittest._num_browser_crashes, 2)
-    self.assertEquals( \
-      BrowserCrashAfterStartIntegrationUnittest._num_browser_starts, 3)
+      'browser_crash_after_start_integration_unittest', [],
+      [('unittest_data.integration_tests.BrowserCrashAfterStartTest.restart')],
+      [])
+    self.assertEquals(self._test_state['num_browser_crashes'], 2)
+    self.assertEquals(self._test_state['num_browser_starts'], 3)
 
-  def _RunIntegrationTest(self, test_name, failures, successes):
-    options = browser_test_runner.TestRunOptions()
-    # Suppress printing out information for passing tests.
-    options.verbosity = 0
-    config = gpu_project_config.CONFIG
-    temp_file = tempfile.NamedTemporaryFile(delete=False)
-    temp_file.close()
-    temp_file_name = temp_file.name
+  def _RunIntegrationTest(self, test_name, failures, successes, skips):
+    config = chromium_config.ChromiumConfig(
+        top_level_dir=path_util.GetGpuTestDir(),
+        benchmark_dirs=[
+            os.path.join(path_util.GetGpuTestDir(), 'unittest_data')])
+    temp_dir = tempfile.mkdtemp()
+    test_results_path = os.path.join(temp_dir, 'test_results.json')
+    test_state_path = os.path.join(temp_dir, 'test_state.json')
     try:
       browser_test_runner.Run(
-          config, options,
+          config,
           [test_name,
-           '--write-abbreviated-json-results-to=%s' % temp_file_name])
-      with open(temp_file_name) as f:
+           '--write-full-results-to=%s' % test_results_path,
+           '--test-state-json-path=%s' % test_state_path])
+      with open(test_results_path) as f:
         test_result = json.load(f)
-      self.assertEquals(test_result['failures'], failures)
-      self.assertEquals(test_result['successes'], successes)
-      self.assertEquals(test_result['valid'], True)
-
+      with open(test_state_path) as f:
+        self._test_state = json.load(f)
+      actual_successes, actual_failures, actual_skips = (
+          self._ExtracTestResults(test_result))
+      self.assertEquals(actual_failures, failures)
+      self.assertEquals(actual_successes, successes)
+      self.assertEquals(actual_skips, skips)
     finally:
-      os.remove(temp_file_name)
+      shutil.rmtree(temp_dir)
+
+  def _ExtracTestResults(self, test_result):
+    delimiter = test_result['path_delimiter']
+    failures = []
+    successes = []
+    skips = []
+    def _IsLeafNode(node):
+      test_dict = node[1]
+      return ('expected' in test_dict and
+              isinstance(test_dict['expected'], basestring))
+    node_queues = []
+    for t in test_result['tests']:
+      node_queues.append((t, test_result['tests'][t]))
+    while node_queues:
+      node = node_queues.pop()
+      full_test_name, test_dict = node
+      if _IsLeafNode(node):
+        if all(res not in test_dict['expected'].split() for res in
+               test_dict['actual'].split()):
+          failures.append(full_test_name)
+        elif test_dict['expected'] == test_dict['actual'] == 'SKIP':
+          skips.append(full_test_name)
+        else:
+          successes.append(full_test_name)
+      else:
+        for k in test_dict:
+          node_queues.append(
+            ('%s%s%s' % (full_test_name, delimiter, k),
+             test_dict[k]))
+    return successes, failures, skips
+
diff --git a/content/test/gpu/gpu_tests/gpu_process_integration_test.py b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
index adf3878..fa9b3c5 100644
--- a/content/test/gpu/gpu_tests/gpu_process_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_process_integration_test.py
@@ -50,8 +50,8 @@
     return 'gpu_process'
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, GpuProcessIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, GpuProcessIntegrationTest).SetUpProcess()
     cls._original_finder_options = cls._finder_options.Copy()
     cls.CustomizeBrowserArgs([])
     cls.StartBrowser()
diff --git a/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py b/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
index 413c63b..2d192fb8d 100644
--- a/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
+++ b/content/test/gpu/gpu_tests/hardware_accelerated_feature_integration_test.py
@@ -37,8 +37,8 @@
     return 'hardware_accelerated_feature'
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, HardwareAcceleratedFeatureIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, HardwareAcceleratedFeatureIntegrationTest).SetUpProcess()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartBrowser()
     cls.SetStaticServerDirs([])
diff --git a/content/test/gpu/gpu_tests/maps_integration_test.py b/content/test/gpu/gpu_tests/maps_integration_test.py
index 891421c..8284ffc 100644
--- a/content/test/gpu/gpu_tests/maps_integration_test.py
+++ b/content/test/gpu/gpu_tests/maps_integration_test.py
@@ -60,16 +60,16 @@
     return maps_expectations.MapsExpectations()
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, MapsIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, MapsIntegrationTest).SetUpProcess()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartWPRServer(os.path.join(data_path, 'maps_004.wpr.updated'),
                        cloud_storage.PUBLIC_BUCKET)
     cls.StartBrowser()
 
   @classmethod
-  def tearDownClass(cls):
-    super(cls, MapsIntegrationTest).tearDownClass()
+  def TearDownProcess(cls):
+    super(cls, MapsIntegrationTest).TearDownProcess()
     cls.StopWPRServer()
 
   @classmethod
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py
index 66b6c339..d7b5c66 100644
--- a/content/test/gpu/gpu_tests/pixel_integration_test.py
+++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -63,8 +63,8 @@
     return 'pixel'
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, PixelIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, PixelIntegrationTest).SetUpProcess()
     cls._original_finder_options = cls._finder_options.Copy()
     cls.CustomizeBrowserArgs([])
     cls.StartBrowser()
diff --git a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
index 76f1a6e..ec0efe1 100644
--- a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
+++ b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
@@ -39,8 +39,8 @@
     return 'screenshot_sync'
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, ScreenshotSyncIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, ScreenshotSyncIntegrationTest).SetUpProcess()
     cls._original_finder_options = cls._finder_options.Copy()
     cls.CustomizeBrowserArgs([])
     cls.StartBrowser()
diff --git a/content/test/gpu/gpu_tests/trace_integration_test.py b/content/test/gpu/gpu_tests/trace_integration_test.py
index 6dfa2cd..9f7e44a 100644
--- a/content/test/gpu/gpu_tests/trace_integration_test.py
+++ b/content/test/gpu/gpu_tests/trace_integration_test.py
@@ -120,8 +120,8 @@
     return trace_test_expectations.TraceTestExpectations()
 
   @classmethod
-  def setUpClass(cls):
-    super(cls, TraceIntegrationTest).setUpClass()
+  def SetUpProcess(cls):
+    super(cls, TraceIntegrationTest).SetUpProcess()
     path_util.SetupTelemetryPaths()
     cls.CustomizeOptions()
     cls.SetBrowserOptions(cls._finder_options)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
index a593790..ba31b00 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_integration_test.py
@@ -313,8 +313,8 @@
         is_asan=cls._is_asan)
 
   @classmethod
-  def setUpClass(cls):
-    super(WebGLConformanceIntegrationTest, cls).setUpClass()
+  def SetUpProcess(cls):
+    super(WebGLConformanceIntegrationTest, cls).SetUpProcess()
     cls.CustomizeOptions()
     cls.SetBrowserOptions(cls._finder_options)
     cls.StartBrowser()
@@ -399,6 +399,7 @@
 
     return test_paths
 
+
 def load_tests(loader, tests, pattern):
   del loader, tests, pattern  # Unused.
   return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/content/test/gpu/run_gpu_integration_test.py b/content/test/gpu/run_gpu_integration_test.py
index 27bf30cf..16deb3ae 100755
--- a/content/test/gpu/run_gpu_integration_test.py
+++ b/content/test/gpu/run_gpu_integration_test.py
@@ -26,10 +26,9 @@
     json.dump(test_result, f)
 
 def main():
-  options = browser_test_runner.TestRunOptions()
   rest_args = sys.argv[1:]
   retval = browser_test_runner.Run(
-      gpu_project_config.CONFIG, options, rest_args)
+      gpu_project_config.CONFIG, rest_args)
   # Postprocess the outputted JSON to trim all of the prefixes from
   # the test names, to keep them as similar to the old form as
   # possible -- and keep them from getting crazily long.
diff --git a/content/test/gpu/unittest_data/__init__.py b/content/test/gpu/unittest_data/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/content/test/gpu/unittest_data/__init__.py
diff --git a/content/test/gpu/unittest_data/integration_tests.py b/content/test/gpu/unittest_data/integration_tests.py
new file mode 100644
index 0000000..bc0589b4e
--- /dev/null
+++ b/content/test/gpu/unittest_data/integration_tests.py
@@ -0,0 +1,213 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+import json
+import logging
+import mock
+import os
+import sys
+import tempfile
+import unittest
+
+from telemetry.testing import fakes
+from telemetry.testing import browser_test_runner
+from telemetry.testing import browser_test_context
+
+import gpu_project_config
+
+from gpu_tests import gpu_integration_test
+from gpu_tests import gpu_test_expectations
+
+
+class _BaseSampleIntegrationTest(gpu_integration_test.GpuIntegrationTest):
+  _test_state = {}
+  @classmethod
+  def AddCommandlineArgs(cls, parser):
+    parser.add_option('--test-state-json-path',
+        help=('Where to dump the test state json (this is used by '
+              'gpu_integration_test_unittest)'))
+
+  @classmethod
+  def TearDownProcess(cls):
+    actual_finder_options = browser_test_context.GetCopy().finder_options
+    test_state_json_path = actual_finder_options.test_state_json_path
+    with open(test_state_json_path, 'w') as f:
+      json.dump(cls._test_state, f)
+    super(_BaseSampleIntegrationTest, cls).TearDownProcess()
+
+
+class SimpleTest(_BaseSampleIntegrationTest):
+  _test_state = {
+    'num_flaky_runs_to_fail': 2,
+    'num_browser_starts': 0
+  }
+
+
+  @classmethod
+  def Name(cls):
+    return 'simple_integration_unittest'
+
+  def setUp(self):
+    super(SimpleTest, self).setUp()
+
+  @classmethod
+  def SetUpProcess(cls):
+    finder_options = fakes.CreateBrowserFinderOptions()
+    finder_options.browser_options.platform = fakes.FakeLinuxPlatform()
+    finder_options.output_formats = ['none']
+    finder_options.suppress_gtest_report = True
+    finder_options.output_dir = None
+    finder_options.upload_bucket = 'public'
+    finder_options.upload_results = False
+    cls._finder_options = finder_options
+    cls.platform = None
+    cls.browser = None
+    cls.SetBrowserOptions(cls._finder_options)
+    cls.StartBrowser()
+
+  @classmethod
+  def GenerateGpuTests(cls, options):
+    yield ('expected_failure', 'failure.html', ())
+    yield ('expected_flaky', 'flaky.html', ())
+    yield ('expected_skip', 'failure.html', ())
+    yield ('unexpected_failure', 'failure.html', ())
+    yield ('unexpected_error', 'error.html', ())
+
+  @classmethod
+  def _CreateExpectations(cls):
+    expectations = gpu_test_expectations.GpuTestExpectations()
+    expectations.Fail('expected_failure')
+    expectations.Flaky('expected_flaky', max_num_retries=3)
+    expectations.Skip('expected_skip')
+    return expectations
+
+  @classmethod
+  def StartBrowser(cls):
+    super(SimpleTest, cls).StartBrowser()
+    cls._test_state['num_browser_starts'] += 1
+
+  def RunActualGpuTest(self, file_path, *args):
+    logging.warn('Running ' + file_path)
+    if file_path == 'failure.html':
+      self.fail('Expected failure')
+    elif file_path == 'flaky.html':
+      if self._test_state['num_flaky_runs_to_fail'] > 0:
+        self._test_state['num_flaky_runs_to_fail'] -= 1
+        self.fail('Expected flaky failure')
+    elif file_path == 'error.html':
+      raise Exception('Expected exception')
+
+
+class BrowserStartFailureTest(_BaseSampleIntegrationTest):
+
+  _test_state = {
+    'num_browser_crashes': 0,
+    'num_browser_starts': 0
+  }
+
+  @classmethod
+  def SetUpProcess(cls):
+    cls._fake_browser_options = \
+        fakes.CreateBrowserFinderOptions(execute_on_startup=cls.CrashOnStart)
+    cls._fake_browser_options.browser_options.platform = \
+        fakes.FakeLinuxPlatform()
+    cls._fake_browser_options.output_formats = ['none']
+    cls._fake_browser_options.suppress_gtest_report = True
+    cls._fake_browser_options.output_dir = None
+    cls._fake_browser_options .upload_bucket = 'public'
+    cls._fake_browser_options .upload_results = False
+    cls._finder_options = cls._fake_browser_options
+    cls.platform = None
+    cls.browser = None
+    cls.SetBrowserOptions(cls._finder_options)
+    cls.StartBrowser()
+
+  @classmethod
+  def _CreateExpectations(cls):
+    return gpu_test_expectations.GpuTestExpectations()
+
+  @classmethod
+  def CrashOnStart(cls):
+    cls._test_state['num_browser_starts'] += 1
+    if cls._test_state['num_browser_crashes'] < 2:
+      cls._test_state['num_browser_crashes'] += 1
+      raise
+
+  @classmethod
+  def Name(cls):
+    return 'browser_start_failure_integration_unittest'
+
+  @classmethod
+  def GenerateGpuTests(cls, options):
+    # This test causes the browser to try and restart the browser 3 times.
+    yield ('restart', 'restart.html', ())
+
+  def RunActualGpuTest(self, file_path, *args):
+    # The logic of this test is run when the browser starts, it fails twice
+    # and then succeeds on the third time so we are just testing that this
+    # is successful based on the parameters.
+    pass
+
+
+class BrowserCrashAfterStartTest(_BaseSampleIntegrationTest):
+
+  _test_state = {
+    'num_browser_crashes': 0,
+    'num_browser_starts': 0,
+  }
+
+  @classmethod
+  def SetUpProcess(cls):
+    cls._fake_browser_options = fakes.CreateBrowserFinderOptions(
+      execute_after_browser_creation=cls.CrashAfterStart)
+    cls._fake_browser_options.browser_options.platform = \
+        fakes.FakeLinuxPlatform()
+    cls._fake_browser_options.output_formats = ['none']
+    cls._fake_browser_options.suppress_gtest_report = True
+    cls._fake_browser_options.output_dir = None
+    cls._fake_browser_options .upload_bucket = 'public'
+    cls._fake_browser_options .upload_results = False
+    cls._finder_options = cls._fake_browser_options
+    cls.platform = None
+    cls.browser = None
+    cls.SetBrowserOptions(cls._finder_options)
+    cls.StartBrowser()
+
+  @classmethod
+  def _CreateExpectations(cls):
+    return gpu_test_expectations.GpuTestExpectations()
+
+  @classmethod
+  def CrashAfterStart(cls, browser):
+    cls._test_state['num_browser_starts'] += 1
+    if cls._test_state['num_browser_crashes'] < 2:
+      cls._test_state['num_browser_crashes'] += 1
+      # This simulates the first tab's renderer process crashing upon
+      # startup. The try/catch forces the GpuIntegrationTest's first
+      # fetch of this tab to fail. crbug.com/682819
+      try:
+        browser.tabs[0].Navigate('chrome://crash')
+      except Exception:
+        pass
+
+  @classmethod
+  def Name(cls):
+    return 'browser_crash_after_start_integration_unittest'
+
+  @classmethod
+  def GenerateGpuTests(cls, options):
+    # This test causes the browser to try and restart the browser 3 times.
+    yield ('restart', 'restart.html', ())
+
+  def RunActualGpuTest(self, file_path, *args):
+    # The logic of this test is run when the browser starts, it fails twice
+    # and then succeeds on the third time so we are just testing that this
+    # is successful based on the parameters.
+    pass
+
+
+def load_tests(loader, tests, pattern):
+  del loader, tests, pattern  # Unused.
+  return gpu_integration_test.LoadAllTestsInModule(sys.modules[__name__])
diff --git a/content/test/web_contents_observer_sanity_checker.cc b/content/test/web_contents_observer_sanity_checker.cc
index 66c371c..e522297b 100644
--- a/content/test/web_contents_observer_sanity_checker.cc
+++ b/content/test/web_contents_observer_sanity_checker.cc
@@ -243,7 +243,8 @@
     const GURL& url,
     const Referrer& referrer,
     WindowOpenDisposition disposition,
-    ui::PageTransition transition) {
+    ui::PageTransition transition,
+    bool started_from_context_menu) {
   AssertRenderFrameExists(source_render_frame_host);
 }
 
diff --git a/content/test/web_contents_observer_sanity_checker.h b/content/test/web_contents_observer_sanity_checker.h
index 867706c..7bb576f0 100644
--- a/content/test/web_contents_observer_sanity_checker.h
+++ b/content/test/web_contents_observer_sanity_checker.h
@@ -61,7 +61,8 @@
                            const GURL& url,
                            const Referrer& referrer,
                            WindowOpenDisposition disposition,
-                           ui::PageTransition transition) override;
+                           ui::PageTransition transition,
+                           bool started_from_context_menu) override;
   void MediaStartedPlaying(const MediaPlayerInfo& media_info,
                            const MediaPlayerId& id) override;
   void MediaStoppedPlaying(const MediaPlayerInfo& media_info,
diff --git a/device/battery/battery_status_manager_linux_unittest.cc b/device/battery/battery_status_manager_linux_unittest.cc
index 68e28ac..6387af8 100644
--- a/device/battery/battery_status_manager_linux_unittest.cc
+++ b/device/battery/battery_status_manager_linux_unittest.cc
@@ -325,7 +325,7 @@
   dbus::MessageWriter array_writer(nullptr);
   dbus::MessageWriter dict_entry_writer(nullptr);
   writer->OpenArray("{sv}", &array_writer);
-  for (auto property_name :
+  for (auto* property_name :
        {kUPowerDevicePropertyIsPresent, kUPowerDevicePropertyState,
         kUPowerDevicePropertyTimeToEmpty, kUPowerDevicePropertyTimeToFull,
         kUPowerDevicePropertyType}) {
diff --git a/device/gamepad/gamepad_data_fetcher_manager.cc b/device/gamepad/gamepad_data_fetcher_manager.cc
index cb91e16..3cc662fb 100644
--- a/device/gamepad/gamepad_data_fetcher_manager.cc
+++ b/device/gamepad/gamepad_data_fetcher_manager.cc
@@ -53,7 +53,7 @@
   DCHECK(!provider_);
 
   provider_ = provider;
-  for (const auto& it : factories_) {
+  for (auto* it : factories_) {
     provider_->AddGamepadDataFetcher(it->CreateDataFetcher());
   }
 }
diff --git a/device/usb/usb_device_win.cc b/device/usb/usb_device_win.cc
index e54d1c88..18e83ef8 100644
--- a/device/usb/usb_device_win.cc
+++ b/device/usb/usb_device_win.cc
@@ -18,10 +18,12 @@
     const std::string& device_path,
     const std::string& hub_path,
     int port_number,
+    const std::string& driver_name,
     scoped_refptr<base::SequencedTaskRunner> blocking_task_runner)
     : device_path_(device_path),
       hub_path_(hub_path),
       port_number_(port_number),
+      driver_name_(driver_name),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       blocking_task_runner_(std::move(blocking_task_runner)) {}
 
diff --git a/device/usb/usb_device_win.h b/device/usb/usb_device_win.h
index 2c43a52..dd17683 100644
--- a/device/usb/usb_device_win.h
+++ b/device/usb/usb_device_win.h
@@ -32,12 +32,14 @@
   UsbDeviceWin(const std::string& device_path,
                const std::string& hub_path,
                int port_number,
+               const std::string& driver_name,
                scoped_refptr<base::SequencedTaskRunner> task_runner);
 
   ~UsbDeviceWin() override;
 
   const std::string& device_path() const { return device_path_; }
   int port_number() const { return port_number_; }
+  const std::string& driver_name() const { return driver_name_; }
 
   // Opens the device's parent hub in order to read the device, configuration
   // and string descriptors.
@@ -59,6 +61,7 @@
   const std::string device_path_;
   const std::string hub_path_;
   const int port_number_;
+  const std::string driver_name_;
 
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
   scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
diff --git a/device/usb/usb_service_unittest.cc b/device/usb/usb_service_unittest.cc
index d5714ff..4013fbe 100644
--- a/device/usb/usb_service_unittest.cc
+++ b/device/usb/usb_service_unittest.cc
@@ -8,7 +8,9 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_io_thread.h"
+#include "device/base/features.h"
 #include "device/test/test_device_client.h"
 #include "device/test/usb_test_gadget.h"
 #include "device/usb/usb_device.h"
@@ -50,6 +52,19 @@
   }
 }
 
+#if defined(OS_WIN)
+TEST_F(UsbServiceTest, GetDevicesNewBackend) {
+  base::test::ScopedFeatureList features;
+  features.InitAndEnableFeature(device::kNewUsbBackend);
+  UsbService* service = device_client_->GetUsbService();
+  if (service) {
+    base::RunLoop loop;
+    service->GetDevices(base::Bind(&OnGetDevices, loop.QuitClosure()));
+    loop.Run();
+  }
+}
+#endif  // defined(OS_WIN)
+
 TEST_F(UsbServiceTest, ClaimGadget) {
   if (!UsbTestGadget::IsTestEnabled()) return;
 
diff --git a/device/usb/usb_service_win.cc b/device/usb/usb_service_win.cc
index 65de4b0..8cc9c0c 100644
--- a/device/usb/usb_service_win.cc
+++ b/device/usb/usb_service_win.cc
@@ -83,8 +83,9 @@
                                SP_DEVICE_INTERFACE_DATA* device_interface_data,
                                std::string* device_path,
                                uint32_t* port_number,
-                               std::string* parent_instance_id) {
-  DWORD required_size;
+                               std::string* parent_instance_id,
+                               std::string* service_name) {
+  DWORD required_size = 0;
   if (SetupDiGetDeviceInterfaceDetail(dev_info, device_interface_data, nullptr,
                                       0, &required_size, nullptr) ||
       GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
@@ -127,6 +128,20 @@
     }
   }
 
+  if (service_name) {
+    if (!GetDeviceStringProperty(dev_info, &dev_info_data,
+                                 DEVPKEY_Device_Service, service_name)) {
+      USB_PLOG(ERROR) << "Failed to get device driver name";
+      return false;
+    }
+
+    // Windows pads this string with a variable number of NUL bytes for no
+    // discernible reason.
+    size_t end = service_name->find_last_not_of('\0');
+    if (end != std::string::npos)
+      service_name->erase(end + 1);
+  }
+
   return true;
 }
 
@@ -150,7 +165,7 @@
   }
 
   return GetDeviceInterfaceDetails(dev_info.get(), &device_interface_data,
-                                   device_path, nullptr, nullptr);
+                                   device_path, nullptr, nullptr, nullptr);
 }
 
 }  // namespace
@@ -182,9 +197,10 @@
       std::string device_path;
       uint32_t port_number;
       std::string parent_instance_id;
+      std::string service_name;
       if (!GetDeviceInterfaceDetails(dev_info.get(), &device_interface_data,
                                      &device_path, &port_number,
-                                     &parent_instance_id)) {
+                                     &parent_instance_id, &service_name)) {
         continue;
       }
 
@@ -198,8 +214,9 @@
       }
 
       service_task_runner_->PostTask(
-          FROM_HERE, base::Bind(&UsbServiceWin::CreateDeviceObject, service_,
-                                device_path, hub_path, port_number));
+          FROM_HERE,
+          base::Bind(&UsbServiceWin::CreateDeviceObject, service_, device_path,
+                     hub_path, port_number, service_name));
     }
 
     if (GetLastError() != ERROR_NO_MORE_ITEMS)
@@ -228,9 +245,10 @@
 
     uint32_t port_number;
     std::string parent_instance_id;
+    std::string service_name;
     if (!GetDeviceInterfaceDetails(dev_info.get(), &device_interface_data,
-                                   nullptr, &port_number,
-                                   &parent_instance_id)) {
+                                   nullptr, &port_number, &parent_instance_id,
+                                   &service_name)) {
       return;
     }
 
@@ -244,8 +262,9 @@
     }
 
     service_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&UsbServiceWin::CreateDeviceObject, service_,
-                              device_path, hub_path, port_number));
+        FROM_HERE,
+        base::Bind(&UsbServiceWin::CreateDeviceObject, service_, device_path,
+                   hub_path, port_number, service_name));
   }
 
  private:
@@ -327,15 +346,16 @@
 
 void UsbServiceWin::CreateDeviceObject(const std::string& device_path,
                                        const std::string& hub_path,
-                                       int port_number) {
+                                       int port_number,
+                                       const std::string& driver_name) {
   // Devices that appear during initial enumeration are gathered into the first
   // result returned by GetDevices() and prevent device add/remove notifications
   // from being sent.
   if (!enumeration_ready())
     ++first_enumeration_countdown_;
 
-  scoped_refptr<UsbDeviceWin> device(
-      new UsbDeviceWin(device_path, hub_path, port_number, task_runner()));
+  scoped_refptr<UsbDeviceWin> device(new UsbDeviceWin(
+      device_path, hub_path, port_number, driver_name, blocking_task_runner()));
   devices_by_path_[device->device_path()] = device;
   device->ReadDescriptors(base::Bind(&UsbServiceWin::DeviceReady,
                                      weak_factory_.GetWeakPtr(), device));
@@ -367,7 +387,8 @@
                   << device->manufacturer_string()
                   << "\", product=" << device->product_id() << " \""
                   << device->product_string() << "\", serial=\""
-                  << device->serial_number() << "\", guid=" << device->guid();
+                  << device->serial_number() << "\", driver=\""
+                  << device->driver_name() << "\", guid=" << device->guid();
   } else {
     devices_by_path_.erase(it);
   }
diff --git a/device/usb/usb_service_win.h b/device/usb/usb_service_win.h
index a915577..58f4bb2 100644
--- a/device/usb/usb_service_win.h
+++ b/device/usb/usb_service_win.h
@@ -41,7 +41,8 @@
   void HelperStarted();
   void CreateDeviceObject(const std::string& device_path,
                           const std::string& hub_path,
-                          int port_number);
+                          int port_number,
+                          const std::string& driver_name);
 
   void DeviceReady(scoped_refptr<UsbDeviceWin> device, bool success);
 
diff --git a/docs/ios_infra.md b/docs/ios_infra.md
index cd423126..3ab0d7f 100644
--- a/docs/ios_infra.md
+++ b/docs/ios_infra.md
@@ -118,14 +118,239 @@
 determined not to affect a certain test target, compilation and execution of the
 test target will be skipped.
 
+## Configuring the bots
+
+See the [configs code location](#Configs) for where to find the config files for
+the bots. The config files are JSON which describe how the bot should compile
+and which tests it should run. The config files are located in the configs
+directory. The configs directory contains a named directory for each master. For
+example:
+```shell
+$ ls ios/build/bots
+OWNERS  scripts  tests  chromium.fyi  chromium.mac
+```
+In this case, configs are defined for iOS bots on [chromium.fyi] and
+[chromium.mac]. Inside each master-specific directory are JSON config files
+named after each bot. For example:
+```shell
+$ ls ios/build/bots/chromium.mac
+ios-device.json ios-simulator.json
+```
+The `ios-device` bot on [chromium.mac] will read its configuration from
+`chromium.mac/ios-device.json` in the configs directory.
+
+### Example
+
+```json
+{
+  "comments": [
+    "Sample config for a bot."
+  ],
+  "gn_args": [
+    "is_debug=true",
+    "target_cpu=\"x64\""
+  ],
+  "tests": [
+    {
+      "app": "ios_chrome_unittests",
+      "device type": "iPhone 5s",
+      "os": "10.0",
+      "xcode version": "8.0"
+    }
+  ]
+}
+```
+The `comments` key is optional and defines a list of strings which can be used
+to annotate the config. You may want to explain why the bot exists and what it's
+doing, particularly if there are extensive and atypical `gn_args`.
+
+The `gn_args` key is a required list of arguments to pass to [GN] to generate
+the build files. Two GN args are required, `is_debug` and `target_cpu`. Use
+`is_debug` to define whether to compile for Debug or Release, and `target_cpu`
+to define whether to compile for x86, x64, arm, or arm64. The iOS bots typically
+perform Debug builds for x86 and x64, and Release builds for arm and arm64. An
+x86/x64 build can only be tested on the [iOS simulator], while an arm/arm64
+build can only be tested on a physical device.
+
+Since Chromium for iOS is shipped as a [universal binary], it's also fairly
+common to set `additional_target_cpus`. For simulator builds, we typically set:
+```json
+"gn_args": [
+  "additional_target_cpus=[\"x86\"]",
+  "is_debug=true",
+  "target_cpu=\"x64\""
+]
+```
+This builds universal binaries which run in 32-bit mode on 32-bit simulators and
+64-bit mode on 64-bit simulators. For device builds we typically set:
+```json
+"gn_args": [
+  "additional_target_cpus=[\"arm\"]",
+  "is_debug=false",
+  "target_cpu=\"arm64\""
+]
+```
+In order to build universal binaries which run in 32-bit mode on 32-bit devices
+and 64-bit mode on 64-bit devices.
+
+The `tests` key is an optional list of dictionaries defining tests to run. There
+are two types of test dictionary, `app` and `include`. An `app` dict defines a
+specific compiled app to run, for example:
+```json
+"tests": [
+  {
+    "app": "ios_chrome_unittests",
+    "device type": "iPhone 5s",
+    "os": "10.0",
+    "xcode version": "8.0"
+  }
+]
+```
+This dict says to run `ios_chrome_unittests` on an `iPhone 5s` running iOS
+`10.0` using Xcode `8.0`. A test dict may optionally define a list of `test
+args`, which are arguments to pass directly to the test on the command line,
+and it may define a boolean value `xctest` to indicate whether the test is an
+[xctest] \(default if unspecified is `false`\). For example:
+```json
+"tests": [
+  {
+    "app": "ios_chrome_unittests",
+    "device type": "iPhone 5s",
+    "os": "10.0",
+    "test args": [
+      "--foo",
+      "--bar"
+    ],
+    "xcode version": "8.0"
+  },
+  {
+    "app": "ios_chrome_integration_egtests",
+    "device type": "iPhone 5s",
+    "os": "10.0",
+    "xcode version": "8.0",
+    "xctest": true
+  }
+]
+```
+This defines two tests to run, first `ios_chrome_unittests` will be run with
+`--foo` and `--bar` passed directly to the test on the command line. Next,
+`ios_chrome_integration_egtests` will be run as an xctest. `"xctest": true`
+must be specified for all xctests, it is an error to try and launch an xctest as
+a regular test.
+
+An `include` dict defines a list of tests to import from the `tests`
+subdirectory in the configs directory. For example:
+```json
+"tests": [
+  {
+    "include": "common_tests.json",
+    "device type": "iPhone 5s",
+    "os": "10.0",
+    "xcode version": "8.0"
+  }
+]
+```
+This dict says to import the list of tests from the `tests` subdirectory and run
+each one on an `iPhone 5s` running iOS `10.0` using Xcode `8.0`. Here's what
+`common_tests.json` might look like:
+```json
+"tests": [
+  {
+    "app": "ios_chrome_unittests"
+  },
+  {
+    "app": "ios_net_unittests"
+  },
+  {
+    "app": "ios_web_unittests"
+  },
+]
+```
+Includes may contain other keys besides `app` which can then be omitted in the
+bot config. For example if `common_tests.json` specifies:
+```json
+"tests": [
+  {
+    "app": "ios_chrome_integration_egtests",
+    "xctest": true,
+    "xcode version": "8.0"
+  }
+]
+```
+Then the bot config may omit the `xctest` or `xcode version` keys, for example:
+```json
+{
+  "comments": [
+    "Sample config for a bot."
+  ],
+  "gn_args": [
+    "is_debug=true",
+    "target_cpu=\"x64\""
+  ],
+  "tests": [
+    {
+      "include": "common_tests.json",
+      "device type": "iPhone 5s",
+      "os": "10.0"
+    }
+  ]
+}
+```
+Includes are not recursive, so `common_tests.json` may not itself include any
+`include` dicts.
+
+### Uploading compiled artifacts from a bot
+
+A bot may be configured to upload compiled artifacts. This is defined by the
+`upload` key. For example:
+```json
+{
+  "comments": [
+    "Sample config for a bot which uploads artifacts."
+  ],
+  "gn_args": [
+    "is_debug=true",
+    "target_cpu=\"x64\""
+  ],
+  "upload": [
+    {
+      "artifact": "Chromium.breakpad",
+      "bucket": "my-gcs-bucket",
+    },
+    {
+      "artifact": "Chromium.app",
+      "bucket": "my-gcs-bucket",
+      "compress": true,
+    },
+    {
+      "artifact": "Chromium.breakpad",
+      "symupload": true,
+    }
+  ]
+}
+```
+After compilation, the bot will upload three artifacts. First the
+`Chromium.breakpad` symbols will be uploaded to
+`gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.breakpad`. Next
+`Chromium.app` will be tarred, gzipped, and uploaded to
+`gs://my-gcs-bucket/<buildername>/<buildnumber>/Chromium.tar.gz`. Finally
+the `Chromium.breakpad` symbols will be uploaded to the [breakpad] crash
+reporting server where they can be used to symbolicate stack traces.
+
+If `artifact` is a directory, you must specify `"compress": true`.
+
 [analyzer]: ../tools/mb
+[breakpad]: https://chromium.googlesource.com/breakpad/breakpad
 [buildbucket]: https://cr-buildbucket.appspot.com
+[chromium.fyi]: https://build.chromium.org/p/chromium.fyi/waterfall
 [chromium.mac]: https://build.chromium.org/p/chromium.mac
 [clang]: ../tools/clang
 [commit queue]: https://dev.chromium.org/developers/testing/commit-queue
 [gitiles]: https://gerrit.googlesource.com/gitiles
+[GN]: ../tools/gn
 [instructions]: ./ios_build_instructions.md
 [iOS recipes]: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipes/ios
+[iOS simulator]: ../testing/iossim
 [recipe module]: https://chromium.googlesource.com/chromium/tools/build/+/master/scripts/slave/recipe_modules/ios
 [recipes]: https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/recipes.md
 [simulator]: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/iOS_Simulator_Guide/Introduction/Introduction.html
@@ -138,3 +363,5 @@
 [try job access]: https://www.chromium.org/getting-involved/become-a-committer#TOC-Try-job-access
 [try server]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall
 [tryserver.chromium.mac]: https://build.chromium.org/p/tryserver.chromium.mac/waterfall
+[universal binary]: https://en.wikipedia.org/wiki/Universal_binary
+[xctest]: https://developer.apple.com/reference/xctest
diff --git a/extensions/browser/api/declarative/rules_registry_service.cc b/extensions/browser/api/declarative/rules_registry_service.cc
index 8fac461..3d8e5ba 100644
--- a/extensions/browser/api/declarative/rules_registry_service.cc
+++ b/extensions/browser/api/declarative/rules_registry_service.cc
@@ -20,6 +20,8 @@
 #include "extensions/browser/api/web_request/web_request_api.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/features/feature_provider.h"
 
 namespace extensions {
 
@@ -74,24 +76,31 @@
   if (ContainsKey(rule_registries_, key))
     return;
 
-  // Only cache rules for regular pages.
-  RulesCacheDelegate* web_request_cache_delegate = NULL;
-  if (rules_registry_id == kDefaultRulesRegistryID) {
-    // Create a RulesCacheDelegate.
-    web_request_cache_delegate =
-        new RulesCacheDelegate(true /*log_storage_init_delay*/);
-    cache_delegates_.push_back(base::WrapUnique(web_request_cache_delegate));
-  }
-  scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
-      new WebRequestRulesRegistry(browser_context_, web_request_cache_delegate,
-                                  rules_registry_id));
+  // Create a web request rules registry if declarative web request is enabled
+  // on the current channel.
+  const Feature* declarative_web_request =
+      FeatureProvider::GetAPIFeature("declarativeWebRequest");
+  if (declarative_web_request->IsAvailableToChannel(GetCurrentChannel())
+          .is_available()) {
+    // Only cache rules for regular pages.
+    RulesCacheDelegate* web_request_cache_delegate = nullptr;
+    if (rules_registry_id == kDefaultRulesRegistryID) {
+      // Create a RulesCacheDelegate.
+      web_request_cache_delegate =
+          new RulesCacheDelegate(true /*log_storage_init_delay*/);
+      cache_delegates_.push_back(base::WrapUnique(web_request_cache_delegate));
+    }
+    scoped_refptr<WebRequestRulesRegistry> web_request_rules_registry(
+        new WebRequestRulesRegistry(
+            browser_context_, web_request_cache_delegate, rules_registry_id));
 
-  RegisterRulesRegistry(web_request_rules_registry);
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
-                 browser_context_, rules_registry_id,
-                 web_request_rules_registry));
+    RegisterRulesRegistry(web_request_rules_registry);
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&RegisterToExtensionWebRequestEventRouterOnIO,
+                   browser_context_, rules_registry_id,
+                   web_request_rules_registry));
+  }
 
   // Only create a ContentRulesRegistry for regular pages.
   if (rules_registry_id == kDefaultRulesRegistryID) {
diff --git a/extensions/browser/api/file_handlers/directory_util.cc b/extensions/browser/api/file_handlers/directory_util.cc
index 516be8f..96d8faa 100644
--- a/extensions/browser/api/file_handlers/directory_util.cc
+++ b/extensions/browser/api/file_handlers/directory_util.cc
@@ -6,9 +6,9 @@
 
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
 #include "net/base/filename_util.h"
 #include "storage/browser/fileapi/file_system_url.h"
 
@@ -22,16 +22,9 @@
 
 namespace {
 
-void GetIsDirectoryFromFileInfo(const base::FilePath& path,
-                                bool* is_directory) {
+bool GetIsDirectoryFromFileInfo(const base::FilePath& path) {
   base::File::Info file_info;
-  *is_directory = GetFileInfo(path, &file_info) && file_info.is_directory;
-}
-
-void OnGetIsDirectoryFromFileInfoCompleted(
-    std::unique_ptr<bool> is_directory,
-    const base::Callback<void(bool)>& callback) {
-  callback.Run(*is_directory);
+  return GetFileInfo(path, &file_info) && file_info.is_directory;
 }
 
 // The callback parameter contains the result and is required to support
@@ -49,14 +42,9 @@
   }
 #endif
 
-  std::unique_ptr<bool> is_directory(new bool);
-  bool* const is_directory_ptr = is_directory.get();
-
-  content::BrowserThread::PostBlockingPoolTaskAndReply(
-      FROM_HERE,
-      base::Bind(&GetIsDirectoryFromFileInfo, path, is_directory_ptr),
-      base::Bind(&OnGetIsDirectoryFromFileInfoCompleted,
-                 base::Passed(&is_directory), callback));
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, base::TaskTraits().MayBlock(),
+      base::Bind(&GetIsDirectoryFromFileInfo, path), callback);
 }
 
 }  // namespace
diff --git a/extensions/browser/api/printer_provider/OWNERS b/extensions/browser/api/printer_provider/OWNERS
index 0fa42c6a4..d038a71 100644
--- a/extensions/browser/api/printer_provider/OWNERS
+++ b/extensions/browser/api/printer_provider/OWNERS
@@ -1,2 +1,4 @@
 tbarzic@chromium.org
 vitalybuka@chromium.org
+
+# COMPONENT: Internals>Printing
diff --git a/extensions/browser/api/printer_provider_internal/OWNERS b/extensions/browser/api/printer_provider_internal/OWNERS
index 0fa42c6a4..d038a71 100644
--- a/extensions/browser/api/printer_provider_internal/OWNERS
+++ b/extensions/browser/api/printer_provider_internal/OWNERS
@@ -1,2 +1,4 @@
 tbarzic@chromium.org
 vitalybuka@chromium.org
+
+# COMPONENT: Internals>Printing
diff --git a/extensions/browser/api/system_display/system_display_api.cc b/extensions/browser/api/system_display/system_display_api.cc
index a12d237..820e2fb 100644
--- a/extensions/browser/api/system_display/system_display_api.cc
+++ b/extensions/browser/api/system_display/system_display_api.cc
@@ -142,7 +142,7 @@
   if (!create)
     return nullptr;
   auto owned_observer = base::MakeUnique<OverscanWebObserver>(web_contents);
-  auto observer_ptr = owned_observer.get();
+  auto* observer_ptr = owned_observer.get();
   observers_[web_contents] = std::move(owned_observer);
   return observer_ptr;
 }
diff --git a/extensions/browser/content_verify_job.cc b/extensions/browser/content_verify_job.cc
index 56552f8..e2f9f7eb 100644
--- a/extensions/browser/content_verify_job.cc
+++ b/extensions/browser/content_verify_job.cc
@@ -8,10 +8,8 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
-#include "base/task_runner_util.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/timer/elapsed_timer.h"
-#include "content/public/browser/browser_thread.h"
 #include "crypto/secure_hash.h"
 #include "crypto/sha2.h"
 #include "extensions/browser/content_hash_reader.h"
@@ -67,9 +65,10 @@
   if (g_test_observer)
     g_test_observer->JobStarted(hash_reader_->extension_id(),
                                 hash_reader_->relative_path());
-  base::PostTaskAndReplyWithResult(
-      content::BrowserThread::GetBlockingPool(),
+  base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE,
+      base::TaskTraits().MayBlock().WithPriority(
+          base::TaskPriority::USER_VISIBLE),
       base::Bind(&ContentHashReader::Init, hash_reader_),
       base::Bind(&ContentVerifyJob::OnHashesReady, this));
 }
diff --git a/extensions/browser/image_loader.cc b/extensions/browser/image_loader.cc
index c2b1fff..038e8be 100644
--- a/extensions/browser/image_loader.cc
+++ b/extensions/browser/image_loader.cc
@@ -244,7 +244,7 @@
     scales.insert(ui::GetScaleForScaleFactor(scale));
 
   // There may not be a screen in unit tests.
-  auto screen = display::Screen::GetScreen();
+  auto* screen = display::Screen::GetScreen();
   if (screen) {
     for (const auto& display : screen->GetAllDisplays())
       scales.insert(display.device_scale_factor());
diff --git a/extensions/browser/sandboxed_unpacker.cc b/extensions/browser/sandboxed_unpacker.cc
index 649a48c..043dcd6 100644
--- a/extensions/browser/sandboxed_unpacker.cc
+++ b/extensions/browser/sandboxed_unpacker.cc
@@ -36,7 +36,7 @@
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
 #include "extensions/common/switches.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/codec/png_codec.h"
diff --git a/extensions/browser/updater/safe_manifest_parser.cc b/extensions/browser/updater/safe_manifest_parser.cc
index 3bc3aee0..08f22a1 100644
--- a/extensions/browser/updater/safe_manifest_parser.cc
+++ b/extensions/browser/updater/safe_manifest_parser.cc
@@ -12,8 +12,8 @@
 #include "content/public/browser/utility_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/common/extension_utility_messages.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ipc/ipc_message_macros.h"
-#include "grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using content::BrowserThread;
diff --git a/extensions/common/api/bluetooth/bluetooth_manifest_handler.cc b/extensions/common/api/bluetooth/bluetooth_manifest_handler.cc
index 6a666d9..e2ffb520 100644
--- a/extensions/common/api/bluetooth/bluetooth_manifest_handler.cc
+++ b/extensions/common/api/bluetooth/bluetooth_manifest_handler.cc
@@ -24,7 +24,7 @@
   if (!data)
     return false;
 
-  extension->SetManifestData(manifest_keys::kBluetooth, data.release());
+  extension->SetManifestData(manifest_keys::kBluetooth, std::move(data));
   return true;
 }
 
diff --git a/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc b/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
index bb6e314..4b67edf 100644
--- a/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
+++ b/extensions/common/api/bluetooth/bluetooth_manifest_permission.cc
@@ -16,7 +16,7 @@
 #include "extensions/common/features/behavior_feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/manifest_constants.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ipc/ipc_message.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/extensions/common/api/declarative/declarative_manifest_handler.cc b/extensions/common/api/declarative/declarative_manifest_handler.cc
index 28b0482..6ff2a318 100644
--- a/extensions/common/api/declarative/declarative_manifest_handler.cc
+++ b/extensions/common/api/declarative/declarative_manifest_handler.cc
@@ -25,7 +25,7 @@
   if (!data)
     return false;
 
-  extension->SetManifestData(manifest_keys::kEventRules, data.release());
+  extension->SetManifestData(manifest_keys::kEventRules, std::move(data));
   return true;
 }
 
diff --git a/extensions/common/api/printer_provider/usb_printer_manifest_handler.cc b/extensions/common/api/printer_provider/usb_printer_manifest_handler.cc
index eb6468f..d4fd8ee4 100644
--- a/extensions/common/api/printer_provider/usb_printer_manifest_handler.cc
+++ b/extensions/common/api/printer_provider/usb_printer_manifest_handler.cc
@@ -26,7 +26,7 @@
     return false;
   }
 
-  extension->SetManifestData(manifest_keys::kUsbPrinters, data.release());
+  extension->SetManifestData(manifest_keys::kUsbPrinters, std::move(data));
   return true;
 }
 
diff --git a/extensions/common/api/sockets/sockets_manifest_handler.cc b/extensions/common/api/sockets/sockets_manifest_handler.cc
index cad731ef..d678b7e 100644
--- a/extensions/common/api/sockets/sockets_manifest_handler.cc
+++ b/extensions/common/api/sockets/sockets_manifest_handler.cc
@@ -24,7 +24,7 @@
   if (!data)
     return false;
 
-  extension->SetManifestData(manifest_keys::kSockets, data.release());
+  extension->SetManifestData(manifest_keys::kSockets, std::move(data));
   return true;
 }
 
diff --git a/extensions/common/api/sockets/sockets_manifest_permission.cc b/extensions/common/api/sockets/sockets_manifest_permission.cc
index aa90412..3380173 100644
--- a/extensions/common/api/sockets/sockets_manifest_permission.cc
+++ b/extensions/common/api/sockets/sockets_manifest_permission.cc
@@ -14,7 +14,7 @@
 #include "extensions/common/api/sockets/sockets_manifest_data.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/manifest_constants.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ipc/ipc_message.h"
 #include "ui/base/l10n/l10n_util.h"
 
diff --git a/extensions/common/event_filter.cc b/extensions/common/event_filter.cc
index b91f25f..7130238 100644
--- a/extensions/common/event_filter.cc
+++ b/extensions/common/event_filter.cc
@@ -87,13 +87,14 @@
 bool EventFilter::CreateConditionSets(
     EventMatcher* matcher,
     URLMatcherConditionSet::Vector* condition_sets) {
-  if (matcher->GetURLFilterCount() == 0) {
+  int url_filter_count = matcher->GetURLFilterCount();
+  if (url_filter_count == 0) {
     // If there are no URL filters then we want to match all events, so create a
     // URLFilter from an empty dictionary.
     base::DictionaryValue empty_dict;
     return AddDictionaryAsConditionSet(&empty_dict, condition_sets);
   }
-  for (int i = 0; i < matcher->GetURLFilterCount(); i++) {
+  for (int i = 0; i < url_filter_count; i++) {
     base::DictionaryValue* url_filter;
     if (!matcher->GetURLFilter(i, &url_filter))
       return false;
@@ -176,7 +177,7 @@
   return matchers;
 }
 
-int EventFilter::GetMatcherCountForEvent(const std::string& name) {
+int EventFilter::GetMatcherCountForEventForTesting(const std::string& name) {
   EventMatcherMultiMap::const_iterator it = event_matchers_.find(name);
   if (it == event_matchers_.end())
     return 0;
diff --git a/extensions/common/event_filter.h b/extensions/common/event_filter.h
index 288c4a1d..55b85b9 100644
--- a/extensions/common/event_filter.h
+++ b/extensions/common/event_filter.h
@@ -48,12 +48,9 @@
                                  const EventFilteringInfo& event_info,
                                  int routing_id);
 
-  int GetMatcherCountForEvent(const std::string& event_name);
+  int GetMatcherCountForEventForTesting(const std::string& event_name);
 
-  // For testing.
-  bool IsURLMatcherEmpty() const {
-    return url_matcher_.IsEmpty();
-  }
+  bool IsURLMatcherEmptyForTesting() const { return url_matcher_.IsEmpty(); }
 
  private:
   class EventMatcherEntry {
diff --git a/extensions/common/event_filter_unittest.cc b/extensions/common/event_filter_unittest.cc
index 1d88d0e7..6e96c991 100644
--- a/extensions/common/event_filter_unittest.cc
+++ b/extensions/common/event_filter_unittest.cc
@@ -192,15 +192,15 @@
 }
 
 TEST_F(EventFilterUnittest, TestGetMatcherCountForEvent) {
-  ASSERT_EQ(0, event_filter_.GetMatcherCountForEvent("event1"));
+  ASSERT_EQ(0, event_filter_.GetMatcherCountForEventForTesting("event1"));
   int id1 = event_filter_.AddEventMatcher("event1", AllURLs());
-  ASSERT_EQ(1, event_filter_.GetMatcherCountForEvent("event1"));
+  ASSERT_EQ(1, event_filter_.GetMatcherCountForEventForTesting("event1"));
   int id2 = event_filter_.AddEventMatcher("event1", AllURLs());
-  ASSERT_EQ(2, event_filter_.GetMatcherCountForEvent("event1"));
+  ASSERT_EQ(2, event_filter_.GetMatcherCountForEventForTesting("event1"));
   event_filter_.RemoveEventMatcher(id1);
-  ASSERT_EQ(1, event_filter_.GetMatcherCountForEvent("event1"));
+  ASSERT_EQ(1, event_filter_.GetMatcherCountForEventForTesting("event1"));
   event_filter_.RemoveEventMatcher(id2);
-  ASSERT_EQ(0, event_filter_.GetMatcherCountForEvent("event1"));
+  ASSERT_EQ(0, event_filter_.GetMatcherCountForEventForTesting("event1"));
 }
 
 TEST_F(EventFilterUnittest, RemoveEventMatcherReturnsEventName) {
@@ -220,7 +220,7 @@
   std::unique_ptr<EventMatcher> matcher(
       MatcherFromURLFilterList(std::move(filter_list)));
   int id1 = event_filter_.AddEventMatcher("event1", std::move(matcher));
-  EXPECT_TRUE(event_filter_.IsURLMatcherEmpty());
+  EXPECT_TRUE(event_filter_.IsURLMatcherEmptyForTesting());
   ASSERT_EQ(-1, id1);
 }
 
@@ -237,12 +237,12 @@
 
 TEST_F(EventFilterUnittest,
     InternalURLMatcherShouldBeEmptyWhenThereAreNoEventMatchers) {
-  ASSERT_TRUE(event_filter_.IsURLMatcherEmpty());
+  ASSERT_TRUE(event_filter_.IsURLMatcherEmptyForTesting());
   int id = event_filter_.AddEventMatcher("event1",
                                          HostSuffixMatcher("google.com"));
-  ASSERT_FALSE(event_filter_.IsURLMatcherEmpty());
+  ASSERT_FALSE(event_filter_.IsURLMatcherEmptyForTesting());
   event_filter_.RemoveEventMatcher(id);
-  ASSERT_TRUE(event_filter_.IsURLMatcherEmpty());
+  ASSERT_TRUE(event_filter_.IsURLMatcherEmptyForTesting());
 }
 
 TEST_F(EventFilterUnittest, EmptyURLsShouldBeMatchedByEmptyURLFilters) {
diff --git a/extensions/common/event_matcher.cc b/extensions/common/event_matcher.cc
index 25d23ab9..3876b899 100644
--- a/extensions/common/event_matcher.cc
+++ b/extensions/common/event_matcher.cc
@@ -32,11 +32,13 @@
   }
 
   if (event_info.has_window_type()) {
-    for (int i = 0; i < GetWindowTypeCount(); i++) {
+    int window_type_count = GetWindowTypeCount();
+    for (int i = 0; i < window_type_count; i++) {
       std::string window_type;
       if (GetWindowType(i, &window_type) &&
-          window_type == event_info.window_type())
+          window_type == event_info.window_type()) {
         return true;
+      }
     }
     return false;
   }
diff --git a/extensions/common/event_matcher.h b/extensions/common/event_matcher.h
index e775398..802aa68 100644
--- a/extensions/common/event_matcher.h
+++ b/extensions/common/event_matcher.h
@@ -55,9 +55,9 @@
   // {url: [{hostSuffix: 'google.com'}]}
   //
   // The valid filter keys are event-specific.
-  std::unique_ptr<base::DictionaryValue> filter_;
+  const std::unique_ptr<base::DictionaryValue> filter_;
 
-  int routing_id_;
+  const int routing_id_;
 
   DISALLOW_COPY_AND_ASSIGN(EventMatcher);
 };
diff --git a/extensions/common/extension.cc b/extensions/common/extension.cc
index 6e86d9e..2022263d 100644
--- a/extensions/common/extension.cc
+++ b/extensions/common/extension.cc
@@ -379,9 +379,9 @@
 }
 
 void Extension::SetManifestData(const std::string& key,
-                                Extension::ManifestData* data) {
+                                std::unique_ptr<Extension::ManifestData> data) {
   DCHECK(!finished_parsing_manifest_ && thread_checker_.CalledOnValidThread());
-  manifest_data_[key] = std::unique_ptr<ManifestData>(data);
+  manifest_data_[key] = std::move(data);
 }
 
 Manifest::Location Extension::location() const {
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index a5c2702..97c0ca6eb 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -258,10 +258,11 @@
   // Can only be called after InitValue is finished.
   ManifestData* GetManifestData(const std::string& key) const;
 
-  // Sets |data| to be associated with the key. Takes ownership of |data|.
+  // Sets |data| to be associated with the key.
   // Can only be called before InitValue is finished. Not thread-safe;
   // all SetManifestData calls should be on only one thread.
-  void SetManifestData(const std::string& key, ManifestData* data);
+  void SetManifestData(const std::string& key,
+                       std::unique_ptr<ManifestData> data);
 
   // Accessors:
 
diff --git a/extensions/common/features/complex_feature.cc b/extensions/common/features/complex_feature.cc
index ed129da..35680d1 100644
--- a/extensions/common/features/complex_feature.cc
+++ b/extensions/common/features/complex_feature.cc
@@ -98,6 +98,24 @@
   return false;
 }
 
+Feature::Availability ComplexFeature::IsAvailableToChannel(
+    version_info::Channel channel) const {
+  Feature::Availability first_availability =
+      features_[0]->IsAvailableToChannel(channel);
+  if (first_availability.is_available())
+    return first_availability;
+
+  for (FeatureList::const_iterator it = features_.begin() + 1;
+       it != features_.end(); ++it) {
+    Availability availability = (*it)->IsAvailableToChannel(channel);
+    if (availability.is_available())
+      return availability;
+  }
+  // If none of the SimpleFeatures are available, we return the availability
+  // info of the first SimpleFeature that was not available.
+  return first_availability;
+}
+
 bool ComplexFeature::IsInternal() const {
   // Constructor verifies that composed features are consistent, thus we can
   // return just the first feature's value.
diff --git a/extensions/common/features/complex_feature.h b/extensions/common/features/complex_feature.h
index 9ccbd4f..c331901 100644
--- a/extensions/common/features/complex_feature.h
+++ b/extensions/common/features/complex_feature.h
@@ -41,6 +41,8 @@
 
   bool IsIdInBlacklist(const std::string& extension_id) const override;
   bool IsIdInWhitelist(const std::string& extension_id) const override;
+  Availability IsAvailableToChannel(
+      version_info::Channel channel) const override;
 
  protected:
   // Feature:
diff --git a/extensions/common/features/feature.h b/extensions/common/features/feature.h
index d3179bb9..0664e173 100644
--- a/extensions/common/features/feature.h
+++ b/extensions/common/features/feature.h
@@ -10,6 +10,7 @@
 
 #include "base/strings/string_piece.h"
 #include "base/values.h"
+#include "components/version_info/version_info.h"
 #include "extensions/common/manifest.h"
 
 class GURL;
@@ -136,6 +137,12 @@
                                             const GURL& url,
                                             Platform platform) const = 0;
 
+  // Returns the availability of the feature on the given |channel|. The
+  // availability result will either be IS_AVAILABLE, UNSUPPORTED_CHANNEL or
+  // NOT_PRESENT.
+  virtual Availability IsAvailableToChannel(
+      version_info::Channel channel) const = 0;
+
   // Returns true if the feature is available to the current environment,
   // without needing to know information about an Extension or any other
   // contextual information. Typically used when the Feature is purely
diff --git a/extensions/common/features/simple_feature.cc b/extensions/common/features/simple_feature.cc
index d901cd9..0f7675b1 100644
--- a/extensions/common/features/simple_feature.cc
+++ b/extensions/common/features/simple_feature.cc
@@ -53,6 +53,11 @@
   return feature->IsAvailableToContext(extension, context, url, platform);
 }
 
+Feature::Availability IsAvailableToChannelForBind(version_info::Channel channel,
+                                                  const Feature* feature) {
+  return feature->IsAvailableToChannel(channel);
+}
+
 // Gets a human-readable name for the given extension type, suitable for giving
 // to developers in an error message.
 std::string GetDisplayName(Manifest::Type type) {
@@ -455,6 +460,13 @@
   return IsIdInList(extension_id, whitelist_);
 }
 
+Feature::Availability SimpleFeature::IsAvailableToChannel(
+    version_info::Channel channel) const {
+  if (channel_ && *channel_ < channel)
+    return CreateAvailability(UNSUPPORTED_CHANNEL, *channel_);
+  return CheckDependencies(base::Bind(&IsAvailableToChannelForBind, channel));
+}
+
 // static
 bool SimpleFeature::IsIdInArray(const std::string& extension_id,
                                 const char* const array[],
diff --git a/extensions/common/features/simple_feature.h b/extensions/common/features/simple_feature.h
index 343282e..117da20a 100644
--- a/extensions/common/features/simple_feature.h
+++ b/extensions/common/features/simple_feature.h
@@ -76,6 +76,8 @@
   bool IsInternal() const override;
   bool IsIdInBlacklist(const std::string& extension_id) const override;
   bool IsIdInWhitelist(const std::string& extension_id) const override;
+  Availability IsAvailableToChannel(
+      version_info::Channel channel) const override;
 
   static bool IsIdInArray(const std::string& extension_id,
                           const char* const array[],
diff --git a/extensions/common/features/simple_feature_unittest.cc b/extensions/common/features/simple_feature_unittest.cc
index a570248..e8f4c3c 100644
--- a/extensions/common/features/simple_feature_unittest.cc
+++ b/extensions/common/features/simple_feature_unittest.cc
@@ -45,15 +45,9 @@
 
 Feature::AvailabilityResult IsAvailableInChannel(Channel channel_for_feature,
                                                  Channel channel_for_testing) {
-  ScopedCurrentChannel current_channel(channel_for_testing);
-
   SimpleFeature feature;
   feature.set_channel(channel_for_feature);
-  return feature
-      .IsAvailableToManifest("random-extension", Manifest::TYPE_UNKNOWN,
-                             Manifest::INVALID_LOCATION, -1,
-                             Feature::GetCurrentPlatform())
-      .result();
+  return feature.IsAvailableToChannel(channel_for_testing).result();
 }
 
 }  // namespace
@@ -762,56 +756,6 @@
             IsAvailableInChannel(Channel::UNKNOWN, Channel::STABLE));
 }
 
-// Tests simple feature availability across channels.
-TEST_F(SimpleFeatureTest, SimpleFeatureAvailability) {
-  std::unique_ptr<ComplexFeature> complex_feature;
-  {
-    std::unique_ptr<SimpleFeature> feature1(new SimpleFeature());
-    feature1->channel_.reset(new Channel(Channel::BETA));
-    feature1->extension_types_.push_back(Manifest::TYPE_EXTENSION);
-    std::unique_ptr<SimpleFeature> feature2(new SimpleFeature());
-    feature2->channel_.reset(new Channel(Channel::BETA));
-    feature2->extension_types_.push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
-    std::vector<Feature*> list;
-    list.push_back(feature1.release());
-    list.push_back(feature2.release());
-    complex_feature.reset(new ComplexFeature(&list));
-  }
-
-  Feature* feature = static_cast<Feature*>(complex_feature.get());
-  // Make sure both rules are applied correctly.
-  {
-    ScopedCurrentChannel current_channel(Channel::BETA);
-    EXPECT_EQ(
-        Feature::IS_AVAILABLE,
-        feature->IsAvailableToManifest("1",
-                                       Manifest::TYPE_EXTENSION,
-                                       Manifest::INVALID_LOCATION,
-                                       Feature::UNSPECIFIED_PLATFORM).result());
-    EXPECT_EQ(
-        Feature::IS_AVAILABLE,
-        feature->IsAvailableToManifest("2",
-                                       Manifest::TYPE_LEGACY_PACKAGED_APP,
-                                       Manifest::INVALID_LOCATION,
-                                       Feature::UNSPECIFIED_PLATFORM).result());
-  }
-  {
-    ScopedCurrentChannel current_channel(Channel::STABLE);
-    EXPECT_NE(
-        Feature::IS_AVAILABLE,
-        feature->IsAvailableToManifest("1",
-                                       Manifest::TYPE_EXTENSION,
-                                       Manifest::INVALID_LOCATION,
-                                       Feature::UNSPECIFIED_PLATFORM).result());
-    EXPECT_NE(
-        Feature::IS_AVAILABLE,
-        feature->IsAvailableToManifest("2",
-                                       Manifest::TYPE_LEGACY_PACKAGED_APP,
-                                       Manifest::INVALID_LOCATION,
-                                       Feature::UNSPECIFIED_PLATFORM).result());
-  }
-}
-
 // Tests complex feature availability across channels.
 TEST_F(SimpleFeatureTest, ComplexFeatureAvailability) {
   std::unique_ptr<ComplexFeature> complex_feature;
@@ -821,8 +765,8 @@
     feature1->channel_.reset(new Channel(Channel::UNKNOWN));
     feature1->extension_types_.push_back(Manifest::TYPE_EXTENSION);
     std::unique_ptr<SimpleFeature> feature2(new SimpleFeature());
-    // Rule: "legacy_packaged_app", channel stable.
-    feature2->channel_.reset(new Channel(Channel::STABLE));
+    // Rule: "legacy_packaged_app", channel beta.
+    feature2->channel_.reset(new Channel(Channel::BETA));
     feature2->extension_types_.push_back(Manifest::TYPE_LEGACY_PACKAGED_APP);
     std::vector<Feature*> list;
     list.push_back(feature1.release());
@@ -830,7 +774,18 @@
     complex_feature.reset(new ComplexFeature(&list));
   }
 
-  Feature* feature = static_cast<Feature*>(complex_feature.get());
+  Feature* feature = complex_feature.get();
+  EXPECT_EQ(Feature::IS_AVAILABLE,
+            feature->IsAvailableToChannel(Channel::UNKNOWN).result());
+  EXPECT_EQ(Feature::IS_AVAILABLE,
+            feature->IsAvailableToChannel(Channel::CANARY).result());
+  EXPECT_EQ(Feature::IS_AVAILABLE,
+            feature->IsAvailableToChannel(Channel::DEV).result());
+  EXPECT_EQ(Feature::IS_AVAILABLE,
+            feature->IsAvailableToChannel(Channel::BETA).result());
+  EXPECT_EQ(Feature::UNSUPPORTED_CHANNEL,
+            feature->IsAvailableToChannel(Channel::STABLE).result());
+
   {
     ScopedCurrentChannel current_channel(Channel::UNKNOWN);
     EXPECT_EQ(Feature::IS_AVAILABLE,
@@ -839,6 +794,12 @@
                                           Manifest::INVALID_LOCATION,
                                           Feature::UNSPECIFIED_PLATFORM)
                   .result());
+    EXPECT_EQ(Feature::IS_AVAILABLE,
+              feature
+                  ->IsAvailableToManifest(
+                      "1", Manifest::TYPE_LEGACY_PACKAGED_APP,
+                      Manifest::INVALID_LOCATION, Feature::UNSPECIFIED_PLATFORM)
+                  .result());
   }
   {
     ScopedCurrentChannel current_channel(Channel::BETA);
@@ -848,9 +809,21 @@
                       "2", Manifest::TYPE_LEGACY_PACKAGED_APP,
                       Manifest::INVALID_LOCATION, Feature::UNSPECIFIED_PLATFORM)
                   .result());
+    EXPECT_NE(Feature::IS_AVAILABLE,
+              feature
+                  ->IsAvailableToManifest("1", Manifest::TYPE_EXTENSION,
+                                          Manifest::INVALID_LOCATION,
+                                          Feature::UNSPECIFIED_PLATFORM)
+                  .result());
   }
   {
-    ScopedCurrentChannel current_channel(Channel::BETA);
+    ScopedCurrentChannel current_channel(Channel::STABLE);
+    EXPECT_NE(Feature::IS_AVAILABLE,
+              feature
+                  ->IsAvailableToManifest(
+                      "2", Manifest::TYPE_LEGACY_PACKAGED_APP,
+                      Manifest::INVALID_LOCATION, Feature::UNSPECIFIED_PLATFORM)
+                  .result());
     EXPECT_NE(Feature::IS_AVAILABLE,
               feature
                   ->IsAvailableToManifest("1", Manifest::TYPE_EXTENSION,
diff --git a/extensions/common/file_util.cc b/extensions/common/file_util.cc
index 2e986c430..7821e35 100644
--- a/extensions/common/file_util.cc
+++ b/extensions/common/file_util.cc
@@ -38,7 +38,7 @@
 #include "extensions/common/manifest_handler.h"
 #include "extensions/common/manifest_handlers/default_locale_handler.h"
 #include "extensions/common/manifest_handlers/icons_handler.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "net/base/escape.h"
 #include "net/base/filename_util.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/extensions/common/file_util_unittest.cc b/extensions/common/file_util_unittest.cc
index 5be68fa..4aea12c 100644
--- a/extensions/common/file_util_unittest.cc
+++ b/extensions/common/file_util_unittest.cc
@@ -21,7 +21,7 @@
 #include "extensions/common/extension_paths.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/extensions/common/manifest_handlers/action_handlers_handler.cc b/extensions/common/manifest_handlers/action_handlers_handler.cc
index 967db22..2d30318 100644
--- a/extensions/common/manifest_handlers/action_handlers_handler.cc
+++ b/extensions/common/manifest_handlers/action_handlers_handler.cc
@@ -59,7 +59,7 @@
     info->action_handlers.insert(action_type);
   }
 
-  extension->SetManifestData(keys::kActionHandlers, info.release());
+  extension->SetManifestData(keys::kActionHandlers, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/app_isolation_info.cc b/extensions/common/manifest_handlers/app_isolation_info.cc
index 3242ca2..94be889 100644
--- a/extensions/common/manifest_handlers/app_isolation_info.cc
+++ b/extensions/common/manifest_handlers/app_isolation_info.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
@@ -44,7 +45,8 @@
 bool AppIsolationHandler::Parse(Extension* extension, base::string16* error) {
   // Platform apps always get isolated storage.
   if (extension->is_platform_app()) {
-    extension->SetManifestData(keys::kIsolation, new AppIsolationInfo(true));
+    extension->SetManifestData(keys::kIsolation,
+                               base::MakeUnique<AppIsolationInfo>(true));
     return true;
   }
 
@@ -84,7 +86,8 @@
   }
 
   if (has_isolated_storage)
-    extension->SetManifestData(keys::kIsolation, new AppIsolationInfo(true));
+    extension->SetManifestData(keys::kIsolation,
+                               base::MakeUnique<AppIsolationInfo>(true));
 
   return true;
 }
diff --git a/extensions/common/manifest_handlers/background_info.cc b/extensions/common/manifest_handlers/background_info.cc
index 3cd0bc4..0466dcd 100644
--- a/extensions/common/manifest_handlers/background_info.cc
+++ b/extensions/common/manifest_handlers/background_info.cc
@@ -21,7 +21,7 @@
 #include "extensions/common/manifest_handlers/permissions_parser.h"
 #include "extensions/common/permissions/api_permission_set.h"
 #include "extensions/common/switches.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 using base::ASCIIToUTF16;
@@ -267,7 +267,7 @@
     return false;
   }
 
-  extension->SetManifestData(kBackground, info.release());
+  extension->SetManifestData(kBackground, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/content_capabilities_handler.cc b/extensions/common/manifest_handlers/content_capabilities_handler.cc
index d304017..c994dea3 100644
--- a/extensions/common/manifest_handlers/content_capabilities_handler.cc
+++ b/extensions/common/manifest_handlers/content_capabilities_handler.cc
@@ -106,7 +106,7 @@
     }
   }
 
-  extension->SetManifestData(keys::kContentCapabilities, info.release());
+  extension->SetManifestData(keys::kContentCapabilities, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc
index 6fe6294..48c655b 100644
--- a/extensions/common/manifest_handlers/csp_info.cc
+++ b/extensions/common/manifest_handlers/csp_info.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -116,8 +117,9 @@
                SanitizeContentSecurityPolicy(content_security_policy,
                                              GetValidatorOptions(extension),
                                              NULL));
-      extension->SetManifestData(keys::kContentSecurityPolicy,
-                                 new CSPInfo(content_security_policy));
+      extension->SetManifestData(
+          keys::kContentSecurityPolicy,
+          base::MakeUnique<CSPInfo>(content_security_policy));
     }
     return true;
   }
@@ -141,8 +143,9 @@
     extension->AddInstallWarnings(warnings);
   }
 
-  extension->SetManifestData(keys::kContentSecurityPolicy,
-                             new CSPInfo(content_security_policy));
+  extension->SetManifestData(
+      keys::kContentSecurityPolicy,
+      base::MakeUnique<CSPInfo>(content_security_policy));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/default_locale_handler.cc b/extensions/common/manifest_handlers/default_locale_handler.cc
index 47fde82..2fa21c29 100644
--- a/extensions/common/manifest_handlers/default_locale_handler.cc
+++ b/extensions/common/manifest_handlers/default_locale_handler.cc
@@ -16,7 +16,7 @@
 #include "extensions/common/extension_l10n_util.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
@@ -45,7 +45,7 @@
     *error = base::ASCIIToUTF16(manifest_errors::kInvalidDefaultLocale);
     return false;
   }
-  extension->SetManifestData(keys::kDefaultLocale, info.release());
+  extension->SetManifestData(keys::kDefaultLocale, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/externally_connectable.cc b/extensions/common/manifest_handlers/externally_connectable.cc
index e5942514..871ea0c 100644
--- a/extensions/common/manifest_handlers/externally_connectable.cc
+++ b/extensions/common/manifest_handlers/externally_connectable.cc
@@ -82,7 +82,7 @@
                                         APIPermission::kWebConnectable);
   }
   extension->AddInstallWarnings(install_warnings);
-  extension->SetManifestData(keys::kExternallyConnectable, info.release());
+  extension->SetManifestData(keys::kExternallyConnectable, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/file_handler_info.cc b/extensions/common/manifest_handlers/file_handler_info.cc
index 8ee9960..2e802553 100644
--- a/extensions/common/manifest_handlers/file_handler_info.cc
+++ b/extensions/common/manifest_handlers/file_handler_info.cc
@@ -205,7 +205,7 @@
     return false;
   }
 
-  extension->SetManifestData(keys::kFileHandlers, info.release());
+  extension->SetManifestData(keys::kFileHandlers, std::move(info));
   extension->AddInstallWarnings(install_warnings);
   return true;
 }
diff --git a/extensions/common/manifest_handlers/icons_handler.cc b/extensions/common/manifest_handlers/icons_handler.cc
index dd599e68..90cdbddb 100644
--- a/extensions/common/manifest_handlers/icons_handler.cc
+++ b/extensions/common/manifest_handlers/icons_handler.cc
@@ -16,7 +16,7 @@
 #include "extensions/common/file_util.h"
 #include "extensions/common/manifest_constants.h"
 #include "extensions/common/manifest_handler_helpers.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace extensions {
@@ -69,7 +69,7 @@
     return false;
   }
 
-  extension->SetManifestData(keys::kIcons, icons_info.release());
+  extension->SetManifestData(keys::kIcons, std::move(icons_info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/incognito_info.cc b/extensions/common/manifest_handlers/incognito_info.cc
index 0bae1df..74af1f0 100644
--- a/extensions/common/manifest_handlers/incognito_info.cc
+++ b/extensions/common/manifest_handlers/incognito_info.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "extensions/common/extension.h"
@@ -48,7 +49,8 @@
           ? IncognitoInfo::Mode::SPLIT
           : IncognitoInfo::Mode::SPANNING;
   if (!extension->manifest()->HasKey(keys::kIncognito)) {
-    extension->SetManifestData(keys::kIncognito, new IncognitoInfo(mode));
+    extension->SetManifestData(keys::kIncognito,
+                               base::MakeUnique<IncognitoInfo>(mode));
     return true;
   }
 
@@ -69,7 +71,8 @@
     return false;
   }
 
-  extension->SetManifestData(keys::kIncognito, new IncognitoInfo(mode));
+  extension->SetManifestData(keys::kIncognito,
+                             base::MakeUnique<IncognitoInfo>(mode));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/kiosk_mode_info.cc b/extensions/common/manifest_handlers/kiosk_mode_info.cc
index b9baf4bda..b9947e28c 100644
--- a/extensions/common/manifest_handlers/kiosk_mode_info.cc
+++ b/extensions/common/manifest_handlers/kiosk_mode_info.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -149,8 +150,8 @@
 
   extension->SetManifestData(
       keys::kKioskMode,
-      new KioskModeInfo(kiosk_status, ids, required_platform_version,
-                        always_update));
+      base::MakeUnique<KioskModeInfo>(
+          kiosk_status, ids, required_platform_version, always_update));
 
   return true;
 }
diff --git a/extensions/common/manifest_handlers/launcher_page_info.cc b/extensions/common/manifest_handlers/launcher_page_info.cc
index d782145..9c6450d 100644
--- a/extensions/common/manifest_handlers/launcher_page_info.cc
+++ b/extensions/common/manifest_handlers/launcher_page_info.cc
@@ -8,7 +8,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "extensions/common/manifest.h"
 #include "extensions/common/manifest_constants.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
@@ -50,7 +50,7 @@
   launcher_page_info->page = launcher_page_page;
 
   extension->SetManifestData(manifest_keys::kLauncherPage,
-                             launcher_page_info.release());
+                             std::move(launcher_page_info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/mime_types_handler.cc b/extensions/common/manifest_handlers/mime_types_handler.cc
index 364305a..365d71c 100644
--- a/extensions/common/manifest_handlers/mime_types_handler.cc
+++ b/extensions/common/manifest_handlers/mime_types_handler.cc
@@ -120,7 +120,7 @@
     info->handler_.set_handler_url(mime_types_handler);
   }
 
-  extension->SetManifestData(keys::kMimeTypesHandler, info.release());
+  extension->SetManifestData(keys::kMimeTypesHandler, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/nacl_modules_handler.cc b/extensions/common/manifest_handlers/nacl_modules_handler.cc
index 148caca6..74244f02 100644
--- a/extensions/common/manifest_handlers/nacl_modules_handler.cc
+++ b/extensions/common/manifest_handlers/nacl_modules_handler.cc
@@ -81,7 +81,7 @@
     nacl_module_data->nacl_modules_.back().mime_type = mime_type;
   }
 
-  extension->SetManifestData(keys::kNaClModules, nacl_module_data.release());
+  extension->SetManifestData(keys::kNaClModules, std::move(nacl_module_data));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/oauth2_manifest_handler.cc b/extensions/common/manifest_handlers/oauth2_manifest_handler.cc
index 7d381b5..2e99bf2 100644
--- a/extensions/common/manifest_handlers/oauth2_manifest_handler.cc
+++ b/extensions/common/manifest_handlers/oauth2_manifest_handler.cc
@@ -90,7 +90,7 @@
     info->scopes.push_back(scope);
   }
 
-  extension->SetManifestData(keys::kOAuth2, info.release());
+  extension->SetManifestData(keys::kOAuth2, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/offline_enabled_info.cc b/extensions/common/manifest_handlers/offline_enabled_info.cc
index fd73099..684048f 100644
--- a/extensions/common/manifest_handlers/offline_enabled_info.cc
+++ b/extensions/common/manifest_handlers/offline_enabled_info.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -48,8 +49,9 @@
 
     const bool has_webview_permission =
         PermissionsParser::HasAPIPermission(extension, APIPermission::kWebView);
-    extension->SetManifestData(keys::kOfflineEnabled,
-                               new OfflineEnabledInfo(!has_webview_permission));
+    extension->SetManifestData(
+        keys::kOfflineEnabled,
+        base::MakeUnique<OfflineEnabledInfo>(!has_webview_permission));
     return true;
   }
 
@@ -61,8 +63,9 @@
     return false;
   }
 
-  extension->SetManifestData(keys::kOfflineEnabled,
-                             new OfflineEnabledInfo(offline_enabled));
+  extension->SetManifestData(
+      keys::kOfflineEnabled,
+      base::MakeUnique<OfflineEnabledInfo>(offline_enabled));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/options_page_info.cc b/extensions/common/manifest_handlers/options_page_info.cc
index 7e1d1df..b81159f 100644
--- a/extensions/common/manifest_handlers/options_page_info.cc
+++ b/extensions/common/manifest_handlers/options_page_info.cc
@@ -198,7 +198,7 @@
     return false;
 
   extension->AddInstallWarnings(install_warnings);
-  extension->SetManifestData(keys::kOptionsUI, info.release());
+  extension->SetManifestData(keys::kOptionsUI, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/permissions_parser.cc b/extensions/common/manifest_handlers/permissions_parser.cc
index 14a2e19..af8ba0c 100644
--- a/extensions/common/manifest_handlers/permissions_parser.cc
+++ b/extensions/common/manifest_handlers/permissions_parser.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/command_line.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
@@ -275,7 +276,7 @@
                         initial_required_permissions_->scriptable_hosts));
   extension->SetManifestData(
       keys::kPermissions,
-      new ManifestPermissions(std::move(required_permissions)));
+      base::MakeUnique<ManifestPermissions>(std::move(required_permissions)));
 
   std::unique_ptr<const PermissionSet> optional_permissions(new PermissionSet(
       initial_optional_permissions_->api_permissions,
@@ -283,7 +284,7 @@
       initial_optional_permissions_->host_permissions, URLPatternSet()));
   extension->SetManifestData(
       keys::kOptionalPermissions,
-      new ManifestPermissions(std::move(optional_permissions)));
+      base::MakeUnique<ManifestPermissions>(std::move(optional_permissions)));
 }
 
 // static
diff --git a/extensions/common/manifest_handlers/requirements_info.cc b/extensions/common/manifest_handlers/requirements_info.cc
index c89d974..d73af89 100644
--- a/extensions/common/manifest_handlers/requirements_info.cc
+++ b/extensions/common/manifest_handlers/requirements_info.cc
@@ -66,7 +66,7 @@
       new RequirementsInfo(extension->manifest()));
 
   if (!extension->manifest()->HasKey(keys::kRequirements)) {
-    extension->SetManifestData(keys::kRequirements, requirements.release());
+    extension->SetManifestData(keys::kRequirements, std::move(requirements));
     return true;
   }
 
@@ -153,7 +153,7 @@
     }
   }
 
-  extension->SetManifestData(keys::kRequirements, requirements.release());
+  extension->SetManifestData(keys::kRequirements, std::move(requirements));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/sandboxed_page_info.cc b/extensions/common/manifest_handlers/sandboxed_page_info.cc
index c8ad586..11d97dc7 100644
--- a/extensions/common/manifest_handlers/sandboxed_page_info.cc
+++ b/extensions/common/manifest_handlers/sandboxed_page_info.cc
@@ -120,7 +120,7 @@
   CHECK(csp_validator::ContentSecurityPolicyIsSandboxed(
       sandboxed_info->content_security_policy, extension->GetType()));
 
-  extension->SetManifestData(keys::kSandboxedPages, sandboxed_info.release());
+  extension->SetManifestData(keys::kSandboxedPages, std::move(sandboxed_info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/shared_module_info.cc b/extensions/common/manifest_handlers/shared_module_info.cc
index b8f6229..90280e85 100644
--- a/extensions/common/manifest_handlers/shared_module_info.cc
+++ b/extensions/common/manifest_handlers/shared_module_info.cc
@@ -210,7 +210,7 @@
   std::unique_ptr<SharedModuleInfo> info(new SharedModuleInfo);
   if (!info->Parse(extension, error))
     return false;
-  extension->SetManifestData(kSharedModule, info.release());
+  extension->SetManifestData(kSharedModule, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/web_accessible_resources_info.cc b/extensions/common/manifest_handlers/web_accessible_resources_info.cc
index 1a9dc2aa..2d4b393 100644
--- a/extensions/common/manifest_handlers/web_accessible_resources_info.cc
+++ b/extensions/common/manifest_handlers/web_accessible_resources_info.cc
@@ -92,7 +92,7 @@
     pattern.SetPath(pattern.path() + relative_path);
     info->web_accessible_resources_.AddPattern(pattern);
   }
-  extension->SetManifestData(keys::kWebAccessibleResources, info.release());
+  extension->SetManifestData(keys::kWebAccessibleResources, std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_handlers/webview_info.cc b/extensions/common/manifest_handlers/webview_info.cc
index 989df76..57a5aa01 100644
--- a/extensions/common/manifest_handlers/webview_info.cc
+++ b/extensions/common/manifest_handlers/webview_info.cc
@@ -166,7 +166,8 @@
     info->AddPartitionItem(std::move(partition_item));
   }
 
-  extension->SetManifestData(keys::kWebviewAccessibleResources, info.release());
+  extension->SetManifestData(keys::kWebviewAccessibleResources,
+                             std::move(info));
   return true;
 }
 
diff --git a/extensions/common/manifest_url_handlers.cc b/extensions/common/manifest_url_handlers.cc
index c3bcaba..f58f1fb 100644
--- a/extensions/common/manifest_url_handlers.cc
+++ b/extensions/common/manifest_url_handlers.cc
@@ -103,7 +103,7 @@
         errors::kInvalidHomepageURL, homepage_url_str);
     return false;
   }
-  extension->SetManifestData(keys::kHomepageURL, manifest_url.release());
+  extension->SetManifestData(keys::kHomepageURL, std::move(manifest_url));
   return true;
 }
 
@@ -135,7 +135,7 @@
     return false;
   }
 
-  extension->SetManifestData(keys::kUpdateURL, manifest_url.release());
+  extension->SetManifestData(keys::kUpdateURL, std::move(manifest_url));
   return true;
 }
 
@@ -167,7 +167,7 @@
     *error = base::ASCIIToUTF16(errors::kInvalidAboutPage);
     return false;
   }
-  extension->SetManifestData(keys::kAboutPage, manifest_url.release());
+  extension->SetManifestData(keys::kAboutPage, std::move(manifest_url));
   return true;
 }
 
diff --git a/extensions/common/permissions/extensions_api_permissions.cc b/extensions/common/permissions/extensions_api_permissions.cc
index a0f7fea..f8cd038 100644
--- a/extensions/common/permissions/extensions_api_permissions.cc
+++ b/extensions/common/permissions/extensions_api_permissions.cc
@@ -13,7 +13,7 @@
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/socket_permission.h"
 #include "extensions/common/permissions/usb_device_permission.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 
 namespace extensions {
 
diff --git a/extensions/common/permissions/media_galleries_permission.cc b/extensions/common/permissions/media_galleries_permission.cc
index d3b245f..10fb24c 100644
--- a/extensions/common/permissions/media_galleries_permission.cc
+++ b/extensions/common/permissions/media_galleries_permission.cc
@@ -12,7 +12,7 @@
 #include "base/logging.h"
 #include "base/strings/utf_string_conversions.h"
 #include "extensions/common/permissions/permissions_info.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
diff --git a/extensions/common/permissions/settings_override_permission.cc b/extensions/common/permissions/settings_override_permission.cc
index afa14db..df5b073 100644
--- a/extensions/common/permissions/settings_override_permission.cc
+++ b/extensions/common/permissions/settings_override_permission.cc
@@ -9,7 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "extensions/common/permissions/api_permission_set.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
diff --git a/extensions/common/permissions/socket_permission.cc b/extensions/common/permissions/socket_permission.cc
index cee281b..33c3b29 100644
--- a/extensions/common/permissions/socket_permission.cc
+++ b/extensions/common/permissions/socket_permission.cc
@@ -12,7 +12,7 @@
 #include "extensions/common/api/sockets/sockets_manifest_permission.h"
 #include "extensions/common/permissions/permissions_info.h"
 #include "extensions/common/permissions/set_disjunction_permission.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
diff --git a/extensions/common/permissions/usb_device_permission.cc b/extensions/common/permissions/usb_device_permission.cc
index 4e2f2d5..d6238ca13 100644
--- a/extensions/common/permissions/usb_device_permission.cc
+++ b/extensions/common/permissions/usb_device_permission.cc
@@ -22,7 +22,7 @@
 #include "extensions/common/features/feature.h"
 #include "extensions/common/features/feature_provider.h"
 #include "extensions/common/permissions/permissions_info.h"
-#include "grit/extensions_strings.h"
+#include "extensions/strings/grit/extensions_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
 namespace extensions {
diff --git a/extensions/renderer/native_extension_bindings_system_unittest.cc b/extensions/renderer/native_extension_bindings_system_unittest.cc
index a7708e6..a192c38 100644
--- a/extensions/renderer/native_extension_bindings_system_unittest.cc
+++ b/extensions/renderer/native_extension_bindings_system_unittest.cc
@@ -99,7 +99,7 @@
   }
 
   void TearDown() override {
-    for (const auto& context : raw_script_contexts_)
+    for (auto* context : raw_script_contexts_)
       script_context_set_->Remove(context);
     base::RunLoop().RunUntilIdle();
     script_context_set_.reset();
diff --git a/extensions/strings/BUILD.gn b/extensions/strings/BUILD.gn
index b32b998..23d0c2a2 100644
--- a/extensions/strings/BUILD.gn
+++ b/extensions/strings/BUILD.gn
@@ -9,6 +9,7 @@
 
 grit("strings") {
   source = "extensions_strings.grd"
+  use_qualified_include = true
   outputs = [
     "grit/extensions_strings.h",
     "extensions_strings_am.pak",
diff --git a/extensions/test/data/api_test/printer_provider/OWNERS b/extensions/test/data/api_test/printer_provider/OWNERS
index 0fa42c6a4..d038a71 100644
--- a/extensions/test/data/api_test/printer_provider/OWNERS
+++ b/extensions/test/data/api_test/printer_provider/OWNERS
@@ -1,2 +1,4 @@
 tbarzic@chromium.org
 vitalybuka@chromium.org
+
+# COMPONENT: Internals>Printing
diff --git a/gin/v8_platform.cc b/gin/v8_platform.cc
index 4fe7c7c..276dd77c 100644
--- a/gin/v8_platform.cc
+++ b/gin/v8_platform.cc
@@ -204,14 +204,14 @@
 
   void OnTraceLogEnabled() final {
     base::AutoLock lock(mutex_);
-    for (auto o : observers_) {
+    for (auto* o : observers_) {
       o->OnTraceEnabled();
     }
   }
 
   void OnTraceLogDisabled() final {
     base::AutoLock lock(mutex_);
-    for (auto o : observers_) {
+    for (auto* o : observers_) {
       o->OnTraceDisabled();
     }
   }
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.cc b/gpu/ipc/client/command_buffer_proxy_impl.cc
index 033507e..233df39 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.cc
+++ b/gpu/ipc/client/command_buffer_proxy_impl.cc
@@ -335,6 +335,15 @@
   update_vsync_parameters_completion_callback_ = callback;
 }
 
+void CommandBufferProxyImpl::SetNeedsVSync(bool needs_vsync) {
+  CheckLock();
+  base::AutoLock lock(last_state_lock_);
+  if (last_state_.error != gpu::error::kNoError)
+    return;
+
+  Send(new GpuCommandBufferMsg_SetNeedsVSync(route_id_, needs_vsync));
+}
+
 gpu::CommandBuffer::State CommandBufferProxyImpl::WaitForTokenInRange(
     int32_t start,
     int32_t end) {
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 5a7199b4..c35b7009 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -152,6 +152,8 @@
   void SetUpdateVSyncParametersCallback(
       const UpdateVSyncParametersCallback& callback);
 
+  void SetNeedsVSync(bool needs_vsync);
+
   int32_t route_id() const { return route_id_; }
 
   const scoped_refptr<GpuChannelHost>& channel() const { return channel_; }
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index 1375acb..1cbea32 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -600,23 +600,38 @@
   // only a single context. See crbug.com/510243 for details.
   use_virtualized_gl_context_ |= channel_->mailbox_manager()->UsesSync();
 
-  gl::GLSurfaceFormat surface_format = gl::GLSurfaceFormat();
   bool offscreen = (surface_handle_ == kNullSurfaceHandle);
   gl::GLSurface* default_surface = manager->GetDefaultOffscreenSurface();
   if (!default_surface) {
     DLOG(ERROR) << "Failed to create default offscreen surface.";
     return false;
   }
+  // On low-spec Android devices, the default offscreen surface is
+  // RGB565, but WebGL rendering contexts still ask for RGBA8888 mode.
+  // That combination works for offscreen rendering, we can still use
+  // a virtualized context with the RGB565 backing surface since we're
+  // not drawing to that. Explicitly set that as the desired surface
+  // format to ensure it's treated as compatible where applicable.
+  gl::GLSurfaceFormat surface_format =
+      offscreen ? default_surface->GetFormat() : gl::GLSurfaceFormat();
 #if defined(OS_ANDROID)
   if (init_params.attribs.red_size <= 5 &&
       init_params.attribs.green_size <= 6 &&
       init_params.attribs.blue_size <= 5 &&
-      init_params.attribs.alpha_size == 0)
+      init_params.attribs.alpha_size == 0) {
+    // We hit this code path when creating the onscreen render context
+    // used for compositing on low-end Android devices.
+    //
+    // TODO(klausw): explicitly copy rgba sizes? Currently the formats
+    // supported are only RGB565 and default (RGBA8888).
     surface_format.SetRGB565();
-  // TODO(klausw): explicitly copy rgba sizes?
+    DVLOG(1) << __FUNCTION__ << ": Choosing RGB565 mode.";
+  }
 
   // We can only use virtualized contexts for onscreen command buffers if their
   // config is compatible with the offscreen ones - otherwise MakeCurrent fails.
+  // Example use case is a client requesting an onscreen RGBA8888 buffer for
+  // fullscreen video on a low-spec device with RGB565 default format.
   if (!surface_format.IsCompatible(default_surface->GetFormat()) && !offscreen)
     use_virtualized_gl_context_ = false;
 #endif
diff --git a/gpu/ipc/service/image_transport_surface_win.cc b/gpu/ipc/service/image_transport_surface_win.cc
index 7d484e90..5fcaf7f59 100644
--- a/gpu/ipc/service/image_transport_surface_win.cc
+++ b/gpu/ipc/service/image_transport_surface_win.cc
@@ -6,19 +6,32 @@
 
 #include <memory>
 
+#include "base/win/windows_version.h"
 #include "gpu/ipc/service/child_window_surface_win.h"
 #include "gpu/ipc/service/direct_composition_surface_win.h"
+#include "gpu/ipc/service/gpu_vsync_provider_win.h"
 #include "gpu/ipc/service/pass_through_image_transport_surface.h"
 #include "gpu/ipc/service/switches.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_switches.h"
 #include "ui/gl/init/gl_factory.h"
 #include "ui/gl/vsync_provider_win.h"
 
 namespace gpu {
 
+namespace {
+bool IsGpuVSyncSignalSupported() {
+  // TODO(stanisc): http://crbug.com/467617 Limit to Windows 8+ for now because
+  // of locking issue caused by waiting for VSync on Win7.
+  return base::win::GetVersion() >= base::win::VERSION_WIN8 &&
+         base::FeatureList::IsEnabled(features::kD3DVsync);
+}
+
+}  // namespace
+
 // static
 scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface(
     base::WeakPtr<ImageTransportSurfaceDelegate> delegate,
@@ -29,8 +42,13 @@
   scoped_refptr<gl::GLSurface> surface;
   if (gl::GetGLImplementation() == gl::kGLImplementationEGLGLES2 &&
       gl::GLSurfaceEGL::IsDirectCompositionSupported()) {
-    std::unique_ptr<gfx::VSyncProvider> vsync_provider(
-        new gl::VSyncProviderWin(surface_handle));
+    std::unique_ptr<gfx::VSyncProvider> vsync_provider;
+
+    if (IsGpuVSyncSignalSupported())
+      vsync_provider.reset(new GpuVSyncProviderWin(delegate, surface_handle));
+    else
+      vsync_provider.reset(new gl::VSyncProviderWin(surface_handle));
+
     if (base::FeatureList::IsEnabled(switches::kDirectCompositionOverlays)) {
       scoped_refptr<DirectCompositionSurfaceWin> egl_surface =
           make_scoped_refptr(
diff --git a/headless/OWNERS b/headless/OWNERS
index d11af97..bfb2bee 100644
--- a/headless/OWNERS
+++ b/headless/OWNERS
@@ -1,4 +1,5 @@
 skyostil@chromium.org
 alexclarke@chromium.org
 altimin@chromium.org
-eseckler@chromium.org
+
+# TEAM: headless-dev@chromium.org
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc
index a6db422..e993fc1 100644
--- a/headless/lib/browser/headless_content_browser_client.cc
+++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -119,7 +119,7 @@
 void HeadlessContentBrowserClient::OverrideWebkitPrefs(
     content::RenderViewHost* render_view_host,
     content::WebPreferences* prefs) {
-  auto browser_context = HeadlessBrowserContextImpl::From(
+  auto* browser_context = HeadlessBrowserContextImpl::From(
       render_view_host->GetProcess()->GetBrowserContext());
   const base::Callback<void(headless::WebPreferences*)>& callback =
       browser_context->options()->override_web_preferences_callback();
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg
index f53bd79..7cfb95a 100644
--- a/infra/config/cq.cfg
+++ b/infra/config/cq.cfg
@@ -4,9 +4,11 @@
 version: 1
 cq_name: "chromium"
 cq_status_url: "https://chromium-cq-status.appspot.com"
+git_repo_url: "https://chromium.googlesource.com/chromium/src"
 commit_burst_delay: 60
 max_commit_burst: 2
 
+gerrit {}
 rietveld {
   url: "https://codereview.chromium.org"
 }
@@ -17,6 +19,11 @@
     dry_run_access_list: "project-chromium-tryjob-access"
   }
 
+  gerrit_cq_ability {
+    committer_list: "project-chromium-committers"
+    dry_run_access_list: "project-chromium-tryjob-access"
+  }
+
   tree_status {
     tree_status_url: "https://chromium-status.appspot.com"
   }
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 88bdcef..aef2da7 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -951,24 +951,12 @@
       <message name="IDS_IOS_PAYMENT_REQUEST_PAYMENT_ITEMS_TOTAL_FORMAT" desc="The format specifier of the Total label in the payment items in a payment request [iOS only].">
         <ph name="FORMATTED_CURRENCY_CODE">$1<ex>USD</ex></ph> <ph name="FORMATTED_TOTAL_AMOUNT">$2<ex>$ 12.34</ex></ph>
       </message>
-      <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_HEADER" desc="Label of the header of the section which displays the currently selected shipping address and the available shipping options for satisfying a payment request [iOS only].">
-        Shipping
-      </message>
       <message name="IDS_IOS_PAYMENT_REQUEST_ADD_SHIPPING_ADDRESS_BUTTON" desc="Label of the button to add a shipping address [iOS only].">
         Add
       </message>
-      <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE" desc="Title of the view that allows the user to select the shipping address for satisfying a payment request [iOS only].">
-        Shipping Address
-      </message>
-      <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_MESSAGE" desc="Message instructing the user to select a shipping address for satisfying a payment request [iOS only].">
-        Select a shipping address to check shipping methods and requirements.
-      </message>
       <message name="IDS_IOS_PAYMENT_REQUEST_CHECKING_LABEL" desc="Label showing that the new shipping address or the shipping option is being verified. [iOS only]">
         Checking
       </message>
-      <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE" desc="Title of the view that allows the user to select the shipping option for satisfying a payment request [iOS only].">
-        Shipping Method
-      </message>
       <message name="IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_ADD_BUTTON" desc="Label of the button to add a new shipping address [iOS only].">
         Add Address...
       </message>
diff --git a/ios/chrome/browser/payments/BUILD.gn b/ios/chrome/browser/payments/BUILD.gn
index 9109cc2..9fd2b10 100644
--- a/ios/chrome/browser/payments/BUILD.gn
+++ b/ios/chrome/browser/payments/BUILD.gn
@@ -93,6 +93,7 @@
     "//components/autofill/core/browser",
     "//components/autofill/core/browser:test_support",
     "//components/payments:payment_validation",
+    "//components/strings",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/payments/cells",
diff --git a/ios/chrome/browser/payments/payment_request.h b/ios/chrome/browser/payments/payment_request.h
index 966fb2a..5b4cea2 100644
--- a/ios/chrome/browser/payments/payment_request.h
+++ b/ios/chrome/browser/payments/payment_request.h
@@ -39,6 +39,11 @@
     return web_payment_request_->details;
   }
 
+  // Returns the payment options from |web_payment_request_|.
+  const web::PaymentOptions& payment_options() const {
+    return web_payment_request_->options;
+  }
+
   // Updates the payment details of the |web_payment_request_|. It also updates
   // the cached references to the shipping options in |web_payment_request_| as
   // well as the reference to the selected shipping option.
diff --git a/ios/chrome/browser/payments/payment_request_coordinator.mm b/ios/chrome/browser/payments/payment_request_coordinator.mm
index 29e293a..6205c4b 100644
--- a/ios/chrome/browser/payments/payment_request_coordinator.mm
+++ b/ios/chrome/browser/payments/payment_request_coordinator.mm
@@ -235,7 +235,7 @@
       (_paymentRequest->payment_details().total != paymentDetails.total);
   _paymentRequest->set_payment_details(paymentDetails);
 
-  if (!paymentDetails.error.empty()) {
+  if (_paymentRequest->shipping_options().empty()) {
     // Display error in the shipping address/option selection view.
     if (_shippingAddressSelectionCoordinator) {
       _paymentRequest->set_selected_shipping_profile(nil);
diff --git a/ios/chrome/browser/payments/payment_request_util.h b/ios/chrome/browser/payments/payment_request_util.h
index 59ae03f9..008fb50 100644
--- a/ios/chrome/browser/payments/payment_request_util.h
+++ b/ios/chrome/browser/payments/payment_request_util.h
@@ -13,6 +13,8 @@
 class AutofillProfile;
 }  // namespace autofill
 
+class PaymentRequest;
+
 namespace payment_request_util {
 
 // Helper function to get the name label from an autofill profile.
@@ -30,6 +32,31 @@
 web::PaymentAddress PaymentAddressFromAutofillProfile(
     autofill::AutofillProfile* profile);
 
+// Returns the title for the shipping section of the payment summary view given
+// the shipping type specified in |payment_request|.
+NSString* GetShippingSectionTitle(PaymentRequest* payment_request);
+
+// Returns the title for the shipping address selection view given the shipping
+// type specified in |payment_request|.
+NSString* GetShippingAddressSelectorTitle(PaymentRequest* payment_request);
+
+// Returns the informational message to be displayed in the shipping address
+// selection view given the shipping type specified in |payment_request|.
+NSString* GetShippingAddressSelectorInfoMessage(PaymentRequest* paymentRequest);
+
+// Returns the error message to be displayed in the shipping address selection
+// view given the shipping type specified in |payment_request|.
+NSString* GetShippingAddressSelectorErrorMessage(
+    PaymentRequest* paymentRequest);
+
+// Returns the title for the shipping option selection view given the shipping
+// type specified in |payment_request|.
+NSString* GetShippingOptionSelectorTitle(PaymentRequest* payment_request);
+
+// Returns the error message to be displayed in the shipping option selection
+// view given the shipping type specified in |payment_request|.
+NSString* GetShippingOptionSelectorErrorMessage(PaymentRequest* paymentRequest);
+
 }  // namespace payment_request_util
 
 #endif  // IOS_CHROME_BROWSER_PAYMENTS_PAYMENT_REQUEST_UTIL_H_
diff --git a/ios/chrome/browser/payments/payment_request_util.mm b/ios/chrome/browser/payments/payment_request_util.mm
index cdab2816..5bdf315 100644
--- a/ios/chrome/browser/payments/payment_request_util.mm
+++ b/ios/chrome/browser/payments/payment_request_util.mm
@@ -8,7 +8,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/payments/payment_request.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace payment_request_util {
 
@@ -68,4 +71,100 @@
   return address;
 }
 
+NSString* GetShippingSectionTitle(PaymentRequest* payment_request) {
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(IDS_PAYMENTS_SHIPPING_SUMMARY_LABEL);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(IDS_PAYMENTS_DELIVERY_SUMMARY_LABEL);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(IDS_PAYMENTS_PICKUP_SUMMARY_LABEL);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
+NSString* GetShippingAddressSelectorTitle(PaymentRequest* payment_request) {
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(IDS_PAYMENTS_DELIVERY_ADDRESS_LABEL);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(IDS_PAYMENTS_PICKUP_ADDRESS_LABEL);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
+NSString* GetShippingAddressSelectorInfoMessage(
+    PaymentRequest* payment_request) {
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(
+          IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(
+          IDS_PAYMENTS_SELECT_DELIVERY_ADDRESS_FOR_DELIVERY_METHODS);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(
+          IDS_PAYMENTS_SELECT_PICKUP_ADDRESS_FOR_PICKUP_METHODS);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
+NSString* GetShippingAddressSelectorErrorMessage(
+    PaymentRequest* payment_request) {
+  if (!payment_request->payment_details().error.empty())
+    return base::SysUTF16ToNSString(payment_request->payment_details().error);
+
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_DELIVERY_ADDRESS);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_PICKUP_ADDRESS);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
+NSString* GetShippingOptionSelectorTitle(PaymentRequest* payment_request) {
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(IDS_PAYMENTS_SHIPPING_OPTION_LABEL);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(IDS_PAYMENTS_DELIVERY_OPTION_LABEL);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(IDS_PAYMENTS_PICKUP_OPTION_LABEL);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
+NSString* GetShippingOptionSelectorErrorMessage(
+    PaymentRequest* payment_request) {
+  if (!payment_request->payment_details().error.empty())
+    return base::SysUTF16ToNSString(payment_request->payment_details().error);
+
+  switch (payment_request->payment_options().shipping_type) {
+    case web::PaymentShippingType::SHIPPING:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_SHIPPING_OPTION);
+    case web::PaymentShippingType::DELIVERY:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_DELIVERY_OPTION);
+    case web::PaymentShippingType::PICKUP:
+      return l10n_util::GetNSString(IDS_PAYMENTS_UNSUPPORTED_PICKUP_OPTION);
+    default:
+      NOTREACHED();
+      return @"";
+  }
+}
+
 }  // namespace payment_request_util
diff --git a/ios/chrome/browser/payments/payment_request_view_controller.mm b/ios/chrome/browser/payments/payment_request_view_controller.mm
index 3daa2ca..8d9f78a 100644
--- a/ios/chrome/browser/payments/payment_request_view_controller.mm
+++ b/ios/chrome/browser/payments/payment_request_view_controller.mm
@@ -223,7 +223,7 @@
   CollectionViewTextItem* shippingTitle = [[[CollectionViewTextItem alloc]
       initWithType:ItemTypeShippingTitle] autorelease];
   shippingTitle.text =
-      l10n_util::GetNSString(IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_HEADER);
+      payment_request_util::GetShippingSectionTitle(_paymentRequest);
   [model setHeader:shippingTitle
       forSectionWithIdentifier:SectionIdentifierShipping];
 
@@ -242,8 +242,8 @@
         [[[CollectionViewDetailItem alloc]
             initWithType:ItemTypeAddShippingAddress] autorelease];
     shippingAddressItem = addAddressItem;
-    addAddressItem.text = l10n_util::GetNSString(
-        IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE);
+    addAddressItem.text =
+        payment_request_util::GetShippingAddressSelectorTitle(_paymentRequest);
     addAddressItem.detailText = [l10n_util::GetNSString(
         IDS_IOS_PAYMENT_REQUEST_ADD_SHIPPING_ADDRESS_BUTTON)
         uppercaseStringWithLocale:[NSLocale currentLocale]];
@@ -266,8 +266,8 @@
         [[[CollectionViewDetailItem alloc]
             initWithType:ItemTypeSelectShippingOption] autorelease];
     shippingOptionItem = selectShippingOptionItem;
-    selectShippingOptionItem.text = l10n_util::GetNSString(
-        IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
+    selectShippingOptionItem.text =
+        payment_request_util::GetShippingOptionSelectorTitle(_paymentRequest);
     selectShippingOptionItem.accessoryType =
         MDCCollectionViewCellAccessoryDisclosureIndicator;
   }
diff --git a/ios/chrome/browser/payments/resources/payment_request_manager.js b/ios/chrome/browser/payments/resources/payment_request_manager.js
index f5a136bb..d2a779c 100644
--- a/ios/chrome/browser/payments/resources/payment_request_manager.js
+++ b/ios/chrome/browser/payments/resources/payment_request_manager.js
@@ -417,22 +417,58 @@
 
   // TODO(crbug.com/602666): Perform other validation per spec.
 
+  // TODO(crbug.com/602666): Process payment methods then set parsedMethodData
+  // instead of methodData on this instance.
+  // /**
+  //  * @type {!Object<!Array<string>, ?string>}
+  //  * @private
+  //  */
+  // this.parsedMethodData = ...;
+
   /**
    * @type {!Array<!window.PaymentMethodData>}
+   * @private
    */
   this.methodData = methodData;
 
   /**
    * @type {!window.PaymentDetails}
+   * @private
    */
   this.details = details;
 
   /**
    * @type {?window.PaymentOptions}
+   * @private
    */
   this.options = opt_options || null;
 
   /**
+   * The state of this request, used to govern its lifecycle.
+   * TODO(crbug.com/602666): Implement state transitions per spec.
+   * @type {string}
+   * @private
+   */
+  this.state = 'created';
+
+  /**
+   * True if there is a pending updateWith call to update the payment request
+   * and false otherwise.
+   * TODO(crbug.com/602666): Implement changes in the value of this property per
+   * spec.
+   * @type {boolean}
+   * @private
+   */
+  this.updating = false;
+
+  /**
+   * A provided or generated ID for the this Payment Request instance.
+   * TODO(crbug.com/602666): Generate an ID if one is not provided.
+   * @type {?string}
+   */
+  this.paymentRequestID = null;
+
+  /**
    * Shipping address selected by the user.
    * @type {?window.PaymentAddress}
    */
@@ -445,12 +481,19 @@
   this.shippingOption = null;
 
   /**
-   * The state of this request, used to govern its lifecycle.
-   * TODO(crbug.com/602666): Implement state transitions per spec.
-   * @type {string}
-   * @private
+   * Set to the value of shippingType property of |opt_options| if it is a valid
+   * PaymentShippingType. Otherwise set to PaymentShippingType.SHIPPING.
+   * @type {?PaymentShippingType}
    */
-  this.state = 'created';
+  this.shippingType = null;
+
+  if (opt_options && opt_options.requestShipping) {
+    if (opt_options.shippingType != PaymentShippingType.SHIPPING &&
+        opt_options.shippingType != PaymentShippingType.DELIVERY &&
+        opt_options.shippingType != PaymentShippingType.PICKUP) {
+      this.shippingType = PaymentShippingType.SHIPPING;
+    }
+  }
 };
 
 window.PaymentRequest.prototype = {
@@ -518,10 +561,24 @@
 window.PaymentDetailsModifier;
 
 /**
+ * Contains the possible values for affecting the payment request user interface
+ * for gathering the shipping address if window.PaymentOptions.requestShipping
+ * is set to true.
+ * @enum {string}
+ */
+var PaymentShippingType = {
+  SHIPPING: 'shipping',
+  DELIVERY: 'delivery',
+  PICKUP: 'pickup'
+};
+
+/**
  * @typedef {{
+ *   requestPayerName: (boolean|undefined),
  *   requestPayerEmail: (boolean|undefined),
  *   requestPayerPhone: (boolean|undefined),
- *   requestShipping: (boolean|undefined)
+ *   requestShipping: (boolean|undefined),
+ *   shippingType: (!PaymentShippingType|undefined)
  * }}
  */
 window.PaymentOptions;
diff --git a/ios/chrome/browser/payments/shipping_address_selection_coordinator.mm b/ios/chrome/browser/payments/shipping_address_selection_coordinator.mm
index b7f2cf5..e3dfcb5 100644
--- a/ios/chrome/browser/payments/shipping_address_selection_coordinator.mm
+++ b/ios/chrome/browser/payments/shipping_address_selection_coordinator.mm
@@ -9,6 +9,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "ios/chrome/browser/payments/payment_request.h"
+#import "ios/chrome/browser/payments/payment_request_util.h"
 
 @interface ShippingAddressSelectionCoordinator () {
   base::WeakNSProtocol<id<ShippingAddressSelectionCoordinatorDelegate>>
@@ -60,9 +61,10 @@
   _viewController.get().view.userInteractionEnabled = YES;
 
   [_viewController setIsLoading:NO];
-  [_viewController
-      setErrorMessage:base::SysUTF16ToNSString(
-                          _paymentRequest->payment_details().error)];
+  NSString* errorMessage =
+      payment_request_util::GetShippingAddressSelectorErrorMessage(
+          _paymentRequest);
+  [_viewController setErrorMessage:errorMessage];
   [_viewController loadModel];
   [[_viewController collectionView] reloadData];
 }
diff --git a/ios/chrome/browser/payments/shipping_address_selection_view_controller.mm b/ios/chrome/browser/payments/shipping_address_selection_view_controller.mm
index 9e411e72..19a7041 100644
--- a/ios/chrome/browser/payments/shipping_address_selection_view_controller.mm
+++ b/ios/chrome/browser/payments/shipping_address_selection_view_controller.mm
@@ -6,7 +6,6 @@
 
 #import "base/ios/weak_nsobject.h"
 #include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/strings/grit/components_strings.h"
@@ -76,8 +75,8 @@
 - (instancetype)initWithPaymentRequest:(PaymentRequest*)paymentRequest {
   DCHECK(paymentRequest);
   if ((self = [super initWithStyle:CollectionViewControllerStyleAppBar])) {
-    self.title = l10n_util::GetNSString(
-        IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE);
+    self.title =
+        payment_request_util::GetShippingAddressSelectorTitle(paymentRequest);
 
     UIBarButtonItem* returnButton =
         [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
@@ -129,8 +128,9 @@
     messageItem.text = _errorMessage;
     messageItem.image = NativeImage(IDR_IOS_PAYMENTS_WARNING);
   } else {
-    messageItem.text = l10n_util::GetNSString(
-        IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_MESSAGE);
+    messageItem.text =
+        payment_request_util::GetShippingAddressSelectorInfoMessage(
+            _paymentRequest);
   }
   [model addItem:messageItem
       toSectionWithIdentifier:SectionIdentifierShippingAddress];
diff --git a/ios/chrome/browser/payments/shipping_address_selection_view_controller_unittest.mm b/ios/chrome/browser/payments/shipping_address_selection_view_controller_unittest.mm
index 80c31b1..50b0705 100644
--- a/ios/chrome/browser/payments/shipping_address_selection_view_controller_unittest.mm
+++ b/ios/chrome/browser/payments/shipping_address_selection_view_controller_unittest.mm
@@ -8,13 +8,13 @@
 #include "base/memory/ptr_util.h"
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/payments/cells/payments_text_item.h"
 #import "ios/chrome/browser/payments/cells/shipping_address_item.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #include "ios/chrome/browser/payments/payment_request_test_util.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
-#include "ios/chrome/grit/ios_strings.h"
 #include "ios/web/public/payments/payment_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -59,7 +59,7 @@
 TEST_F(ShippingAddressSelectionViewControllerTest, TestModel) {
   CreateController();
   CheckController();
-  CheckTitleWithId(IDS_IOS_PAYMENT_REQUEST_SHIPPING_ADDRESS_SELECTION_TITLE);
+  CheckTitleWithId(IDS_PAYMENTS_SHIPPING_ADDRESS_LABEL);
 
   [GetShippingAddressSelectionViewController() loadModel];
 
diff --git a/ios/chrome/browser/payments/shipping_option_selection_coordinator.mm b/ios/chrome/browser/payments/shipping_option_selection_coordinator.mm
index 5645a2a3..c30c6bed 100644
--- a/ios/chrome/browser/payments/shipping_option_selection_coordinator.mm
+++ b/ios/chrome/browser/payments/shipping_option_selection_coordinator.mm
@@ -7,6 +7,7 @@
 #import "base/ios/weak_nsobject.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/payments/payment_request_util.h"
 
 @interface ShippingOptionSelectionCoordinator () {
   base::WeakNSProtocol<id<ShippingOptionSelectionCoordinatorDelegate>>
@@ -58,9 +59,10 @@
   _viewController.get().view.userInteractionEnabled = YES;
 
   [_viewController setIsLoading:NO];
-  [_viewController
-      setErrorMessage:base::SysUTF16ToNSString(
-                          _paymentRequest->payment_details().error)];
+  NSString* errorMessage =
+      payment_request_util::GetShippingOptionSelectorErrorMessage(
+          _paymentRequest);
+  [_viewController setErrorMessage:errorMessage];
   [_viewController loadModel];
   [[_viewController collectionView] reloadData];
 }
diff --git a/ios/chrome/browser/payments/shipping_option_selection_view_controller.mm b/ios/chrome/browser/payments/shipping_option_selection_view_controller.mm
index e0fca858..1620902 100644
--- a/ios/chrome/browser/payments/shipping_option_selection_view_controller.mm
+++ b/ios/chrome/browser/payments/shipping_option_selection_view_controller.mm
@@ -12,6 +12,7 @@
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/payments/cells/payments_text_item.h"
 #include "ios/chrome/browser/payments/payment_request.h"
+#import "ios/chrome/browser/payments/payment_request_util.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
@@ -22,7 +23,6 @@
 #include "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -71,8 +71,8 @@
 - (instancetype)initWithPaymentRequest:(PaymentRequest*)paymentRequest {
   DCHECK(paymentRequest);
   if ((self = [super initWithStyle:CollectionViewControllerStyleAppBar])) {
-    self.title = l10n_util::GetNSString(
-        IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
+    self.title =
+        payment_request_util::GetShippingOptionSelectorTitle(paymentRequest);
 
     UIBarButtonItem* returnButton =
         [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon backIcon]
diff --git a/ios/chrome/browser/payments/shipping_option_selection_view_controller_unittest.mm b/ios/chrome/browser/payments/shipping_option_selection_view_controller_unittest.mm
index a3f3b21..e9470272 100644
--- a/ios/chrome/browser/payments/shipping_option_selection_view_controller_unittest.mm
+++ b/ios/chrome/browser/payments/shipping_option_selection_view_controller_unittest.mm
@@ -8,13 +8,13 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/core/browser/test_personal_data_manager.h"
+#include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/payments/cells/payments_text_item.h"
 #include "ios/chrome/browser/payments/payment_request.h"
 #import "ios/chrome/browser/payments/payment_request_test_util.h"
 #import "ios/chrome/browser/ui/autofill/cells/status_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller_test.h"
-#include "ios/chrome/grit/ios_strings.h"
 #include "ios/web/public/payments/payment_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -51,7 +51,7 @@
 TEST_F(ShippingOptionSelectionViewControllerTest, TestModel) {
   CreateController();
   CheckController();
-  CheckTitleWithId(IDS_IOS_PAYMENT_REQUEST_SHIPPING_OPTION_SELECTION_TITLE);
+  CheckTitleWithId(IDS_PAYMENTS_SHIPPING_OPTION_LABEL);
 
   [GetShippingOptionSelectionViewController() loadModel];
 
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index a6eda18..484c358 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -1494,20 +1494,16 @@
   base::WeakNSObject<Tab> weakSelf(self);
   // TODO(crbug.com/692117): Remove |window_name| from constructor.
   web::BlockedPopupInfo poupInfo(popupURL, referrer, nil /* window_name */, ^{
-    base::scoped_nsobject<Tab> strongSelf([weakSelf retain]);
-    if (!strongSelf) {
-      return;
+    web::WebState* webState = [weakSelf webState];
+    if (webState) {
+      web::WebState::OpenURLParams params(
+          localPopupURL, referrer, WindowOpenDisposition::NEW_POPUP,
+          ui::PAGE_TRANSITION_LINK, true /* is_renderer_initiated */);
+      params.url = localPopupURL;
+      params.referrer = referrer;
+      params.transition = ui::PAGE_TRANSITION_LINK;
+      webState->OpenURL(params);
     }
-    [strongSelf updateSnapshotWithOverlay:YES visibleFrameOnly:YES];
-    [strongSelf.get()->parentTabModel_
-        insertOrUpdateTabWithURL:localPopupURL
-                        referrer:referrer
-                      transition:ui::PAGE_TRANSITION_LINK
-                      windowName:nil
-                          opener:self
-                     openedByDOM:YES
-                         atIndex:TabModelConstants::kTabPositionAutomatically
-                    inBackground:NO];
   });
   BlockedPopupTabHelper::FromWebState(self.webState)->HandlePopup(poupInfo);
 }
diff --git a/ios/chrome/browser/ui/DEPS b/ios/chrome/browser/ui/DEPS
index fa03c9a..0a1586ac 100644
--- a/ios/chrome/browser/ui/DEPS
+++ b/ios/chrome/browser/ui/DEPS
@@ -8,7 +8,6 @@
   # TODO(crbug.com/620489): Remove these exceptions.
   "^browser_view_controller\.mm$": [
     "+ios/web/navigation/crw_session_controller.h",
-    "+ios/web/navigation/crw_session_entry.h",
     "+ios/web/navigation/navigation_manager_impl.h",
     "+ios/web/web_state/ui/crw_web_controller.h",
   ],
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 102e29ed..89b97b29 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -171,7 +171,6 @@
 #include "ios/public/provider/chrome/browser/voice/voice_search_controller_delegate.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
 #import "ios/web/navigation/crw_session_controller.h"
-#import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/navigation/navigation_manager_impl.h"
 #include "ios/web/public/active_state_manager.h"
 #include "ios/web/public/navigation_item.h"
@@ -1917,11 +1916,10 @@
 
   // Hide the toolbar if displaying phone NTP.
   if (!IsIPadIdiom()) {
-    CRWSessionEntry* entry =
-        [[tab navigationManager]->GetSessionController() currentEntry];
+    web::NavigationItem* item = [tab navigationManager]->GetVisibleItem();
     BOOL hideToolbar = NO;
-    if (entry) {
-      GURL url = [entry navigationItem]->GetURL();
+    if (item) {
+      GURL url = item->GetURL();
       BOOL isNTP = url.GetOrigin() == GURL(kChromeUINewTabURL);
       hideToolbar = isNTP && !_isOffTheRecord &&
                     ![_toolbarController isOmniboxFirstResponder] &&
@@ -2376,6 +2374,18 @@
       webState->GetNavigationManager()->LoadURLWithParams(loadParams);
       return webState;
     }
+    case WindowOpenDisposition::NEW_POPUP: {
+      Tab* tab = [[self tabModel]
+          insertOrUpdateTabWithURL:params.url
+                          referrer:params.referrer
+                        transition:params.transition
+                        windowName:nil
+                            opener:LegacyTabHelper::GetTabForWebState(webState)
+                       openedByDOM:YES
+                           atIndex:TabModelConstants::kTabPositionAutomatically
+                      inBackground:NO];
+      return tab.webState;
+    }
     default:
       NOTIMPLEMENTED();
       return nullptr;
@@ -3361,7 +3371,7 @@
   DCHECK([tab navigationManager]);
   CRWSessionController* sc = [tab navigationManager]->GetSessionController();
   [_toolbarController showTabHistoryPopupInView:[self view]
-                             withSessionEntries:[sc backwardEntries]
+                                      withItems:[sc backwardItems]
                                  forBackHistory:YES];
 }
 
@@ -3377,14 +3387,14 @@
   DCHECK([tab navigationManager]);
   CRWSessionController* sc = [tab navigationManager]->GetSessionController();
   [_toolbarController showTabHistoryPopupInView:[self view]
-                             withSessionEntries:[sc forwardEntries]
+                                      withItems:[sc forwardItems]
                                  forBackHistory:NO];
 }
 
 - (void)navigateToSelectedEntry:(id)sender {
   DCHECK([sender isKindOfClass:[TabHistoryCell class]]);
   TabHistoryCell* selectedCell = (TabHistoryCell*)sender;
-  [[_model currentTab] goToItem:selectedCell.entry.navigationItem];
+  [[_model currentTab] goToItem:selectedCell.item];
   [_toolbarController dismissTabHistoryPopup];
 }
 
@@ -4805,13 +4815,6 @@
   return [_model currentTab].useDesktopUserAgent;
 }
 
-- (CRWSessionEntry*)currentSessionEntry {
-  Tab* tab = [_model currentTab];
-  if (![tab navigationManager])
-    return nil;
-  return [[tab navigationManager]->GetSessionController() currentEntry];
-}
-
 #pragma mark - BookmarkBridgeMethods
 
 // If an added or removed bookmark is the same as the current url, update the
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 8926439..74da394 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -210,6 +210,7 @@
     "//components/browsing_data/core",
     "//components/prefs",
     "//components/strings",
+    "//components/url_formatter:url_formatter",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
diff --git a/ios/chrome/browser/ui/history/DEPS b/ios/chrome/browser/ui/history/DEPS
deleted file mode 100644
index cb80df7..0000000
--- a/ios/chrome/browser/ui/history/DEPS
+++ /dev/null
@@ -1,15 +0,0 @@
-specific_include_rules = {
-  # TODO(crbug.com/620907): Remove these exceptions.
-  "^tab_history_cell\.mm$": [
-    "+ios/web/navigation/crw_session_entry.h",
-  ],
-  "tab_history_popup_controller.mm": [
-    "+ios/web/navigation/crw_session_entry.h",
-  ],
-  "tab_history_popup_controller_unittest.mm": [
-    "+ios/web/navigation/crw_session_entry.h",
-  ],
-  "tab_history_view_controller.mm": [
-    "+ios/web/navigation/crw_session_entry.h",
-  ],
-}
diff --git a/ios/chrome/browser/ui/history/tab_history_cell.h b/ios/chrome/browser/ui/history/tab_history_cell.h
index 745a9d5d..590e037f 100644
--- a/ios/chrome/browser/ui/history/tab_history_cell.h
+++ b/ios/chrome/browser/ui/history/tab_history_cell.h
@@ -7,18 +7,20 @@
 
 #import <UIKit/UIKit.h>
 
-@class CRWSessionEntry;
+namespace web {
+class NavigationItem;
+}
 
 // Table cell used in TabHistoryViewController.
 @interface TabHistoryCell : UICollectionViewCell
-@property(strong, nonatomic) CRWSessionEntry* entry;
-@property(weak, nonatomic, readonly) UILabel* titleLabel;
+@property(assign, nonatomic) const web::NavigationItem* item;
+@property(strong, nonatomic, readonly) UILabel* titleLabel;
 @end
 
 // Header for a section of TabHistoryCells.
 @interface TabHistorySectionHeader : UICollectionReusableView
-@property(weak, nonatomic, readonly) UIImageView* iconView;
-@property(weak, nonatomic, readonly) UIView* lineView;
+@property(strong, nonatomic, readonly) UIImageView* iconView;
+@property(strong, nonatomic, readonly) UIView* lineView;
 @end
 
 // Footer for a section of TabHistoryCells.
diff --git a/ios/chrome/browser/ui/history/tab_history_cell.mm b/ios/chrome/browser/ui/history/tab_history_cell.mm
index 2d34024..b2d708a 100644
--- a/ios/chrome/browser/ui/history/tab_history_cell.mm
+++ b/ios/chrome/browser/ui/history/tab_history_cell.mm
@@ -8,7 +8,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
-#import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/public/navigation_item.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -42,10 +41,10 @@
 }
 }
 
-@implementation TabHistoryCell {
-  CRWSessionEntry* _entry;
-  UILabel* _titleLabel;
-}
+@implementation TabHistoryCell
+
+@synthesize item = _item;
+@synthesize titleLabel = _titleLabel;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
@@ -73,59 +72,34 @@
 
 - (void)layoutSubviews {
   [super layoutSubviews];
-
-  CGRect bounds = [[self contentView] bounds];
-  CGRect frame = AlignRectOriginAndSizeToPixels(bounds);
-  [_titleLabel setFrame:frame];
+  self.titleLabel.frame =
+      AlignRectOriginAndSizeToPixels(self.contentView.bounds);
 }
 
-- (CRWSessionEntry*)entry {
-  return _entry;
-}
+#pragma mark Accessors
 
-- (void)setEntry:(CRWSessionEntry*)entry {
-  _entry = entry;
+- (void)setItem:(const web::NavigationItem*)item {
+  _item = item;
 
-  NSString* title = nil;
-  web::NavigationItem* navigationItem = [_entry navigationItem];
-  if (navigationItem) {
-    // TODO(rohitrao): Can this use GetTitleForDisplay() instead?
-    if (navigationItem->GetTitle().empty())
-      title = base::SysUTF8ToNSString(navigationItem->GetURL().spec());
-    else
-      title = base::SysUTF16ToNSString(navigationItem->GetTitle());
-  }
-
-  [_titleLabel setText:title];
-  [self setAccessibilityLabel:title];
+  self.titleLabel.text =
+      _item ? base::SysUTF16ToNSString(_item->GetTitleForDisplay()) : nil;
+  [self setAccessibilityLabel:self.titleLabel.text];
   [self setNeedsLayout];
 }
 
-- (UILabel*)titleLabel {
-  return _titleLabel;
-}
+#pragma mark UICollectionViewCell
 
 - (void)prepareForReuse {
   [super prepareForReuse];
-  _entry = nil;
-  [_titleLabel setText:nil];
-  [self setAccessibilityLabel:nil];
+  self.item = nullptr;
 }
 
 @end
 
-@implementation TabHistorySectionHeader {
-  UIImageView* _iconView;
-  UIView* _lineView;
-}
+@implementation TabHistorySectionHeader
 
-- (UIImageView*)iconView {
-  return _iconView;
-}
-
-- (UIView*)lineView {
-  return _lineView;
-}
+@synthesize iconView = _iconView;
+@synthesize lineView = _lineView;
 
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
@@ -134,17 +108,17 @@
     _iconView = [[UIImageView alloc] initWithFrame:iconFrame];
     [self addSubview:_iconView];
 
-    UIColor* lineColor = UIColorFromRGB(kHeaderLineRGB);
-
     _lineView = [[UIView alloc] initWithFrame:CGRectZero];
-    [[_lineView layer] setCornerRadius:HeaderLineRadius()];
-    [_lineView setBackgroundColor:lineColor];
+    _lineView.layer.cornerRadius = HeaderLineRadius();
+    _lineView.backgroundColor = UIColorFromRGB(kHeaderLineRGB);
     [self addSubview:_lineView];
   }
 
   return self;
 }
 
+#pragma mark UIView
+
 - (void)layoutSubviews {
   [super layoutSubviews];
 
@@ -153,7 +127,7 @@
 
   CGRect iconViewFrame = AlignRectToPixel(bounds);
   iconViewFrame.size = CGSizeMake(kSiteIconViewWidth, kSiteIconViewWidth);
-  [_iconView setFrame:iconViewFrame];
+  self.iconView.frame = iconViewFrame;
 
   CGFloat iconViewMaxY = CGRectGetMaxY(iconViewFrame);
   CGFloat height =
@@ -167,8 +141,7 @@
   lineViewFrame.size.width = HeaderLineWidth();
   lineViewFrame.size.height = height;
   lineViewFrame = AlignRectOriginAndSizeToPixels(lineViewFrame);
-
-  [_lineView setFrame:lineViewFrame];
+  self.lineView.frame = lineViewFrame;
 }
 
 @end
@@ -178,7 +151,7 @@
 - (instancetype)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self)
-    [self setBackgroundColor:UIColorFromRGB(kFooterRGB)];
+    self.backgroundColor = UIColorFromRGB(kFooterRGB);
 
   return self;
 }
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller.h b/ios/chrome/browser/ui/history/tab_history_popup_controller.h
index 293447f..8cd8a6294 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller.h
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller.h
@@ -7,20 +7,19 @@
 
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_controller.h"
 
-@class TabHistoryViewController;
+#include "ios/web/public/navigation_item_list.h"
 
 // The view controller for the tab history menu that appears when the user long
 // presses the back or forward button.
 @interface TabHistoryPopupController : PopupMenuController
 
-// Initializes the popup to display |entries| with the given |origin| that is
+// Initializes the popup to display |items| with the given |origin| that is
 // relevant to the |parent|'s coordinate system.
 // |entries| is an array of CRWSessionEntries.
-// TODO(crbug.com/546355): Convert this class to use an array of
-//    NavigationEntries
 - (id)initWithOrigin:(CGPoint)origin
           parentView:(UIView*)parent
-             entries:(NSArray*)entries;
+               items:(const web::NavigationItemList&)items
+    NS_DESIGNATED_INITIALIZER;
 
 @end
 
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller.mm b/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
index 832de03..5c6c124 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller.mm
@@ -15,20 +15,22 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/common/material_timing.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
-#import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/public/navigation_item.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 #include "ui/gfx/ios/uikit_util.h"
+#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
 namespace {
-static const CGFloat kTabHistoryMinWidth = 250.0;
-static const CGFloat kTabHistoryMaxWidthLandscapePhone = 350.0;
+const CGFloat kTabHistoryMinWidth = 250.0;
+const CGFloat kTabHistoryMaxWidthLandscapePhone = 350.0;
 // x coordinate for the textLabel in a default table cell with an image.
-static const CGFloat kCellTextXCoordinate = 60.0;
+const CGFloat kCellTextXCoordinate = 60.0;
+// The corner radius for the popover container view.
+const CGFloat kPopoverCornerRadius = 2.0;
 // Inset for the shadows of the contained views.
 NS_INLINE UIEdgeInsets TabHistoryPopupMenuInsets() {
   return UIEdgeInsetsMakeDirected(9, 11, 12, 11);
@@ -41,91 +43,90 @@
 static const CGFloat kHeightPercentage = 0.85;
 }  // anonymous namespace
 
-@interface TabHistoryPopupController () {
-  // TableViewController for the table displaying tab history entries.
-  TabHistoryViewController* tabHistoryTableViewController_;
+@interface TabHistoryPopupController ()
 
-  // Container view of the history entries table.
-  UIView* tabHistoryTableViewContainer_;
-}
-
-// Determines the width for the popup depending on the device, orientation, and
-// CRWSessionEntrys to display.
-- (CGFloat)calculatePopupWidth:(NSArray*)entries;
-
+// The UITableViewController displaying Tab history items.
 @property(nonatomic, strong)
     TabHistoryViewController* tabHistoryTableViewController;
+// The container view that displays |tabHistoryTableViewController|.
 @property(nonatomic, strong) UIView* tabHistoryTableViewContainer;
 
+// Determines the width for the popup depending on the device, orientation, and
+// number of NavigationItems to display.
++ (CGFloat)popupWidthForItems:(const web::NavigationItemList)items;
+
 @end
 
 @implementation TabHistoryPopupController
 
-@synthesize tabHistoryTableViewController = tabHistoryTableViewController_;
-@synthesize tabHistoryTableViewContainer = tabHistoryTableViewContainer_;
+@synthesize tabHistoryTableViewController = _tabHistoryTableViewController;
+@synthesize tabHistoryTableViewContainer = _tabHistoryTableViewContainer;
 
 - (id)initWithOrigin:(CGPoint)origin
           parentView:(UIView*)parent
-             entries:(NSArray*)entries {
+               items:(const web::NavigationItemList&)items {
   DCHECK(parent);
-  self = [super initWithParentView:parent];
-  if (self) {
-    tabHistoryTableViewController_ = [[TabHistoryViewController alloc] init];
-    [tabHistoryTableViewController_ setSessionEntries:entries];
+  if ((self = [super initWithParentView:parent])) {
+    // Create the table view controller.
+    _tabHistoryTableViewController =
+        [[TabHistoryViewController alloc] initWithItems:items];
 
-    UICollectionView* collectionView =
-        [tabHistoryTableViewController_ collectionView];
-    [collectionView setAccessibilityIdentifier:@"Tab History"];
+    // Set up the container view.
+    _tabHistoryTableViewContainer = [[UIView alloc] initWithFrame:CGRectZero];
+    _tabHistoryTableViewContainer.layer.cornerRadius = kPopoverCornerRadius;
+    _tabHistoryTableViewContainer.layer.masksToBounds = YES;
+    [_tabHistoryTableViewContainer
+        addSubview:_tabHistoryTableViewController.view];
 
-    tabHistoryTableViewContainer_ = [[UIView alloc] initWithFrame:CGRectZero];
-    [tabHistoryTableViewContainer_ layer].cornerRadius = 2;
-    [tabHistoryTableViewContainer_ layer].masksToBounds = YES;
-    [tabHistoryTableViewContainer_ addSubview:collectionView];
-
+    // Calculate the optimal popup size.
     LayoutOffset originOffset =
         kHistoryPopupLeadingOffset - TabHistoryPopupMenuInsets().left;
     CGPoint newOrigin = CGPointLayoutOffset(origin, originOffset);
     newOrigin.y += kHistoryPopupYOffset;
-
     CGFloat availableHeight =
         (CGRectGetHeight([parent bounds]) - origin.y) * kHeightPercentage;
     CGFloat optimalHeight =
-        [tabHistoryTableViewController_ optimalHeight:availableHeight];
-    CGFloat popupWidth = [self calculatePopupWidth:entries];
+        [_tabHistoryTableViewController optimalHeight:availableHeight];
+    CGFloat popupWidth = [[self class] popupWidthForItems:items];
     [self setOptimalSize:CGSizeMake(popupWidth, optimalHeight)
                 atOrigin:newOrigin];
-
-    CGRect bounds = [[self popupContainer] bounds];
-    CGRect frame = UIEdgeInsetsInsetRect(bounds, TabHistoryPopupMenuInsets());
-
-    [tabHistoryTableViewContainer_ setFrame:frame];
-    [collectionView setFrame:[tabHistoryTableViewContainer_ bounds]];
-
-    [[self popupContainer] addSubview:tabHistoryTableViewContainer_];
-    CGRect containerFrame = [[self popupContainer] frame];
-    CGPoint destination = CGPointMake(CGRectGetLeadingEdge(containerFrame),
-                                      CGRectGetMinY(containerFrame));
-    [self fadeInPopupFromSource:origin toDestination:destination];
   }
   return self;
 }
 
+- (void)dealloc {
+  [_tabHistoryTableViewContainer removeFromSuperview];
+}
+
+#pragma mark - PopupMenuController
+
 - (void)fadeInPopupFromSource:(CGPoint)source
                 toDestination:(CGPoint)destination {
-  [tabHistoryTableViewContainer_ setAlpha:0];
+  // Add the container view to the popup view and resize.
+  if (!_tabHistoryTableViewContainer.superview)
+    [self.popupContainer addSubview:_tabHistoryTableViewContainer];
+  _tabHistoryTableViewContainer.frame = UIEdgeInsetsInsetRect(
+      self.popupContainer.bounds, TabHistoryPopupMenuInsets());
+  _tabHistoryTableViewController.view.frame =
+      _tabHistoryTableViewContainer.bounds;
+
+  // Set up the animation.
+  [_tabHistoryTableViewContainer setAlpha:0];
   [UIView animateWithDuration:ios::material::kDuration1
                    animations:^{
-                     [tabHistoryTableViewContainer_ setAlpha:1];
+                     [_tabHistoryTableViewContainer setAlpha:1];
                    }];
   [super fadeInPopupFromSource:source toDestination:destination];
 }
 
 - (void)dismissAnimatedWithCompletion:(void (^)(void))completion {
-  [tabHistoryTableViewContainer_ setAlpha:0];
+  [_tabHistoryTableViewContainer setAlpha:0];
   [super dismissAnimatedWithCompletion:completion];
 }
 
-- (CGFloat)calculatePopupWidth:(NSArray*)entries {
+#pragma mark -
+
++ (CGFloat)popupWidthForItems:(const web::NavigationItemList)items {
   CGFloat maxWidth;
 
   // Determine the maximum width for the device and orientation.
@@ -145,8 +146,7 @@
   // Increase the width to fit the text to display but don't exceed maxWidth.
   CGFloat cellWidth = kTabHistoryMinWidth;
   UIFont* font = [[MDFRobotoFontLoader sharedInstance] regularFontOfSize:16];
-  for (CRWSessionEntry* sessionEntry in entries) {
-    web::NavigationItem* item = sessionEntry.navigationItem;
+  for (web::NavigationItem* item : items) {
     // TODO(rohitrao): Can this be replaced with GetTitleForDisplay()?
     NSString* cellText = item->GetTitle().empty()
                              ? base::SysUTF8ToNSString(item->GetURL().spec())
@@ -155,7 +155,7 @@
                            kCellTextXCoordinate;
 
     // If contentWidth is larger than maxWidth, return maxWidth instead of
-    // checking the rest of the entries.
+    // checking the rest of the items.
     if (contentWidth > maxWidth)
       return maxWidth;
     if (contentWidth > cellWidth)
@@ -164,8 +164,4 @@
   return cellWidth;
 }
 
-- (void)dealloc {
-  [tabHistoryTableViewContainer_ removeFromSuperview];
-}
-
 @end
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller_egtest.mm b/ios/chrome/browser/ui/history/tab_history_popup_controller_egtest.mm
index 1881fe80..3ef29aba 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller_egtest.mm
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller_egtest.mm
@@ -6,6 +6,7 @@
 
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/url_formatter/url_formatter.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
@@ -16,6 +17,13 @@
 #error "This file requires ARC support."
 #endif
 
+namespace {
+// Formats |url| for display and returns an NSString representation.
+NSString* GetFormattedURLString(const GURL& url) {
+  return base::SysUTF16ToNSString(url_formatter::FormatUrl(url));
+}
+}
+
 // Tests for tab history popup.
 @interface TabHistoryPopupControllerTestCase : ChromeTestCase
 @end
@@ -31,10 +39,10 @@
   const GURL URL3 = web::test::HttpServer::MakeUrl("http://page3");
   const GURL URL4 = web::test::HttpServer::MakeUrl("http://page4");
   NSString* entry0 = @"New Tab";
-  NSString* entry1 = base::SysUTF8ToNSString(URL1.spec());
-  NSString* entry2 = base::SysUTF8ToNSString(URL2.spec());
-  NSString* entry3 = base::SysUTF8ToNSString(URL3.spec());
-  NSString* entry4 = base::SysUTF8ToNSString(URL4.spec());
+  NSString* entry1 = GetFormattedURLString(URL1);
+  NSString* entry2 = GetFormattedURLString(URL2);
+  NSString* entry3 = GetFormattedURLString(URL3);
+  NSString* entry4 = GetFormattedURLString(URL4);
 
   // Create map of canned responses and set up the test HTML server.
   std::map<GURL, std::string> responses;
diff --git a/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm b/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
index 3782087..6f1e9e7 100644
--- a/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
+++ b/ios/chrome/browser/ui/history/tab_history_popup_controller_unittest.mm
@@ -11,7 +11,6 @@
 #include "components/sessions/core/session_types.h"
 #import "ios/chrome/browser/ui/history/tab_history_view_controller.h"
 #include "ios/chrome/browser/ui/ui_util.h"
-#import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/public/navigation_item.h"
 #include "ios/web/public/referrer.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -20,7 +19,7 @@
 #include "ui/gfx/ios/uikit_util.h"
 
 @interface TabHistoryPopupController (Testing)
-- (CGFloat)calculatePopupWidth:(NSArray*)entries;
++ (CGFloat)popupWidthForItems:(const web::NavigationItemList)items;
 @property(nonatomic, retain)
     TabHistoryViewController* tabHistoryTableViewController;
 @end
@@ -32,36 +31,26 @@
 class TabHistoryPopupControllerTest : public PlatformTest {
  protected:
   void SetUp() override {
+    web::Referrer referrer(GURL("http://www.example.com"),
+                           web::ReferrerPolicyDefault);
+    items_.push_back(web::NavigationItem::Create());
+    items_.back()->SetURL(GURL("http://www.example.com/0"));
+    items_.back()->SetReferrer(referrer);
+    items_.push_back(web::NavigationItem::Create());
+    items_.back()->SetURL(GURL("http://www.example.com/1"));
+    items_.back()->SetReferrer(referrer);
+    items_.push_back(web::NavigationItem::Create());
+    items_.back()->SetURL(GURL("http://www.example.com/0"));
+    items_.back()->SetReferrer(referrer);
+
     parent_.reset([[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]);
     popup_.reset([[TabHistoryPopupController alloc]
         initWithOrigin:CGPointZero
             parentView:parent_
-               entries:testEntriesArray()]);
+                 items:web::CreateRawNavigationItemList(items_)]);
   }
-  void TearDown() override {
-    parent_.reset();
-    popup_.reset();
-  }
-  NSArray* testEntriesArray() {
-    web::Referrer referrer(GURL("http://www.example.com"),
-                           web::ReferrerPolicyDefault);
-    std::unique_ptr<web::NavigationItem> item0 = web::NavigationItem::Create();
-    item0->SetURL(GURL("http://www.example.com/0"));
-    item0->SetReferrer(referrer);
-    CRWSessionEntry* entry0 =
-        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item0)];
-    std::unique_ptr<web::NavigationItem> item1 = web::NavigationItem::Create();
-    item1->SetURL(GURL("http://www.example.com/1"));
-    item1->SetReferrer(referrer);
-    CRWSessionEntry* entry1 =
-        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item1)];
-    std::unique_ptr<web::NavigationItem> item2 = web::NavigationItem::Create();
-    item2->SetURL(GURL("http://www.example.com/2"));
-    item2->SetReferrer(referrer);
-    CRWSessionEntry* entry2 =
-        [[CRWSessionEntry alloc] initWithNavigationItem:std::move(item2)];
-    return [NSArray arrayWithObjects:entry0, entry1, entry2, nil];
-  }
+
+  web::ScopedNavigationItemList items_;
   base::scoped_nsobject<UIView> parent_;
   base::scoped_nsobject<TabHistoryPopupController> popup_;
 };
@@ -81,30 +70,6 @@
 }
 
 TEST_F(TabHistoryPopupControllerTest, TestCalculatePopupWidth) {
-  web::Referrer referrer(GURL("http://www.example.com"),
-                         web::ReferrerPolicyDefault);
-  std::unique_ptr<web::NavigationItem> itemShort =
-      web::NavigationItem::Create();
-  itemShort->SetURL(GURL("http://foo.com/"));
-  itemShort->SetReferrer(referrer);
-  CRWSessionEntry* entryShort =
-      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemShort)];
-  std::unique_ptr<web::NavigationItem> itemMedium =
-      web::NavigationItem::Create();
-  itemMedium->SetURL(GURL("http://www.example.com/mediumurl"));
-  itemMedium->SetReferrer(referrer);
-  CRWSessionEntry* entryMedium =
-      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemMedium)];
-  std::string longURL =
-      "http://www.example.com/this/is/areally/long/url/that/"
-      "is/larger/than/the/maximum/table/width/so/its/text/will/get/cut/off/and/"
-      "the/max/width/is/used/";
-  std::unique_ptr<web::NavigationItem> itemLong = web::NavigationItem::Create();
-  itemLong->SetURL(GURL(longURL));
-  itemLong->SetReferrer(referrer);
-  CRWSessionEntry* entryLong =
-      [[CRWSessionEntry alloc] initWithNavigationItem:std::move(itemLong)];
-
   CGFloat minWidth = kTabHistoryMinWidth;
   CGFloat maxWidth = kTabHistoryMinWidth;
   if (!IsIPadIdiom()) {
@@ -117,19 +82,37 @@
         [UIApplication sharedApplication].keyWindow.frame.size.width * .85);
   }
 
-  CGFloat width =
-      [popup_ calculatePopupWidth:[NSArray arrayWithObjects:entryShort, nil]];
+  // Add an item with a short URL and verify that the minimum width is returned.
+  web::ScopedNavigationItemList items;
+  web::Referrer referrer(GURL("http://www.example.com"),
+                         web::ReferrerPolicyDefault);
+  items.push_back(web::NavigationItem::Create());
+  items.back()->SetURL(GURL("http://foo.com/"));
+  items.back()->SetReferrer(referrer);
+  web::NavigationItemList raw_items = web::CreateRawNavigationItemList(items);
+  CGFloat width = [TabHistoryPopupController popupWidthForItems:raw_items];
   EXPECT_EQ(minWidth, width);
 
-  width =
-      [popup_ calculatePopupWidth:[NSArray arrayWithObjects:entryShort,
-                                                            entryMedium, nil]];
+  // Add an item with a medium URL and verify that the returned width is between
+  // the minimum and maximum.
+  items.push_back(web::NavigationItem::Create());
+  items.back()->SetURL(GURL("http://www.example.com/mediumurl"));
+  items.back()->SetReferrer(referrer);
+  raw_items.push_back(items.back().get());
+  width = [TabHistoryPopupController popupWidthForItems:raw_items];
   EXPECT_GE(width, minWidth);
   EXPECT_LE(width, maxWidth);
 
-  width = [popup_
-      calculatePopupWidth:[NSArray arrayWithObjects:entryShort, entryLong,
-                                                    entryMedium, nil]];
+  // Add an item with a long URL and verify that the maximum width is returned.
+  std::string long_url =
+      "http://www.example.com/this/is/areally/long/url/that/"
+      "is/larger/than/the/maximum/table/width/so/its/text/will/get/cut/off/and/"
+      "the/max/width/is/used/";
+  items.push_back(web::NavigationItem::Create());
+  items.back()->SetURL(GURL(long_url));
+  items.back()->SetReferrer(referrer);
+  raw_items.push_back(items.back().get());
+  width = [TabHistoryPopupController popupWidthForItems:raw_items];
   EXPECT_EQ(maxWidth, width);
 }
 
diff --git a/ios/chrome/browser/ui/history/tab_history_view_controller.h b/ios/chrome/browser/ui/history/tab_history_view_controller.h
index cc7877e..5343bc2 100644
--- a/ios/chrome/browser/ui/history/tab_history_view_controller.h
+++ b/ios/chrome/browser/ui/history/tab_history_view_controller.h
@@ -7,12 +7,21 @@
 
 #import <UIKit/UIKit.h>
 
-// View controller for displaying a list of CRWSessionEntry objects in a table.
+#include "ios/web/public/navigation_item_list.h"
+
+// View controller for displaying a list of NavigationItems in a table.
 @interface TabHistoryViewController : UICollectionViewController
 
-// TODO(crbug.com/546355): Convert this class to use an array of
-//    NavigationEntries.
-@property(nonatomic, strong) NSArray* sessionEntries;
+// Designated initializer that takes a NavigationItemList.
+- (instancetype)initWithItems:(const web::NavigationItemList&)items
+    NS_DESIGNATED_INITIALIZER;
+
+// TabHistoryViewControllers must be initialized with |-initWithItems:|.
+- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
+- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout
+    NS_UNAVAILABLE;
+- (instancetype)initWithNibName:(NSString*)nibNameOrNil
+                         bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
 
 // Returns the optimal height needed to display the session entries.
 // The height returned is usually less than the |suggestedHeight| unless
diff --git a/ios/chrome/browser/ui/history/tab_history_view_controller.mm b/ios/chrome/browser/ui/history/tab_history_view_controller.mm
index 954ea175..5f84835 100644
--- a/ios/chrome/browser/ui/history/tab_history_view_controller.mm
+++ b/ios/chrome/browser/ui/history/tab_history_view_controller.mm
@@ -12,7 +12,6 @@
 #import "ios/chrome/browser/ui/history/tab_history_cell.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h"
-#import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/public/favicon_status.h"
 #include "ios/web/public/navigation_item.h"
 #include "ui/gfx/image/image.h"
@@ -27,9 +26,11 @@
 // Tools menu is scrollable.
 const CGFloat kLastRowVisiblePercentage = 0.6;
 // Reuse identifier for cells.
-NSString* cellIdentifier = @"TabHistoryCell";
-NSString* footerIdentifier = @"Footer";
-NSString* headerIdentifier = @"Header";
+NSString* const kCellIdentifier = @"TabHistoryCell";
+NSString* const kFooterIdentifier = @"Footer";
+NSString* const kHeaderIdentifier = @"Header";
+// The collection view's a11y label.
+NSString* const kCollectionViewLabel = @"Tab History";
 // Height of rows.
 const CGFloat kCellHeight = 48.0;
 // Fraction height for partially visible row.
@@ -71,6 +72,36 @@
   return 1.0 / [[UIScreen mainScreen] scale];
 }
 
+// Returns a vector of of NavigationItemLists where the NavigationItems in
+// |items| are separated by host.
+NS_INLINE std::vector<web::NavigationItemList> PartitionItemsByHost(
+    const web::NavigationItemList& items) {
+  std::vector<web::NavigationItemList> partitionedItems;
+  // Used to store the previous host when partitioning NavigationItems.
+  std::string previousHost;
+  // The NavigationItemList containing NavigationItems with the same host.
+  web::NavigationItemList itemsWithSameHostname;
+  // Separate the items in |items| by host.
+  for (web::NavigationItem* item : items) {
+    std::string currentHost = item->GetURL().host();
+    if (previousHost.empty())
+      previousHost = currentHost;
+    // TODO: This should use some sort of Top Level Domain matching instead of
+    // explicit host match so that images.googe.com matches shopping.google.com.
+    if (previousHost == currentHost) {
+      itemsWithSameHostname.push_back(item);
+    } else {
+      partitionedItems.push_back(itemsWithSameHostname);
+      itemsWithSameHostname = web::NavigationItemList(1, item);
+      previousHost = currentHost;
+    }
+  }
+  // Add the last list contiaining the same host.
+  if (!itemsWithSameHostname.empty())
+    partitionedItems.push_back(itemsWithSameHostname);
+  return partitionedItems;
+}
+
 }  // namespace
 
 @interface TabHistoryViewControllerLayout : UICollectionViewLayout
@@ -219,15 +250,50 @@
 
 @interface TabHistoryViewController ()<MDCInkTouchControllerDelegate> {
   MDCInkTouchController* _inkTouchController;
-  NSArray* _partitionedEntries;
-  NSArray* _sessionEntries;
+  // A vector of NavigationItemLists where the NavigationItems are separated
+  // by hostname.
+  std::vector<web::NavigationItemList> _partitionedItems;
 }
+
+// Returns the NavigationItem corresponding with |indexPath|.
+- (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath;
+
+// Removes all NavigationItem pointers from this class.  Tapping a cell that
+// triggers a navigation may delete NavigationItems, so NavigationItem
+// references should be reset to avoid use-after-free errors.
+- (void)clearNavigationItems;
+
 @end
 
 @implementation TabHistoryViewController
 
-- (NSArray*)sessionEntries {
-  return _sessionEntries;
+- (instancetype)initWithItems:(const web::NavigationItemList&)items {
+  TabHistoryViewControllerLayout* layout =
+      [[TabHistoryViewControllerLayout alloc] init];
+  if ((self = [super initWithCollectionViewLayout:layout])) {
+    // Populate |_partitionedItems|.
+    _partitionedItems = PartitionItemsByHost(items);
+
+    // Set up the UICollectionView.
+    UICollectionView* collectionView = [self collectionView];
+    collectionView.accessibilityLabel = kCollectionViewLabel;
+    collectionView.backgroundColor = [UIColor whiteColor];
+    [collectionView registerClass:[TabHistoryCell class]
+        forCellWithReuseIdentifier:kCellIdentifier];
+    [collectionView registerClass:[TabHistorySectionHeader class]
+        forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
+               withReuseIdentifier:kHeaderIdentifier];
+    [collectionView registerClass:[TabHistorySectionFooter class]
+        forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
+               withReuseIdentifier:kFooterIdentifier];
+
+    // Set up the ink controller.
+    _inkTouchController =
+        [[MDCInkTouchController alloc] initWithView:collectionView];
+    [_inkTouchController setDelegate:self];
+    [_inkTouchController addInkView];
+  }
+  return self;
 }
 
 #pragma mark Public Methods
@@ -236,9 +302,8 @@
   DCHECK(suggestedHeight >= kCellHeight);
   CGFloat optimalHeight = 0;
 
-  for (NSArray* sectionArray in _partitionedEntries) {
-    NSUInteger sectionItemCount = [sectionArray count];
-    for (NSUInteger i = 0; i < sectionItemCount; ++i) {
+  for (web::NavigationItemList& itemsWithSameHost : _partitionedItems) {
+    for (size_t count = 0; count < itemsWithSameHost.size(); ++count) {
       CGFloat proposedHeight = optimalHeight + kCellHeight;
 
       if (proposedHeight > suggestedHeight) {
@@ -263,153 +328,67 @@
   return optimalHeight;
 }
 
-- (instancetype)init {
-  TabHistoryViewControllerLayout* layout =
-      [[TabHistoryViewControllerLayout alloc] init];
-
-  return [self initWithCollectionViewLayout:layout];
-}
-
-- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout {
-  self = [super initWithCollectionViewLayout:layout];
-  if (self) {
-    UICollectionView* collectionView = [self collectionView];
-    [collectionView setBackgroundColor:[UIColor whiteColor]];
-
-    [collectionView registerClass:[TabHistoryCell class]
-        forCellWithReuseIdentifier:cellIdentifier];
-
-    [collectionView registerClass:[TabHistorySectionHeader class]
-        forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
-               withReuseIdentifier:headerIdentifier];
-
-    [collectionView registerClass:[TabHistorySectionFooter class]
-        forSupplementaryViewOfKind:UICollectionElementKindSectionFooter
-               withReuseIdentifier:footerIdentifier];
-
-    _inkTouchController =
-        [[MDCInkTouchController alloc] initWithView:collectionView];
-    [_inkTouchController setDelegate:self];
-    [_inkTouchController addInkView];
-  }
-
-  return self;
-}
-
 #pragma mark UICollectionViewDelegate
 
 - (void)collectionView:(UICollectionView*)collectionView
     didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  UICollectionViewCell* cell =
-      [collectionView cellForItemAtIndexPath:indexPath];
+  TabHistoryCell* cell = base::mac::ObjCCastStrict<TabHistoryCell>(
+      [collectionView cellForItemAtIndexPath:indexPath]);
   [collectionView chromeExecuteCommand:cell];
+  [self clearNavigationItems];
 }
 
 #pragma mark UICollectionViewDataSource
 
-- (CRWSessionEntry*)entryForIndexPath:(NSIndexPath*)indexPath {
-  NSInteger section = [indexPath section];
-  NSInteger item = [indexPath item];
-
-  DCHECK(section < (NSInteger)[_partitionedEntries count]);
-  DCHECK(item < (NSInteger)[[_partitionedEntries objectAtIndex:section] count]);
-  NSArray* sectionedArray = [_partitionedEntries objectAtIndex:section];
-
-  return [sectionedArray objectAtIndex:item];
-}
-
 - (NSInteger)collectionView:(UICollectionView*)collectionView
      numberOfItemsInSection:(NSInteger)section {
-  DCHECK(section < (NSInteger)[_partitionedEntries count]);
-  return [[_partitionedEntries objectAtIndex:section] count];
+  size_t sectionIdx = static_cast<size_t>(section);
+  DCHECK_LT(sectionIdx, _partitionedItems.size());
+  return _partitionedItems[sectionIdx].size();
 }
 
 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
                  cellForItemAtIndexPath:(NSIndexPath*)indexPath {
   TabHistoryCell* cell =
-      [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
+      [collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier
                                                 forIndexPath:indexPath];
-
-  [cell setEntry:[self entryForIndexPath:indexPath]];
-  [cell setTag:IDC_BACK_FORWARD_IN_TAB_HISTORY];
-
+  cell.item = [self itemAtIndexPath:indexPath];
+  cell.tag = IDC_BACK_FORWARD_IN_TAB_HISTORY;
   return cell;
 }
 
 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView*)view {
-  return [_partitionedEntries count];
+  return _partitionedItems.size();
 }
 
 - (UICollectionReusableView*)collectionView:(UICollectionView*)view
           viewForSupplementaryElementOfKind:(NSString*)kind
                                 atIndexPath:(NSIndexPath*)indexPath {
+  // Return a footer cell if requested.
   if ([kind isEqualToString:UICollectionElementKindSectionFooter]) {
     return [view dequeueReusableSupplementaryViewOfKind:kind
-                                    withReuseIdentifier:footerIdentifier
+                                    withReuseIdentifier:kFooterIdentifier
                                            forIndexPath:indexPath];
   }
-
   DCHECK([kind isEqualToString:UICollectionElementKindSectionHeader]);
-  CRWSessionEntry* sessionEntry = [self entryForIndexPath:indexPath];
-  web::NavigationItem* navigationItem = [sessionEntry navigationItem];
 
+  // Dequeue a header cell and populate its favicon image.
   TabHistorySectionHeader* header =
       [view dequeueReusableSupplementaryViewOfKind:kind
-                               withReuseIdentifier:headerIdentifier
+                               withReuseIdentifier:kHeaderIdentifier
                                       forIndexPath:indexPath];
-
   UIImage* iconImage = nil;
-  const gfx::Image& image = navigationItem->GetFavicon().image;
+  const gfx::Image& image =
+      [self itemAtIndexPath:indexPath]->GetFavicon().image;
   if (!image.IsEmpty())
     iconImage = image.ToUIImage();
   else
     iconImage = [UIImage imageNamed:@"default_favicon"];
-
   [[header iconView] setImage:iconImage];
 
   return header;
 }
 
-- (void)setSessionEntries:(NSArray*)sessionEntries {
-  _sessionEntries = sessionEntries;
-
-  std::string previousHost;
-
-  NSMutableArray* sectionArray = [NSMutableArray array];
-  NSMutableArray* partitionedEntries = [NSMutableArray array];
-
-  NSInteger numberOfEntries = [_sessionEntries count];
-  for (NSInteger index = 0; index < numberOfEntries; ++index) {
-    CRWSessionEntry* sessionEntry = [_sessionEntries objectAtIndex:index];
-    web::NavigationItem* navigationItem = [sessionEntry navigationItem];
-
-    std::string currentHost;
-    if (navigationItem)
-      currentHost = navigationItem->GetURL().host();
-
-    if (previousHost.empty())
-      previousHost = currentHost;
-
-    // TODO: This should use some sort of Top Level Domain matching instead of
-    // explicit host match so that images.googe.com matches shopping.google.com.
-    if (previousHost == currentHost) {
-      [sectionArray addObject:sessionEntry];
-    } else {
-      [partitionedEntries addObject:sectionArray];
-      sectionArray = [NSMutableArray arrayWithObject:sessionEntry];
-      previousHost = currentHost;
-    }
-  }
-
-  if ([sectionArray count])
-    [partitionedEntries addObject:sectionArray];
-
-  if (![partitionedEntries count])
-    partitionedEntries = nil;
-
-  _partitionedEntries = partitionedEntries;
-}
-
 #pragma mark MDCInkTouchControllerDelegate
 
 - (BOOL)inkTouchController:(MDCInkTouchController*)inkTouchController
@@ -431,4 +410,22 @@
   return YES;
 }
 
+#pragma mark -
+
+- (const web::NavigationItem*)itemAtIndexPath:(NSIndexPath*)indexPath {
+  size_t section = static_cast<size_t>([indexPath section]);
+  size_t item = static_cast<size_t>([indexPath item]);
+  DCHECK_LT(section, _partitionedItems.size());
+  DCHECK_LT(item, _partitionedItems[section].size());
+  return _partitionedItems[section][item];
+}
+
+- (void)clearNavigationItems {
+  _partitionedItems.clear();
+  for (UICollectionViewCell* cell in self.collectionView.visibleCells) {
+    TabHistoryCell* historyCell = base::mac::ObjCCast<TabHistoryCell>(cell);
+    historyCell.item = nullptr;
+  }
+}
+
 @end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index d449366..659afd7 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -7,7 +7,6 @@
 #import <CoreText/CoreText.h>
 
 #include "base/command_line.h"
-#include "base/ios/ios_util.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/mac/objc_property_releaser.h"
@@ -278,7 +277,7 @@
 }
 
 - (NSTextAlignment)bestTextAlignment {
-  if (!base::ios::IsRunningOnIOS9OrLater() || [self isFirstResponder]) {
+  if ([self isFirstResponder]) {
     return [self bestAlignmentForText:[self text]];
   }
   return NSTextAlignmentNatural;
diff --git a/ios/chrome/browser/ui/preload_controller_delegate.h b/ios/chrome/browser/ui/preload_controller_delegate.h
index e23302e903..46e08c56 100644
--- a/ios/chrome/browser/ui/preload_controller_delegate.h
+++ b/ios/chrome/browser/ui/preload_controller_delegate.h
@@ -7,16 +7,11 @@
 
 #import <UIKit/UIKit.h>
 
-@class CRWSessionEntry;
-
 // A protocol implemented by a delegate of PreloadController
 @protocol PreloadControllerDelegate
 
 // Should preload controller request a desktop site.
 - (BOOL)shouldUseDesktopUserAgent;
-// Return the current sessionEntry from the delegate.
-// TODO(crbug.com/546348): See if this can return a NavigationItem instead.
-- (CRWSessionEntry*)currentSessionEntry;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_PRELOAD_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
index 16732f5..66febd2 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.h
@@ -12,6 +12,7 @@
 #include "ios/chrome/browser/ui/qr_scanner/qr_scanner_view_controller.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_controller_delegate.h"
+#include "ios/web/public/navigation_item_list.h"
 
 @protocol PreloadProvider;
 @class Tab;
@@ -150,7 +151,7 @@
 
 // Shows the tab history popup inside |view|.
 - (void)showTabHistoryPopupInView:(UIView*)view
-               withSessionEntries:(NSArray*)sessionEntries
+                        withItems:(const web::NavigationItemList&)items
                    forBackHistory:(BOOL)isBackHistory;
 
 // Dismisses the tab history popup.
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 498ce10..ee215e35 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -805,7 +805,7 @@
 }
 
 - (void)showTabHistoryPopupInView:(UIView*)view
-               withSessionEntries:(NSArray*)sessionEntries
+                        withItems:(const web::NavigationItemList&)items
                    forBackHistory:(BOOL)isBackHistory {
   if (_tabHistoryPopupController)
     return;
@@ -826,9 +826,15 @@
   _tabHistoryPopupController.reset([[TabHistoryPopupController alloc]
       initWithOrigin:convertedOrigin
           parentView:view
-             entries:sessionEntries]);
+               items:items]);
   [_tabHistoryPopupController setDelegate:self];
 
+  // Fade in the popup and notify observers.
+  CGRect containerFrame = [[_tabHistoryPopupController popupContainer] frame];
+  CGPoint destination = CGPointMake(CGRectGetLeadingEdge(containerFrame),
+                                    CGRectGetMinY(containerFrame));
+  [_tabHistoryPopupController fadeInPopupFromSource:convertedOrigin
+                                      toDestination:destination];
   [[NSNotificationCenter defaultCenter]
       postNotificationName:kTabHistoryPopupWillShowNotification
                     object:nil];
diff --git a/ios/clean/OWNERS b/ios/clean/OWNERS
new file mode 100644
index 0000000..d5d7f59
--- /dev/null
+++ b/ios/clean/OWNERS
@@ -0,0 +1,2 @@
+lpromero@chromium.org
+marq@chromium.org
diff --git a/ios/clean/DEPS b/ios/clean/chrome/DEPS
similarity index 66%
rename from ios/clean/DEPS
rename to ios/clean/chrome/DEPS
index e06ba51..e6eb2ee 100644
--- a/ios/clean/DEPS
+++ b/ios/clean/chrome/DEPS
@@ -5,4 +5,7 @@
   "+ios/shared",
   "+ios/third_party",
   "+ios/web",
+
+  # Strings and resources.
+  "+components/strings/grit",
 ]
diff --git a/ios/clean/chrome/app/steps/launch_to_foreground.mm b/ios/clean/chrome/app/steps/launch_to_foreground.mm
index e8a7247..f8e6950e 100644
--- a/ios/clean/chrome/app/steps/launch_to_foreground.mm
+++ b/ios/clean/chrome/app/steps/launch_to_foreground.mm
@@ -69,7 +69,7 @@
   if (motion == UIEventSubtypeMotionShake) {
     UIApplication* app = [UIApplication sharedApplication];
     [app.delegate application:app
-                      openURL:[NSURL URLWithString:@"https://www.google.com"]
+                      openURL:[NSURL URLWithString:@"chrome://newtab"]
                       options:@{}];
   }
   [super motionEnded:motion withEvent:event];
diff --git a/ios/clean/chrome/browser/ui/ntp/BUILD.gn b/ios/clean/chrome/browser/ui/ntp/BUILD.gn
new file mode 100644
index 0000000..609b8fb2
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/ntp/BUILD.gn
@@ -0,0 +1,36 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("ntp") {
+  sources = [
+    "new_tab_page_coordinator.h",
+    "new_tab_page_coordinator.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":ntp_ui",
+    "//ios/clean/chrome/browser",
+    "//ios/shared/chrome/browser/coordinator_context",
+  ]
+}
+
+source_set("ntp_ui") {
+  sources = [
+    "new_tab_page_view_controller.h",
+    "new_tab_page_view_controller.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    "//base",
+    "//components/strings:components_strings_grit",
+    "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser/ui/ntp:ntp_internal",
+    "//ios/clean/chrome/browser/ui",
+    "//ui/base:base",
+  ]
+}
diff --git a/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h
new file mode 100644
index 0000000..ec6381b9
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_COORDINATOR_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_COORDINATOR_H_
+
+#import <UIKit/UIKit.h>
+#import "ios/clean/chrome/browser/browser_coordinator.h"
+
+// Coordinator that runs a "New Tab Page" : The UI displayed instead of a web
+// page when a new tab is created.
+@interface NTPCoordinator : BrowserCoordinator
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_COORDINATOR_H_
diff --git a/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
new file mode 100644
index 0000000..4e61776
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.mm
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h"
+
+#import "ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h"
+#import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface NTPCoordinator ()
+@property(nonatomic, strong) NTPViewController* viewController;
+@end
+
+@implementation NTPCoordinator
+@synthesize viewController = _viewController;
+
+- (void)start {
+  self.viewController = [[NTPViewController alloc] init];
+  [self.context.baseViewController presentViewController:self.viewController
+                                                animated:self.context.animated
+                                              completion:nil];
+}
+
+@end
diff --git a/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h b/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h
new file mode 100644
index 0000000..c2b5f34
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h
@@ -0,0 +1,14 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_VIEW_CONTROLLER_H_
+#define IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+// View controller that displays a new tab page.
+@interface NTPViewController : UIViewController
+@end
+
+#endif  // IOS_CLEAN_CHROME_BROWSER_UI_NTP_NEW_TAB_PAGE_VIEW_CONTROLLER_H_
diff --git a/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.mm b/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
new file mode 100644
index 0000000..7e9eee5a
--- /dev/null
+++ b/ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.mm
@@ -0,0 +1,79 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/clean/chrome/browser/ui/ntp/new_tab_page_view_controller.h"
+
+#import "base/ios/crb_protocol_observers.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/ntp/new_tab_page_bar.h"
+#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
+#import "ios/chrome/browser/ui/ntp/new_tab_page_controller.h"
+#import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation NTPViewController
+
+#pragma mark - UIViewController
+
+- (void)viewDidLoad {
+  self.title = l10n_util::GetNSString(IDS_NEW_TAB_TITLE);
+  self.view.backgroundColor = [UIColor whiteColor];
+
+  UIScrollView* scrollView = [[UIScrollView alloc] initWithFrame:CGRectZero];
+  [scrollView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth |
+                                   UIViewAutoresizingFlexibleHeight)];
+  scrollView.pagingEnabled = YES;
+  scrollView.showsHorizontalScrollIndicator = NO;
+  scrollView.showsVerticalScrollIndicator = NO;
+  scrollView.contentMode = UIViewContentModeScaleAspectFit;
+  scrollView.bounces = YES;
+  scrollView.scrollsToTop = NO;
+
+  NewTabPageBar* tabBar = [[NewTabPageBar alloc] initWithFrame:CGRectZero];
+  NewTabPageView* ntpView = [[NewTabPageView alloc] initWithFrame:CGRectZero
+                                                    andScrollView:scrollView
+                                                        andTabBar:tabBar];
+  ntpView.translatesAutoresizingMaskIntoConstraints = NO;
+  [self.view addSubview:ntpView];
+
+  [NSLayoutConstraint activateConstraints:@[
+    [ntpView.topAnchor constraintEqualToAnchor:self.view.topAnchor],
+    [ntpView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
+    [ntpView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
+    [ntpView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
+  ]];
+
+  // PLACEHOLDER: this logic should move out of the UIVC.
+  NSString* mostVisited = l10n_util::GetNSString(IDS_IOS_NEW_TAB_MOST_VISITED);
+  NSString* bookmarks =
+      l10n_util::GetNSString(IDS_IOS_NEW_TAB_BOOKMARKS_PAGE_TITLE_MOBILE);
+  NSString* openTabs = l10n_util::GetNSString(IDS_IOS_NEW_TAB_RECENT_TABS);
+
+  NSMutableArray* tabBarItems = [NSMutableArray array];
+
+  NewTabPageBarItem* mostVisitedItem = [NewTabPageBarItem
+      newTabPageBarItemWithTitle:mostVisited
+                      identifier:NewTabPage::kMostVisitedPanel
+                           image:[UIImage imageNamed:@"ntp_mv_search"]];
+  NewTabPageBarItem* bookmarksItem = [NewTabPageBarItem
+      newTabPageBarItemWithTitle:bookmarks
+                      identifier:NewTabPage::kBookmarksPanel
+                           image:[UIImage imageNamed:@"ntp_bookmarks"]];
+  [tabBarItems addObject:bookmarksItem];
+  [tabBarItems addObject:mostVisitedItem];
+
+  NewTabPageBarItem* openTabsItem = [NewTabPageBarItem
+      newTabPageBarItemWithTitle:openTabs
+                      identifier:NewTabPage::kOpenTabsPanel
+                           image:[UIImage imageNamed:@"ntp_opentabs"]];
+  [tabBarItems addObject:openTabsItem];
+  tabBar.items = tabBarItems;
+}
+
+@end
diff --git a/ios/clean/chrome/browser/ui/tab/BUILD.gn b/ios/clean/chrome/browser/ui/tab/BUILD.gn
index 6e256bc..a341ea1 100644
--- a/ios/clean/chrome/browser/ui/tab/BUILD.gn
+++ b/ios/clean/chrome/browser/ui/tab/BUILD.gn
@@ -18,6 +18,7 @@
     "//ios/clean/chrome/browser/ui",
     "//ios/clean/chrome/browser/ui/actions",
     "//ios/clean/chrome/browser/ui/animators",
+    "//ios/clean/chrome/browser/ui/ntp",
     "//ios/clean/chrome/browser/ui/presenters",
     "//ios/clean/chrome/browser/ui/toolbar",
     "//ios/clean/chrome/browser/ui/web_contents",
diff --git a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
index 4afcb23..9139cc9 100644
--- a/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab/tab_coordinator.mm
@@ -15,10 +15,13 @@
 #import "ios/clean/chrome/browser/browser_coordinator+internal.h"
 #import "ios/clean/chrome/browser/ui/actions/tab_grid_actions.h"
 #import "ios/clean/chrome/browser/ui/animators/zoom_transition_animator.h"
+#import "ios/clean/chrome/browser/ui/ntp/new_tab_page_coordinator.h"
 #import "ios/clean/chrome/browser/ui/tab/tab_container_view_controller.h"
 #import "ios/clean/chrome/browser/ui/toolbar/toolbar_coordinator.h"
 #import "ios/clean/chrome/browser/ui/web_contents/web_coordinator.h"
 #import "ios/shared/chrome/browser/coordinator_context/coordinator_context.h"
+#import "ios/web/public/web_state/web_state.h"
+#import "ios/web/public/web_state/web_state_observer_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -30,11 +33,15 @@
 const BOOL kUseBottomToolbar = NO;
 }  // namespace
 
-@interface TabCoordinator ()<UIViewControllerTransitioningDelegate>
+@interface TabCoordinator ()<CRWWebStateObserver,
+                             UIViewControllerTransitioningDelegate>
 @property(nonatomic, strong) TabContainerViewController* viewController;
 @end
 
-@implementation TabCoordinator
+@implementation TabCoordinator {
+  std::unique_ptr<web::WebStateObserverBridge> _webStateObserver;
+}
+
 @synthesize presentationKey = _presentationKey;
 @synthesize viewController = _viewController;
 @synthesize webState = _webState;
@@ -43,6 +50,8 @@
   self.viewController = [self newTabContainer];
   self.viewController.transitioningDelegate = self;
   self.viewController.modalPresentationStyle = UIModalPresentationCustom;
+  _webStateObserver =
+      base::MakeUnique<web::WebStateObserverBridge>(self.webState, self);
 
   WebCoordinator* webCoordinator = [[WebCoordinator alloc] init];
   webCoordinator.webState = self.webState;
@@ -87,6 +96,7 @@
   [self.viewController.presentingViewController
       dismissViewControllerAnimated:self.context.animated
                          completion:nil];
+  _webStateObserver.reset();
 }
 
 - (BOOL)canAddOverlayCoordinator:(BrowserCoordinator*)overlayCoordinator {
@@ -106,6 +116,21 @@
   return [[TopToolbarTabViewController alloc] init];
 }
 
+#pragma mark - CRWWebStateObserver
+
+// This will eventually be called in -didFinishNavigation and perhaps as an
+// optimization in some equivalent to loadURL.
+- (void)webState:(web::WebState*)webState
+    didCommitNavigationWithDetails:(const web::LoadCommittedDetails&)details {
+  if (webState->GetLastCommittedURL() == GURL("chrome://newtab/")) {
+    NTPCoordinator* ntpCoordinator = [[NTPCoordinator alloc] init];
+    [self addChildCoordinator:ntpCoordinator];
+    ntpCoordinator.context.baseViewController = nil;
+    [ntpCoordinator start];
+    self.viewController.contentViewController = ntpCoordinator.viewController;
+  }
+}
+
 #pragma mark - UIViewControllerTransitioningDelegate
 
 - (id<UIViewControllerAnimatedTransitioning>)
diff --git a/ios/web/navigation/crw_session_certificate_policy_manager.h b/ios/web/navigation/crw_session_certificate_policy_manager.h
index 72553c1..2d33f388 100644
--- a/ios/web/navigation/crw_session_certificate_policy_manager.h
+++ b/ios/web/navigation/crw_session_certificate_policy_manager.h
@@ -11,8 +11,6 @@
 #include "base/memory/ref_counted.h"
 #include "net/cert/cert_status_flags.h"
 
-@class CRWSessionEntry;
-
 namespace net {
 class X509Certificate;
 }
diff --git a/ios/web/navigation/navigation_item_storage_builder.mm b/ios/web/navigation/navigation_item_storage_builder.mm
index 1b166724..286501c 100644
--- a/ios/web/navigation/navigation_item_storage_builder.mm
+++ b/ios/web/navigation/navigation_item_storage_builder.mm
@@ -34,7 +34,12 @@
 NavigationItemStorageBuilder::BuildNavigationItemImpl(
     CRWNavigationItemStorage* navigation_item_storage) const {
   std::unique_ptr<NavigationItemImpl> item(new web::NavigationItemImpl());
-  item->virtual_url_ = navigation_item_storage.virtualURL;
+  // While the virtual URL is persisted, we still need the original request URL
+  // and the non-virtual URL to be set upon NavigationItem creation.  Since
+  // GetVirtualURL() returns |url_| for the non-overridden case, this will also
+  // update the virtual URL reported by this object.
+  item->original_request_url_ = navigation_item_storage.virtualURL;
+  item->url_ = navigation_item_storage.virtualURL;
   item->referrer_ = navigation_item_storage.referrer;
   item->timestamp_ = navigation_item_storage.timestamp;
   item->title_ = navigation_item_storage.title;
diff --git a/ios/web/payments/payment_request.cc b/ios/web/payments/payment_request.cc
index fdfdb56c..5d56b31 100644
--- a/ios/web/payments/payment_request.cc
+++ b/ios/web/payments/payment_request.cc
@@ -32,8 +32,10 @@
 static const char kMethodData[] = "methodData";
 static const char kMethodDataData[] = "data";
 static const char kMethodName[] = "methodName";
-static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
 static const char kPaymentCurrencyAmountCurrency[] = "currency";
+static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
+static const char kPaymentCurrencyAmountCurrencySystemISO4217[] =
+    "urn:iso:std:iso:4217";
 static const char kPaymentCurrencyAmountValue[] = "value";
 static const char kPaymentDetails[] = "details";
 static const char kPaymentDetailsDisplayItems[] = "displayItems";
@@ -43,6 +45,14 @@
 static const char kPaymentItemAmount[] = "amount";
 static const char kPaymentItemLabel[] = "label";
 static const char kPaymentItemPending[] = "pending";
+static const char kPaymentOptions[] = "options";
+static const char kPaymentOptionsRequestPayerEmail[] = "requestPayerEmail";
+static const char kPaymentOptionsRequestPayerName[] = "requestPayerName";
+static const char kPaymentOptionsRequestPayerPhone[] = "requestPayerPhone";
+static const char kPaymentOptionsRequestShipping[] = "requestShipping";
+static const char kPaymentOptionsShippingType[] = "shippingType";
+static const char kPaymentOptionsShippingTypeDelivery[] = "delivery";
+static const char kPaymentOptionsShippingTypePickup[] = "pickup";
 static const char kPaymentShippingOptionAmount[] = "amount";
 static const char kPaymentShippingOptionId[] = "id";
 static const char kPaymentShippingOptionLabel[] = "label";
@@ -149,9 +159,10 @@
 }
 
 PaymentCurrencyAmount::PaymentCurrencyAmount()
-    // By default, the value is urn:iso:std:iso:4217 indicating that currency is
-    // defined by [ISO4217] (for example, USD for US Dollars).
-    : currency_system(base::ASCIIToUTF16("urn:iso:std:iso:4217")) {}
+    // By default, the currency is defined by [ISO4217]. For example, USD for
+    // US Dollars.
+    : currency_system(
+          base::ASCIIToUTF16(kPaymentCurrencyAmountCurrencySystemISO4217)) {}
 
 PaymentCurrencyAmount::~PaymentCurrencyAmount() = default;
 
@@ -334,21 +345,51 @@
 }
 
 PaymentOptions::PaymentOptions()
-    : request_payer_email(false),
+    : request_payer_name(false),
+      request_payer_email(false),
       request_payer_phone(false),
-      request_shipping(false) {}
+      request_shipping(false),
+      shipping_type(PaymentShippingType::SHIPPING) {}
 PaymentOptions::~PaymentOptions() = default;
 
 bool PaymentOptions::operator==(const PaymentOptions& other) const {
-  return this->request_payer_email == other.request_payer_email &&
+  return this->request_payer_name == other.request_payer_name &&
+         this->request_payer_email == other.request_payer_email &&
          this->request_payer_phone == other.request_payer_phone &&
-         this->request_shipping == other.request_shipping;
+         this->request_shipping == other.request_shipping &&
+         this->shipping_type == other.shipping_type;
 }
 
 bool PaymentOptions::operator!=(const PaymentOptions& other) const {
   return !(*this == other);
 }
 
+bool PaymentOptions::FromDictionaryValue(const base::DictionaryValue& value) {
+  value.GetBoolean(kPaymentOptionsRequestPayerName, &this->request_payer_name);
+
+  value.GetBoolean(kPaymentOptionsRequestPayerEmail,
+                   &this->request_payer_email);
+
+  value.GetBoolean(kPaymentOptionsRequestPayerPhone,
+                   &this->request_payer_phone);
+
+  value.GetBoolean(kPaymentOptionsRequestShipping, &this->request_shipping);
+
+  base::string16 shipping_type;
+  value.GetString(kPaymentOptionsShippingType, &shipping_type);
+  if (shipping_type ==
+      base::ASCIIToUTF16(kPaymentOptionsShippingTypeDelivery)) {
+    this->shipping_type = PaymentShippingType::DELIVERY;
+  } else if (shipping_type ==
+             base::ASCIIToUTF16(kPaymentOptionsShippingTypePickup)) {
+    this->shipping_type = PaymentShippingType::PICKUP;
+  } else {
+    this->shipping_type = PaymentShippingType::SHIPPING;
+  }
+
+  return true;
+}
+
 PaymentRequest::PaymentRequest() {}
 PaymentRequest::PaymentRequest(const PaymentRequest& other) = default;
 PaymentRequest::~PaymentRequest() = default;
@@ -387,11 +428,17 @@
 
   // Parse the payment details.
   const base::DictionaryValue* payment_details_dict = nullptr;
-  if (value.GetDictionary(kPaymentDetails, &payment_details_dict))
-    if (!this->details.FromDictionaryValue(*payment_details_dict))
-      return false;
+  if (!value.GetDictionary(kPaymentDetails, &payment_details_dict) ||
+      !this->details.FromDictionaryValue(*payment_details_dict)) {
+    return false;
+  }
 
-  // TODO(crbug.com/602666): Parse the remaining elements.
+  // Parse the payment options.
+  const base::DictionaryValue* payment_options = nullptr;
+  // Options field is optional.
+  if (value.GetDictionary(kPaymentOptions, &payment_options))
+    if (!this->options.FromDictionaryValue(*payment_options))
+      return false;
 
   return true;
 }
diff --git a/ios/web/payments/payment_request_unittest.cc b/ios/web/payments/payment_request_unittest.cc
index 44962be..529c8590 100644
--- a/ios/web/payments/payment_request_unittest.cc
+++ b/ios/web/payments/payment_request_unittest.cc
@@ -236,6 +236,11 @@
   base::DictionaryValue request_dict;
 
   // Add the expected values to expected_request.
+  expected_request.details.total.label = base::ASCIIToUTF16("TOTAL");
+  expected_request.details.total.amount.currency = base::ASCIIToUTF16("GBP");
+  expected_request.details.total.amount.value = base::ASCIIToUTF16("6.66");
+  expected_request.details.error = base::ASCIIToUTF16("Error in details");
+
   PaymentMethodData method_data;
   std::vector<base::string16> supported_methods;
   supported_methods.push_back(base::ASCIIToUTF16("Visa"));
@@ -243,6 +248,18 @@
   expected_request.method_data.push_back(method_data);
 
   // Add the same values to the dictionary to be parsed.
+  std::unique_ptr<base::DictionaryValue> details_dict(
+      new base::DictionaryValue);
+  std::unique_ptr<base::DictionaryValue> total_dict(new base::DictionaryValue);
+  total_dict->SetString("label", "TOTAL");
+  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
+  amount_dict->SetString("currency", "GBP");
+  amount_dict->SetString("value", "6.66");
+  total_dict->Set("amount", std::move(amount_dict));
+  details_dict->Set("total", std::move(total_dict));
+  details_dict->SetString("error", "Error in details");
+  request_dict.Set("details", std::move(details_dict));
+
   std::unique_ptr<base::ListValue> method_data_list(new base::ListValue);
   std::unique_ptr<base::DictionaryValue> method_data_dict(
       new base::DictionaryValue);
@@ -256,23 +273,19 @@
   EXPECT_TRUE(output_request.FromDictionaryValue(request_dict));
   EXPECT_EQ(expected_request, output_request);
 
-  // If payment details are present, parse those as well.
-  expected_request.details.total.label = base::ASCIIToUTF16("TOTAL");
-  expected_request.details.total.amount.currency = base::ASCIIToUTF16("GBP");
-  expected_request.details.total.amount.value = base::ASCIIToUTF16("6.66");
-  expected_request.details.error = base::ASCIIToUTF16("Error in details");
-
-  std::unique_ptr<base::DictionaryValue> details_dict(
+  // If payment options are present, parse those as well.
+  std::unique_ptr<base::DictionaryValue> options_dict(
       new base::DictionaryValue);
-  std::unique_ptr<base::DictionaryValue> total_dict(new base::DictionaryValue);
-  total_dict->SetString("label", "TOTAL");
-  std::unique_ptr<base::DictionaryValue> amount_dict(new base::DictionaryValue);
-  amount_dict->SetString("currency", "GBP");
-  amount_dict->SetString("value", "6.66");
-  total_dict->Set("amount", std::move(amount_dict));
-  details_dict->Set("total", std::move(total_dict));
-  details_dict->SetString("error", "Error in details");
-  request_dict.Set("details", std::move(details_dict));
+  options_dict->SetBoolean("requestPayerPhone", true);
+  options_dict->SetBoolean("requestShipping", true);
+  options_dict->SetString("shippingType", "delivery");
+  request_dict.Set("options", std::move(options_dict));
+
+  PaymentOptions payment_options;
+  payment_options.request_payer_phone = true;
+  payment_options.request_shipping = true;
+  payment_options.shipping_type = PaymentShippingType::DELIVERY;
+  expected_request.options = payment_options;
 
   EXPECT_TRUE(output_request.FromDictionaryValue(request_dict));
   EXPECT_EQ(expected_request, output_request);
@@ -647,6 +660,11 @@
   PaymentOptions options2;
   EXPECT_EQ(options1, options2);
 
+  options1.request_payer_name = true;
+  EXPECT_NE(options1, options2);
+  options2.request_payer_name = true;
+  EXPECT_EQ(options1, options2);
+
   options1.request_payer_email = true;
   EXPECT_NE(options1, options2);
   options2.request_payer_email = true;
@@ -661,6 +679,14 @@
   EXPECT_NE(options1, options2);
   options2.request_shipping = true;
   EXPECT_EQ(options1, options2);
+
+  // PaymentShippingType::SHIPPING is the default value for shipping_type.
+  options1.shipping_type = PaymentShippingType::SHIPPING;
+  EXPECT_EQ(options1, options2);
+  options1.shipping_type = PaymentShippingType::PICKUP;
+  EXPECT_NE(options1, options2);
+  options2.shipping_type = PaymentShippingType::PICKUP;
+  EXPECT_EQ(options1, options2);
 }
 
 // Tests that two payment request objects are not equal if their property values
diff --git a/ios/web/public/payments/payment_request.h b/ios/web/public/payments/payment_request.h
index c2a8baa..a12c289 100644
--- a/ios/web/public/payments/payment_request.h
+++ b/ios/web/public/payments/payment_request.h
@@ -248,6 +248,14 @@
   base::string16 error;
 };
 
+// Possible values for affecting the payment request user interface for
+// gathering the shipping address.
+enum class PaymentShippingType : int {
+  SHIPPING = 0,
+  DELIVERY = 1,
+  PICKUP = 2,
+};
+
 // Information describing a shipping option.
 class PaymentOptions {
  public:
@@ -257,6 +265,15 @@
   bool operator==(const PaymentOptions& other) const;
   bool operator!=(const PaymentOptions& other) const;
 
+  // Populates the properties of this PaymentOptions from |value|. Returns true
+  // if the required values are present.
+  bool FromDictionaryValue(const base::DictionaryValue& value);
+
+  // Indicates whether the user agent should collect and return the payer's name
+  // as part of the payment request. For example, this would be set to true to
+  // allow a merchant to make a booking in the payer's name.
+  bool request_payer_name;
+
   // Indicates whether the user agent should collect and return the payer's
   // email address as part of the payment request. For example, this would be
   // set to true to allow a merchant to email a receipt.
@@ -273,6 +290,11 @@
   // This would be set to false for an online-only electronic purchase
   // transaction.
   bool request_shipping;
+
+  // If request_shipping is set to true, then this field may only be used to
+  // influence the way the user agent presents the user interface for gathering
+  // the shipping address.
+  PaymentShippingType shipping_type;
 };
 
 // All of the information provided by a page making a request for payment.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index bfcc3f98..45a5e8b 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2006,6 +2006,11 @@
     _containerView.get().frame = containerViewFrame;
     DCHECK(!CGRectIsEmpty(_containerView.get().frame));
 
+    // TODO(crbug.com/691116): Remove this workaround once tests are no longer
+    // dependent upon this accessibility ID.
+    if (!base::ios::IsRunningOnIOS10OrLater())
+      [_containerView setAccessibilityIdentifier:@"Container View"];
+
     [_containerView addGestureRecognizer:[self touchTrackingRecognizer]];
     // Is |currentUrl| a web scheme or native chrome scheme.
     web::NavigationItem* item = [self currentNavItem];
diff --git a/mash/simple_wm/simple_wm.cc b/mash/simple_wm/simple_wm.cc
index b8f98a75..e8c4b45 100644
--- a/mash/simple_wm/simple_wm.cc
+++ b/mash/simple_wm/simple_wm.cc
@@ -46,7 +46,7 @@
   }
   ~WindowListModel() override {
     window_container_->RemoveObserver(this);
-    for (auto window : windows_)
+    for (auto* window : windows_)
       window->RemoveObserver(this);
   }
 
diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc
index 47f3ec84..3906b70 100644
--- a/media/audio/audio_manager.cc
+++ b/media/audio/audio_manager.cc
@@ -11,9 +11,6 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
-#include "base/debug/alias.h"
-#include "base/debug/crash_logging.h"
-#include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
@@ -101,8 +98,6 @@
   const std::string& app_name() const { return app_name_; }
 #endif
 
-  void enable_crash_key_logging() { enable_crash_key_logging_ = true; }
-
  private:
   // base::PowerObserver overrides.
   // Disable hang detection when the system goes into the suspend state.
@@ -159,8 +154,6 @@
         successful_pings_ = 0;
         if (++failed_pings_ >= kMaxFailedPingsCount &&
             audio_thread_status_ < THREAD_HUNG) {
-          if (enable_crash_key_logging_)
-            LogAudioDriverCrashKeys();
           HistogramThreadStatus(THREAD_HUNG);
         }
       } else {
@@ -215,25 +208,6 @@
                               THREAD_MAX + 1);
   }
 
-  void LogAudioDriverCrashKeys() {
-    DCHECK(monitor_task_runner_->BelongsToCurrentThread());
-    DCHECK(enable_crash_key_logging_);
-
-#if defined(OS_WIN)
-    std::string driver_name, driver_version;
-    if (!CoreAudioUtil::GetDxDiagDetails(&driver_name, &driver_version))
-      return;
-
-    base::debug::ScopedCrashKey crash_key(
-        "hung-audio-thread-details",
-        base::StringPrintf("%s:%s", driver_name.c_str(),
-                           driver_version.c_str()));
-
-    // Please forward crash reports to http://crbug.com/422522
-    base::debug::DumpWithoutCrashing();
-#endif
-  }
-
   FakeAudioLogFactory fake_log_factory_;
 
   const base::TimeDelta max_hung_task_time_ = base::TimeDelta::FromMinutes(1);
@@ -247,7 +221,6 @@
   bool io_task_running_ = false;
   bool audio_task_running_ = false;
   ThreadStatus audio_thread_status_ = THREAD_NONE;
-  bool enable_crash_key_logging_ = false;
   uint32_t successful_pings_ = 0;
 
 #if defined(OS_WIN)
@@ -363,12 +336,6 @@
   GetHelper()->StartHangTimer(std::move(task_runner));
 }
 
-// static
-void AudioManager::EnableCrashKeyLoggingForAudioThreadHangs() {
-  CHECK(!g_last_created);
-  GetHelper()->enable_crash_key_logging();
-}
-
 #if defined(OS_LINUX)
 // static
 void AudioManager::SetGlobalAppName(const std::string& app_name) {
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h
index 2826bcd..613df4d 100644
--- a/media/audio/audio_manager.h
+++ b/media/audio/audio_manager.h
@@ -39,9 +39,7 @@
 // the need to provide iterators over the existing streams.
 //
 // Except on OSX, a hang monitor for the audio thread is always created. When a
-// thread hang is detected, it is reported to UMA.  Optionally, if called prior,
-// EnableCrashKeyLoggingForAudioThreadHangs() will cause a non-crash dump to be
-// logged on Windows (this allows us to report driver hangs to Microsoft).
+// thread hang is detected, it is reported to UMA.
 class MEDIA_EXPORT AudioManager {
  public:
   // Construct the audio manager; only one instance is allowed.
@@ -77,13 +75,6 @@
   static void StartHangMonitorIfNeeded(
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
-  // Enables non-crash dumps when audio thread hangs are detected.
-  // TODO(dalecurtis): There are no callers to this function at present. A list
-  // of bad drivers has been given to Microsoft. This should be re-enabled in
-  // the future if Microsoft is able to triage third party drivers.
-  // See http://crbug.com/422522
-  static void EnableCrashKeyLoggingForAudioThreadHangs();
-
 #if defined(OS_LINUX)
   // Sets the name of the audio source as seen by external apps. Only actually
   // used with PulseAudio as of this writing.
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 098adc6..b629cada 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -264,6 +264,7 @@
   allow_circular_includes_from = []
   defines = []
   public_deps = [
+    "//media/base:video_facing",
     "//ppapi/features",
     "//ui/gfx:color_space",
   ]
@@ -337,6 +338,19 @@
   }
 }
 
+source_set("video_facing") {
+  visibility = [
+    "//chromeos",
+    "//content/browser",
+    "//content/public/common:common_sources",
+    "//media/base",
+    "//media/capture",
+  ]
+  sources = [
+    "video_facing.h",
+  ]
+}
+
 static_library("test_support") {
   testonly = true
   sources = [
diff --git a/media/base/mime_util.cc b/media/base/mime_util.cc
index ba5905d..b21b045 100644
--- a/media/base/mime_util.cc
+++ b/media/base/mime_util.cc
@@ -29,10 +29,10 @@
   return GetMimeUtil()->IsSupportedMediaFormat(mime_type, codecs, true);
 }
 
-void ParseCodecString(const std::string& codecs,
-                      std::vector<std::string>* codecs_out,
-                      bool strip) {
-  GetMimeUtil()->ParseCodecString(codecs, codecs_out, strip);
+void SplitCodecsToVector(const std::string& codecs,
+                         std::vector<std::string>* codecs_out,
+                         bool strip) {
+  GetMimeUtil()->SplitCodecsToVector(codecs, codecs_out, strip);
 }
 
 void RemoveProprietaryMediaTypesAndCodecsForTests() {
diff --git a/media/base/mime_util.h b/media/base/mime_util.h
index 6a49eba..d7a39f4 100644
--- a/media/base/mime_util.h
+++ b/media/base/mime_util.h
@@ -16,14 +16,14 @@
 // supported/recognized MIME types.
 MEDIA_EXPORT bool IsSupportedMediaMimeType(const std::string& mime_type);
 
-// Parses a codec string, populating |codecs_out| with the prefix of each codec
-// in the string |codecs_in|. For example, passed "aaa.b.c,dd.eee", if
+// Splits various codecs into |codecs_out|, conditionally stripping the profile
+// and level info when |strip| == true. For example, passed "aaa.b.c,dd.eee", if
 // |strip| == true |codecs_out| will contain {"aaa", "dd"}, if |strip| == false
 // |codecs_out| will contain {"aaa.b.c", "dd.eee"}.
 // See http://www.ietf.org/rfc/rfc4281.txt.
-MEDIA_EXPORT void ParseCodecString(const std::string& codecs,
-                                   std::vector<std::string>* codecs_out,
-                                   bool strip);
+MEDIA_EXPORT void SplitCodecsToVector(const std::string& codecs,
+                                      std::vector<std::string>* codecs_out,
+                                      bool strip);
 
 // Indicates that the MIME type and (possible codec string) are supported.
 enum SupportsType {
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index 7370198..2172a63 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -4,6 +4,8 @@
 
 #include "media/base/mime_util_internal.h"
 
+#include <map>
+
 #include "base/command_line.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
@@ -23,17 +25,11 @@
 namespace media {
 namespace internal {
 
-struct CodecIDMappings {
-  const char* const codec_id;
-  MimeUtil::Codec codec;
-};
-
-// List of codec IDs that provide enough information to determine the
-// codec and profile being requested.
-//
-// The "mp4a" strings come from RFC 6381.
-static const CodecIDMappings kUnambiguousCodecStringMap[] = {
-    {"1", MimeUtil::PCM},  // We only allow this for WAV so it isn't ambiguous.
+// Wrapped to avoid static initializer startup cost.
+const std::map<std::string, MimeUtil::Codec>& GetStringToCodecMap() {
+  static const std::map<std::string, MimeUtil::Codec> kStringToCodecMap = {
+    // We only allow this for WAV so it isn't ambiguous.
+    {"1", MimeUtil::PCM},
     // avc1/avc3.XXXXXX may be unambiguous; handled by ParseAVCCodecId().
     // hev1/hvc1.XXXXXX may be unambiguous; handled by ParseHEVCCodecID().
     // vp9, vp9.0, vp09.xx.xx.xx.xx.xx.xx.xx may be unambiguous; handled by
@@ -48,8 +44,8 @@
     //   mp4a.40.2   - MPEG-4 AAC LC
     //   mp4a.40.02  - MPEG-4 AAC LC (leading 0 in aud-oti for compatibility)
     //   mp4a.40.5   - MPEG-4 HE-AAC v1 (AAC LC + SBR)
-    //   mp4a.40.05  - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti for
-    //                 compatibility)
+    //   mp4a.40.05  - MPEG-4 HE-AAC v1 (AAC LC + SBR) (leading 0 in aud-oti
+    //                 for compatibility)
     //   mp4a.40.29  - MPEG-4 HE-AAC v2 (AAC LC + SBR + PS)
     {"mp4a.66", MimeUtil::MPEG2_AAC},
     {"mp4a.67", MimeUtil::MPEG2_AAC},
@@ -63,10 +59,10 @@
     {"mp4a.40.29", MimeUtil::MPEG4_AAC},
 #if BUILDFLAG(ENABLE_AC3_EAC3_AUDIO_DEMUXING)
     // TODO(servolk): Strictly speaking only mp4a.A5 and mp4a.A6 codec ids are
-    // valid according to RFC 6381 section 3.3, 3.4. Lower-case oti (mp4a.a5 and
-    // mp4a.a6) should be rejected. But we used to allow those in older versions
-    // of Chromecast firmware and some apps (notably MPL) depend on those codec
-    // types being supported, so they should be allowed for now
+    // valid according to RFC 6381 section 3.3, 3.4. Lower-case oti (mp4a.a5
+    // and mp4a.a6) should be rejected. But we used to allow those in older
+    // versions of Chromecast firmware and some apps (notably MPL) depend on
+    // those codec types being supported, so they should be allowed for now
     // (crbug.com/564960).
     {"ac-3", MimeUtil::AC3},
     {"mp4a.a5", MimeUtil::AC3},
@@ -80,18 +76,11 @@
     {"flac", MimeUtil::FLAC},
     {"vp8", MimeUtil::VP8},
     {"vp8.0", MimeUtil::VP8},
-    {"theora", MimeUtil::THEORA}};
+    {"theora", MimeUtil::THEORA}
+  };
 
-// List of codec IDs that are ambiguous and don't provide
-// enough information to determine the codec and profile.
-// The codec in these entries indicate the codec and profile
-// we assume the user is trying to indicate.
-static const CodecIDMappings kAmbiguousCodecStringMap[] = {
-    {"mp4a.40", MimeUtil::MPEG4_AAC},
-    {"avc1", MimeUtil::H264},
-    {"avc3", MimeUtil::H264},
-    // avc1/avc3.XXXXXX may be ambiguous; handled by ParseAVCCodecId().
-};
+  return kStringToCodecMap;
+}
 
 static bool ParseVp9CodecID(const std::string& mime_type_lower_case,
                             const std::string& codec_id,
@@ -164,36 +153,56 @@
     bool is_encrypted) const {
   DCHECK(!supported_codecs.empty());
   DCHECK(!codecs.empty());
+  DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
 
-  SupportsType result = IsSupported;
+  SupportsType combined_result = IsSupported;
+
   for (size_t i = 0; i < codecs.size(); ++i) {
-    bool is_ambiguous = true;
+    // Parse the string.
+    bool ambiguous_codec_string = false;
     Codec codec = INVALID_CODEC;
     VideoCodecProfile video_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
     uint8_t video_level = 0;
-    if (!StringToCodec(mime_type_lower_case, codecs[i], &codec, &is_ambiguous,
-                       &video_profile, &video_level, is_encrypted)) {
+    if (!ParseCodecString(mime_type_lower_case, codecs[i], &codec,
+                          &ambiguous_codec_string, &video_profile,
+                          &video_level)) {
       return IsNotSupported;
     }
 
-    VideoCodec video_codec = MimeUtilToVideoCodec(codec);
-
-    if (GetMediaClient() && video_codec != kUnknownVideoCodec &&
-        !GetMediaClient()->IsSupportedVideoConfig(video_codec, video_profile,
-                                                  video_level)) {
+    // Bail if codec not in supported list for given container.
+    if (supported_codecs.find(codec) == supported_codecs.end())
       return IsNotSupported;
+
+    // Make conservative guesses to resolve ambiguity before checking platform
+    // support. H264 and VP9 are the only allowed ambiguous video codec. DO NOT
+    // ADD SUPPORT FOR MORE AMIBIGUOUS STRINGS.
+    if (codec == MimeUtil::H264 && ambiguous_codec_string) {
+      if (video_profile == VIDEO_CODEC_PROFILE_UNKNOWN)
+        video_profile = H264PROFILE_BASELINE;
+      if (!IsValidH264Level(video_level))
+        video_level = 10;
+    } else if (codec == MimeUtil::VP9 && video_level == 0) {
+      // Original VP9 content type (codecs="vp9") does not specify the level.
+      // TODO(chcunningham): Mark this string as ambiguous when new multi-part
+      // VP9 content type is published.
+      video_level = 10;
     }
 
-    if (!IsCodecSupported(codec, mime_type_lower_case, is_encrypted) ||
-        supported_codecs.find(codec) == supported_codecs.end()) {
+    // Check platform support.
+    SupportsType result = IsCodecSupported(
+        mime_type_lower_case, codec, video_profile, video_level, is_encrypted);
+    if (result == IsNotSupported)
       return IsNotSupported;
-    }
 
-    if (is_ambiguous)
-      result = MayBeSupported;
+    // If any codec is "MayBeSupported", return Maybe for the combined result.
+    // Downgrade to MayBeSupported if we had to guess the meaning of one of the
+    // codec strings.
+    if (result == MayBeSupported ||
+        (result == IsSupported && ambiguous_codec_string))
+      combined_result = MayBeSupported;
   }
 
-  return result;
+  return combined_result;
 }
 
 void MimeUtil::InitializeMimeTypeMaps() {
@@ -201,16 +210,6 @@
   allow_proprietary_codecs_ = true;
 #endif
 
-  for (size_t i = 0; i < arraysize(kUnambiguousCodecStringMap); ++i) {
-    string_to_codec_map_[kUnambiguousCodecStringMap[i].codec_id] =
-        CodecEntry(kUnambiguousCodecStringMap[i].codec, false);
-  }
-
-  for (size_t i = 0; i < arraysize(kAmbiguousCodecStringMap); ++i) {
-    string_to_codec_map_[kAmbiguousCodecStringMap[i].codec_id] =
-        CodecEntry(kAmbiguousCodecStringMap[i].codec, true);
-  }
-
   AddSupportedMediaFormats();
 }
 
@@ -339,9 +338,9 @@
          media_format_map_.end();
 }
 
-void MimeUtil::ParseCodecString(const std::string& codecs,
-                                std::vector<std::string>* codecs_out,
-                                bool strip) {
+void MimeUtil::SplitCodecsToVector(const std::string& codecs,
+                                   std::vector<std::string>* codecs_out,
+                                   bool strip) {
   *codecs_out =
       base::SplitString(base::TrimString(codecs, "\"", base::TRIM_ALL), ",",
                         base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
@@ -374,10 +373,11 @@
 
   if (it_media_format_map->second.empty()) {
     // We get here if the mimetype does not expect a codecs parameter.
-    return (codecs.empty() && IsDefaultCodecSupportedLowerCase(
-                                  mime_type_lower_case, is_encrypted))
-               ? IsSupported
-               : IsNotSupported;
+    if (codecs.empty()) {
+      return IsDefaultCodecSupported(mime_type_lower_case, is_encrypted);
+    } else {
+      return IsNotSupported;
+    }
   }
 
   if (codecs.empty()) {
@@ -386,12 +386,11 @@
     // codec the best we can do is say "maybe" because we don't have enough
     // information.
     Codec default_codec = INVALID_CODEC;
-    if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
+    if (!GetDefaultCodec(mime_type_lower_case, &default_codec))
       return MayBeSupported;
 
-    return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted)
-               ? IsSupported
-               : IsNotSupported;
+    return IsSimpleCodecSupported(mime_type_lower_case, default_codec,
+                                  is_encrypted);
   }
 
 #if BUILDFLAG(ENABLE_MSE_MPEG2TS_STREAM_PARSER)
@@ -416,7 +415,7 @@
 }
 
 // static
-bool MimeUtil::IsCodecSupportedOnPlatform(
+bool MimeUtil::IsCodecSupportedOnAndroid(
     Codec codec,
     const std::string& mime_type_lower_case,
     bool is_encrypted,
@@ -542,99 +541,156 @@
   return false;
 }
 
-bool MimeUtil::StringToCodec(const std::string& mime_type_lower_case,
-                             const std::string& codec_id,
-                             Codec* codec,
-                             bool* is_ambiguous,
-                             VideoCodecProfile* out_profile,
-                             uint8_t* out_level,
-                             bool is_encrypted) const {
+bool MimeUtil::ParseCodecString(const std::string& mime_type_lower_case,
+                                const std::string& codec_id,
+                                Codec* codec,
+                                bool* ambiguous_codec_string,
+                                VideoCodecProfile* out_profile,
+                                uint8_t* out_level) const {
+  DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
+  DCHECK(codec);
   DCHECK(out_profile);
   DCHECK(out_level);
+
+  *codec = INVALID_CODEC;
+  *ambiguous_codec_string = false;
   *out_profile = VIDEO_CODEC_PROFILE_UNKNOWN;
   *out_level = 0;
 
-  StringToCodecMappings::const_iterator itr =
-      string_to_codec_map_.find(codec_id);
-  if (itr != string_to_codec_map_.end()) {
-    *codec = itr->second.codec;
-    *is_ambiguous = itr->second.is_ambiguous;
+  std::map<std::string, Codec>::const_iterator itr =
+      GetStringToCodecMap().find(codec_id);
+  if (itr != GetStringToCodecMap().end()) {
+    *codec = itr->second;
+
     return true;
   }
 
-  // If |codec_id| is not in |string_to_codec_map_|, then we assume that it is
+  // Check codec string against short list of allowed ambiguous codecs.
+  // Hard-coded to discourage expansion. DO NOT ADD TO THIS LIST. DO NOT
+  // INCREASE PLACES WHERE |ambiguous_codec_string| = true.
+  // NOTE: avc1/avc3.XXXXXX may be ambiguous handled after ParseAVCCodecId().
+  if (codec_id == "avc1" || codec_id == "avc3") {
+    *codec = MimeUtil::H264;
+    *ambiguous_codec_string = true;
+    return true;
+  } else if (codec_id == "mp4a.40") {
+    *codec = MimeUtil::MPEG4_AAC;
+    *ambiguous_codec_string = true;
+    return true;
+  }
+
+  // If |codec_id| is not in |kStringToCodecMap|, then we assume that it is
   // either VP9, H.264 or HEVC/H.265 codec ID because currently those are the
-  // only ones that are not added to the |string_to_codec_map_| and require
+  // only ones that are not added to the |kStringToCodecMap| and require
   // parsing.
   if (ParseVp9CodecID(mime_type_lower_case, codec_id, out_profile, out_level)) {
     *codec = MimeUtil::VP9;
-    switch (*out_profile) {
-      case VP9PROFILE_PROFILE0:
-        // Profile 0 should always be supported if VP9 is supported.
-        *is_ambiguous = false;
-        break;
-      default:
-        // We don't know if the underlying platform supports these profiles.
-        // Need to add platform level querying to get supported profiles
-        // (crbug/604566).
-        *is_ambiguous = true;
-        break;
-    }
     return true;
   }
 
   if (ParseAVCCodecId(codec_id, out_profile, out_level)) {
     *codec = MimeUtil::H264;
-    switch (*out_profile) {
-// HIGH10PROFILE is supported through fallback to the ffmpeg decoder
-// which is not available on Android, or if FFMPEG is not used.
-#if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID)
-      case H264PROFILE_HIGH10PROFILE:
-        if (is_encrypted) {
-          // FFmpeg is not generally used for encrypted videos, so we do not
-          // know whether 10-bit is supported.
-          *is_ambiguous = true;
-          break;
-        }
-// Fall through.
-#endif
-
-      case H264PROFILE_BASELINE:
-      case H264PROFILE_MAIN:
-      case H264PROFILE_HIGH:
-        *is_ambiguous = !IsValidH264Level(*out_level);
-        break;
-      default:
-        *is_ambiguous = true;
-    }
+    // Allowed string ambiguity since 2014. DO NOT ADD NEW CASES FOR AMBIGUITY.
+    *ambiguous_codec_string = !IsValidH264Level(*out_level);
     return true;
   }
 
 #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
   if (ParseHEVCCodecId(codec_id, out_profile, out_level)) {
     *codec = MimeUtil::HEVC;
-    *is_ambiguous = false;
     return true;
   }
 #endif
 
-  DVLOG(4) << __func__ << ": Unrecognized codec id " << codec_id;
+  DVLOG(2) << __func__ << ": Unrecognized codec id " << codec_id;
   return false;
 }
 
-bool MimeUtil::IsCodecSupported(Codec codec,
-                                const std::string& mime_type_lower_case,
-                                bool is_encrypted) const {
+SupportsType MimeUtil::IsSimpleCodecSupported(
+    const std::string& mime_type_lower_case,
+    Codec codec,
+    bool is_encrypted) const {
+  // Video codecs are not "simple" because they require a profile and level to
+  // be specified. There is no "default" video codec for a given container.
+  DCHECK_EQ(MimeUtilToVideoCodec(codec), kUnknownVideoCodec);
+
+  SupportsType result =
+      IsCodecSupported(mime_type_lower_case, codec, VIDEO_CODEC_PROFILE_UNKNOWN,
+                       0 /* video_level */, is_encrypted);
+
+  // Platform support should never be ambiguous for simple codecs (no range of
+  // profiles to consider).
+  DCHECK_NE(result, MayBeSupported);
+  return result;
+}
+
+SupportsType MimeUtil::IsCodecSupported(const std::string& mime_type_lower_case,
+                                        Codec codec,
+                                        VideoCodecProfile video_profile,
+                                        uint8_t video_level,
+                                        bool is_encrypted) const {
+  DCHECK_EQ(base::ToLowerASCII(mime_type_lower_case), mime_type_lower_case);
   DCHECK_NE(codec, INVALID_CODEC);
 
+  VideoCodec video_codec = MimeUtilToVideoCodec(codec);
+  if (video_codec != kUnknownVideoCodec &&
+      // Theora and VP8 do not have profiles/levels.
+      video_codec != kCodecTheora && video_codec != kCodecVP8) {
+    DCHECK_NE(video_profile, VIDEO_CODEC_PROFILE_UNKNOWN);
+    DCHECK_GT(video_level, 0);
+  }
+
+  // Bail early for disabled proprietary codecs
+  if (!allow_proprietary_codecs_ && IsCodecProprietary(codec)) {
+    return IsNotSupported;
+  }
+
+  // Check for cases of ambiguous platform support.
+  // TODO(chcunningham): DELETE THIS. Platform should know its capabilities.
+  // Answer should come from MediaClient.
+  bool ambiguous_platform_support = false;
+  if (codec == MimeUtil::H264) {
+    switch (video_profile) {
+      // Always supported
+      case H264PROFILE_BASELINE:
+      case H264PROFILE_MAIN:
+      case H264PROFILE_HIGH:
+        break;
+// HIGH10PROFILE is supported through fallback to the ffmpeg decoder
+// which is not available on Android, or if FFMPEG is not used.
+#if !defined(MEDIA_DISABLE_FFMPEG) && !defined(OS_ANDROID)
+      case H264PROFILE_HIGH10PROFILE:
+        // FFmpeg is not generally used for encrypted videos, so we do not
+        // know whether 10-bit is supported.
+        ambiguous_platform_support = is_encrypted;
+        break;
+#endif
+      default:
+        ambiguous_platform_support = true;
+    }
+  } else if (codec == MimeUtil::VP9 && video_profile != VP9PROFILE_PROFILE0) {
+    // We don't know if the underlying platform supports these profiles. Need
+    // to add platform level querying to get supported profiles.
+    // https://crbug.com/604566
+    ambiguous_platform_support = true;
+  }
+
+  if (GetMediaClient() && video_codec != kUnknownVideoCodec &&
+      !GetMediaClient()->IsSupportedVideoConfig(video_codec, video_profile,
+                                                video_level)) {
+    return IsNotSupported;
+  }
+
 #if defined(OS_ANDROID)
-  if (!IsCodecSupportedOnPlatform(codec, mime_type_lower_case, is_encrypted,
-                                  platform_info_)) {
-    return false;
+  // TODO(chcunningham): Delete this. Android platform support should be
+  // handled by (android specific) MediaClient.
+  if (!IsCodecSupportedOnAndroid(codec, mime_type_lower_case, is_encrypted,
+                                 platform_info_)) {
+    return IsNotSupported;
   }
 #endif
 
-  return allow_proprietary_codecs_ || !IsCodecProprietary(codec);
+  return ambiguous_platform_support ? MayBeSupported : IsSupported;
 }
 
 bool MimeUtil::IsCodecProprietary(Codec codec) const {
@@ -662,21 +718,20 @@
   return true;
 }
 
-bool MimeUtil::GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
-                                        Codec* default_codec) const {
-  if (mime_type_lower_case == "audio/mpeg" ||
-      mime_type_lower_case == "audio/mp3" ||
-      mime_type_lower_case == "audio/x-mp3") {
+bool MimeUtil::GetDefaultCodec(const std::string& mime_type,
+                               Codec* default_codec) const {
+  if (mime_type == "audio/mpeg" || mime_type == "audio/mp3" ||
+      mime_type == "audio/x-mp3") {
     *default_codec = MimeUtil::MP3;
     return true;
   }
 
-  if (mime_type_lower_case == "audio/aac") {
+  if (mime_type == "audio/aac") {
     *default_codec = MimeUtil::MPEG4_AAC;
     return true;
   }
 
-  if (mime_type_lower_case == "audio/flac") {
+  if (mime_type == "audio/flac") {
     *default_codec = MimeUtil::FLAC;
     return true;
   }
@@ -684,13 +739,12 @@
   return false;
 }
 
-bool MimeUtil::IsDefaultCodecSupportedLowerCase(
-    const std::string& mime_type_lower_case,
-    bool is_encrypted) const {
+SupportsType MimeUtil::IsDefaultCodecSupported(const std::string& mime_type,
+                                               bool is_encrypted) const {
   Codec default_codec = Codec::INVALID_CODEC;
-  if (!GetDefaultCodecLowerCase(mime_type_lower_case, &default_codec))
-    return false;
-  return IsCodecSupported(default_codec, mime_type_lower_case, is_encrypted);
+  if (!GetDefaultCodec(mime_type, &default_codec))
+    return IsNotSupported;
+  return IsSimpleCodecSupported(mime_type, default_codec, is_encrypted);
 }
 
 }  // namespace internal
diff --git a/media/base/mime_util_internal.h b/media/base/mime_util_internal.h
index e853b89..b0f724e1 100644
--- a/media/base/mime_util_internal.h
+++ b/media/base/mime_util_internal.h
@@ -56,36 +56,28 @@
 
   // See mime_util.h for more information on these methods.
   bool IsSupportedMediaMimeType(const std::string& mime_type) const;
-  void ParseCodecString(const std::string& codecs,
-                        std::vector<std::string>* codecs_out,
-                        bool strip);
+  void SplitCodecsToVector(const std::string& codecs,
+                           std::vector<std::string>* codecs_out,
+                           bool strip);
   SupportsType IsSupportedMediaFormat(const std::string& mime_type,
                                       const std::vector<std::string>& codecs,
                                       bool is_encrypted) const;
 
   void RemoveProprietaryMediaTypesAndCodecs();
 
-  // Checks special platform specific codec restrictions. Returns true if
+  // Checks android platform specific codec restrictions. Returns true if
   // |codec| is supported when contained in |mime_type_lower_case|.
   // |is_encrypted| means the codec will be used with encrypted blocks.
   // |platform_info| describes the availability of various platform features;
   // see PlatformInfo for more details.
-  static bool IsCodecSupportedOnPlatform(
-      Codec codec,
-      const std::string& mime_type_lower_case,
-      bool is_encrypted,
-      const PlatformInfo& platform_info);
+  static bool IsCodecSupportedOnAndroid(Codec codec,
+                                        const std::string& mime_type_lower_case,
+                                        bool is_encrypted,
+                                        const PlatformInfo& platform_info);
 
  private:
   typedef base::hash_set<int> CodecSet;
   typedef std::map<std::string, CodecSet> MediaFormatMappings;
-  struct CodecEntry {
-    CodecEntry() : codec(INVALID_CODEC), is_ambiguous(true) {}
-    CodecEntry(Codec c, bool ambiguous) : codec(c), is_ambiguous(ambiguous) {}
-    Codec codec;
-    bool is_ambiguous;
-  };
-  typedef std::map<std::string, CodecEntry> StringToCodecMappings;
 
   // Initializes the supported media types into hash sets for faster lookup.
   void InitializeMimeTypeMaps();
@@ -109,48 +101,60 @@
                                   const std::string& mime_type_lower_case,
                                   bool is_encrypted) const;
 
-  // Converts a codec ID into an Codec enum value and indicates
-  // whether the conversion was ambiguous.
+  // Converts a codec ID into an Codec enum value and attempts to output the
+  // |out_profile| and |out_level|.
   // Returns true if this method was able to map |codec_id| with
-  // |mime_type_lower_case| to a specific Codec enum value. |codec| and
-  // |is_ambiguous| are only valid if true is returned. Otherwise their value is
-  // undefined after the call.
-  // |is_ambiguous| is true if |codec_id| did not have enough information to
-  // unambiguously determine the proper Codec enum value. If |is_ambiguous|
-  // is true |codec| contains the best guess for the intended Codec enum value.
+  // |mime_type_lower_case| to a specific Codec enum value. |codec| is only
+  // valid if true is returned.
+  // |ambiguous_codec_string| will be set to true when the codec string matches
+  // one of a small number of non-RFC compliant strings (e.g. "avc").
   // |profile| and |level| indicate video codec profile and level (unused for
-  // audio codecs).
+  // audio codecs). These will be VIDEO_CODEC_PROFILE_UNKNOWN and 0 respectively
+  // whenever |codec_id| is incomplete/invalid, or in some cases when
+  // |ambiguous_codec_string| is set to true.
   // |is_encrypted| means the codec will be used with encrypted blocks.
-  bool StringToCodec(const std::string& mime_type_lower_case,
-                     const std::string& codec_id,
-                     Codec* codec,
-                     bool* is_ambiguous,
-                     VideoCodecProfile* out_profile,
-                     uint8_t* out_level,
-                     bool is_encrypted) const;
+  bool ParseCodecString(const std::string& mime_type_lower_case,
+                        const std::string& codec_id,
+                        Codec* codec,
+                        bool* ambiguous_codec_string,
+                        VideoCodecProfile* out_profile,
+                        uint8_t* out_level) const;
 
-  // Returns true if |codec| is supported when contained in
-  // |mime_type_lower_case|. Note: This method will always return false for
-  // proprietary codecs if |allow_proprietary_codecs_| is set to false.
-  // |is_encrypted| means the codec will be used with encrypted blocks.
-  bool IsCodecSupported(Codec codec,
-                        const std::string& mime_type_lower_case,
-                        bool is_encrypted) const;
+  // Returns IsSupported if |codec| when platform supports codec contained in
+  // |mime_type_lower_case|. Returns MayBeSupported when platform support is
+  // unclear. Otherwise returns NotSupported. Note: This method will always
+  // return NotSupported for proprietary codecs if |allow_proprietary_codecs_|
+  // is set to false. |is_encrypted| means the codec will be used with encrypted
+  // blocks.
+  // TODO(chcunningham): Make this method return a bool. Platform support should
+  // always be knowable for a fully specified codec.
+  SupportsType IsCodecSupported(const std::string& mime_type_lower_case,
+                                Codec codec,
+                                VideoCodecProfile video_profile,
+                                uint8_t video_level,
+                                bool is_encrypted) const;
+
+  // Wrapper around IsCodecSupported for simple codecs that are entirely
+  // described (or implied) by the container mime-type.
+  SupportsType IsSimpleCodecSupported(const std::string& mime_type_lower_case,
+                                      Codec codec,
+                                      bool is_encrypted) const;
 
   // Returns true if |codec| refers to a proprietary codec.
   bool IsCodecProprietary(Codec codec) const;
 
-  // Returns true and sets |*default_codec| if |mime_type| has a  default codec
-  // associated with it. Returns false otherwise and the value of
+  // Returns true and sets |*default_codec| if |mime_type_lower_case| has a
+  // default codec associated with it. Returns false otherwise and the value of
   // |*default_codec| is undefined.
-  bool GetDefaultCodecLowerCase(const std::string& mime_type_lower_case,
-                                Codec* default_codec) const;
+  bool GetDefaultCodec(const std::string& mime_type_lower_case,
+                       Codec* default_codec) const;
 
-  // Returns true if |mime_type_lower_case| has a default codec associated with
-  // it and IsCodecSupported() returns true for that particular codec.
-  // |is_encrypted| means the codec will be used with encrypted blocks.
-  bool IsDefaultCodecSupportedLowerCase(const std::string& mime_type_lower_case,
-                                        bool is_encrypted) const;
+  // Returns IsSupported if |mime_type_lower_case| has a default codec
+  // associated with it and IsCodecSupported() returns IsSupported for that
+  // particular codec. |is_encrypted| means the codec will be used with
+  // encrypted blocks.
+  SupportsType IsDefaultCodecSupported(const std::string& mime_type_lower_case,
+                                       bool is_encrypted) const;
 
 #if defined(OS_ANDROID)
   // Indicates the support of various codecs within the platform.
@@ -165,9 +169,6 @@
   // Whether proprietary codec support should be advertised to callers.
   bool allow_proprietary_codecs_;
 
-  // Lookup table for string compare based string -> Codec mappings.
-  StringToCodecMappings string_to_codec_map_;
-
   DISALLOW_COPY_AND_ASSIGN(MimeUtil);
 };
 
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc
index 99be40b5..280e9e08 100644
--- a/media/base/mime_util_unittest.cc
+++ b/media/base/mime_util_unittest.cc
@@ -20,7 +20,7 @@
 namespace media {
 namespace internal {
 
-// MIME type for use with IsCodecSupportedOnPlatform() test; type is ignored in
+// MIME type for use with IsCodecSupportedOnAndroid() test; type is ignored in
 // all cases except for when paired with the Opus codec.
 const char kTestMimeType[] = "foo/foo";
 
@@ -35,7 +35,7 @@
   return std::vector<bool>(1, single_value);
 }
 
-// Helper method for running IsCodecSupportedOnPlatform() tests that will
+// Helper method for running IsCodecSupportedOnAndroid() tests that will
 // iterate over all possible field values for a MimeUtil::PlatformInfo struct.
 //
 // To request a field be varied, set its value to true in the |states_to_vary|
@@ -179,7 +179,7 @@
 
 // Note: codecs should only be a list of 2 or fewer; hence the restriction of
 // results' length to 2.
-TEST(MimeUtilTest, ParseCodecString) {
+TEST(MimeUtilTest, SplitCodecsToVector) {
   const struct {
     const char* const original;
     size_t expected_size;
@@ -199,7 +199,7 @@
 
   for (size_t i = 0; i < arraysize(tests); ++i) {
     std::vector<std::string> codecs_out;
-    ParseCodecString(tests[i].original, &codecs_out, true);
+    SplitCodecsToVector(tests[i].original, &codecs_out, true);
     ASSERT_EQ(tests[i].expected_size, codecs_out.size());
     for (size_t j = 0; j < tests[i].expected_size; ++j)
       EXPECT_EQ(tests[i].results[j], codecs_out[j]);
@@ -207,14 +207,13 @@
 
   // Test without stripping the codec type.
   std::vector<std::string> codecs_out;
-  ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false);
+  SplitCodecsToVector("avc1.42E01E, mp4a.40.2", &codecs_out, false);
   ASSERT_EQ(2u, codecs_out.size());
   EXPECT_EQ("avc1.42E01E", codecs_out[0]);
   EXPECT_EQ("mp4a.40.2", codecs_out[1]);
 }
 
-TEST(IsCodecSupportedOnPlatformTest,
-     EncryptedCodecsFailWithoutPlatformSupport) {
+TEST(IsCodecSupportedOnAndroidTest, EncryptedCodecsFailWithoutPlatformSupport) {
   // Vary all parameters except |has_platform_decoders|.
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
   states_to_vary.has_platform_decoders = false;
@@ -228,12 +227,12 @@
   RunCodecSupportTest(
       states_to_vary, test_states,
       [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) {
-        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(codec, kTestMimeType,
-                                                          true, info));
+        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnAndroid(codec, kTestMimeType,
+                                                         true, info));
       });
 }
 
-TEST(IsCodecSupportedOnPlatformTest, EncryptedCodecBehavior) {
+TEST(IsCodecSupportedOnAndroidTest, EncryptedCodecBehavior) {
   // Vary all parameters except |has_platform_decoders|.
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
   states_to_vary.has_platform_decoders = false;
@@ -245,7 +244,7 @@
   RunCodecSupportTest(
       states_to_vary, test_states,
       [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) {
-        const bool result = MimeUtil::IsCodecSupportedOnPlatform(
+        const bool result = MimeUtil::IsCodecSupportedOnAndroid(
             codec, kTestMimeType, true, info);
         switch (codec) {
           // These codecs are never supported by the Android platform.
@@ -288,7 +287,7 @@
       });
 }
 
-TEST(IsCodecSupportedOnPlatformTest, ClearCodecBehavior) {
+TEST(IsCodecSupportedOnAndroidTest, ClearCodecBehavior) {
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
 
   MimeUtil::PlatformInfo test_states;
@@ -296,7 +295,7 @@
   RunCodecSupportTest(
       states_to_vary, test_states,
       [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) {
-        const bool result = MimeUtil::IsCodecSupportedOnPlatform(
+        const bool result = MimeUtil::IsCodecSupportedOnAndroid(
             codec, kTestMimeType, false, info);
         switch (codec) {
           // These codecs are never supported by the Android platform.
@@ -332,7 +331,7 @@
       });
 }
 
-TEST(IsCodecSupportedOnPlatformTest, OpusOggSupport) {
+TEST(IsCodecSupportedOnAndroidTest, OpusOggSupport) {
   // Vary all parameters; thus use default initial state.
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
   MimeUtil::PlatformInfo test_states;
@@ -340,12 +339,12 @@
   RunCodecSupportTest(
       states_to_vary, test_states,
       [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) {
-        EXPECT_TRUE(MimeUtil::IsCodecSupportedOnPlatform(
+        EXPECT_TRUE(MimeUtil::IsCodecSupportedOnAndroid(
             MimeUtil::OPUS, "audio/ogg", false, info));
       });
 }
 
-TEST(IsCodecSupportedOnPlatformTest, HLSDoesNotSupportMPEG2AAC) {
+TEST(IsCodecSupportedOnAndroidTest, HLSDoesNotSupportMPEG2AAC) {
   // Vary all parameters; thus use default initial state.
   MimeUtil::PlatformInfo states_to_vary = VaryAllFields();
   MimeUtil::PlatformInfo test_states;
@@ -353,13 +352,13 @@
   RunCodecSupportTest(
       states_to_vary, test_states,
       [](const MimeUtil::PlatformInfo& info, MimeUtil::Codec codec) {
-        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(
+        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnAndroid(
             MimeUtil::MPEG2_AAC, "application/x-mpegurl", false, info));
-        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(
+        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnAndroid(
             MimeUtil::MPEG2_AAC, "application/vnd.apple.mpegurl", false, info));
-        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(
+        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnAndroid(
             MimeUtil::MPEG2_AAC, "audio/mpegurl", false, info));
-        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnPlatform(
+        EXPECT_FALSE(MimeUtil::IsCodecSupportedOnAndroid(
             MimeUtil::MPEG2_AAC, "audio/x-mpegurl", false, info));
       });
 }
diff --git a/media/base/video_facing.h b/media/base/video_facing.h
index 9bd0b50e..bf354c2 100644
--- a/media/base/video_facing.h
+++ b/media/base/video_facing.h
@@ -13,7 +13,16 @@
   MEDIA_VIDEO_FACING_USER,
   MEDIA_VIDEO_FACING_ENVIRONMENT,
 
-  NUM_MEDIA_VIDEO_FACING_MODE
+  NUM_MEDIA_VIDEO_FACING_MODES
+};
+
+// Clients interested in video capture events can implement this interface
+// and register the observers to MediaStreamManager or VideoCaptureManager.
+class VideoCaptureObserver {
+ public:
+  virtual ~VideoCaptureObserver() {}
+  virtual void OnVideoCaptureStarted(VideoFacingMode facing) = 0;
+  virtual void OnVideoCaptureStopped(VideoFacingMode facing) = 0;
 };
 
 }  // namespace media
diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc
index 5799869..7f35733 100644
--- a/media/blink/key_system_config_selector.cc
+++ b/media/blink/key_system_config_selector.cc
@@ -299,7 +299,7 @@
                             const std::string& codecs,
                             bool use_aes_decryptor) {
   std::vector<std::string> codec_vector;
-  ParseCodecString(codecs, &codec_vector, false);
+  SplitCodecsToVector(codecs, &codec_vector, false);
   // AesDecryptor decrypts the stream in the demuxer before it reaches the
   // decoder so check whether the media format is supported when clear.
   SupportsType support_result =
@@ -339,7 +339,7 @@
   // This check does not handle extended codecs, so extended codec information
   // is stripped (extended codec information was checked above).
   std::vector<std::string> stripped_codec_vector;
-  ParseCodecString(codecs, &stripped_codec_vector, true);
+  SplitCodecsToVector(codecs, &stripped_codec_vector, true);
   EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule(
       key_system, media_type, container_lower, stripped_codec_vector);
   if (!config_state->IsRuleSupported(codecs_rule))
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index 5a6974ca..67e67e7 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -89,7 +89,7 @@
 
 VideoCaptureDevice::Client::Buffer CreateStubBuffer(int buffer_id,
                                                     size_t mapped_size) {
-  auto buffer = new uint8_t[mapped_size];
+  auto* buffer = new uint8_t[mapped_size];
   const int arbitrary_frame_feedback_id = 0;
   return VideoCaptureDevice::Client::Buffer(
       buffer_id, arbitrary_frame_feedback_id,
diff --git a/media/capture/video/video_capture_device_descriptor.cc b/media/capture/video/video_capture_device_descriptor.cc
index 3a259543..7011608 100644
--- a/media/capture/video/video_capture_device_descriptor.cc
+++ b/media/capture/video/video_capture_device_descriptor.cc
@@ -45,7 +45,7 @@
 
 bool VideoCaptureDeviceDescriptor::operator<(
     const VideoCaptureDeviceDescriptor& other) const {
-  static constexpr int kFacingMapping[NUM_MEDIA_VIDEO_FACING_MODE] = {0, 2, 1};
+  static constexpr int kFacingMapping[NUM_MEDIA_VIDEO_FACING_MODES] = {0, 2, 1};
   static_assert(kFacingMapping[MEDIA_VIDEO_FACING_NONE] == 0,
                 "FACING_NONE has a wrong value");
   static_assert(kFacingMapping[MEDIA_VIDEO_FACING_ENVIRONMENT] == 1,
diff --git a/media/filters/chunk_demuxer.cc b/media/filters/chunk_demuxer.cc
index 177a8194..42cafad 100644
--- a/media/filters/chunk_demuxer.cc
+++ b/media/filters/chunk_demuxer.cc
@@ -587,7 +587,7 @@
     return kReachedIdLimit;
 
   std::vector<std::string> parsed_codec_ids;
-  media::ParseCodecString(codecs, &parsed_codec_ids, false);
+  media::SplitCodecsToVector(codecs, &parsed_codec_ids, false);
 
   std::unique_ptr<media::StreamParser> stream_parser(
       StreamParserFactory::Create(type, parsed_codec_ids, media_log_));
@@ -711,7 +711,7 @@
       stream->set_enabled(false, currTime);
     }
   }
-  for (const auto& stream : enabled_streams) {
+  for (auto* stream : enabled_streams) {
     DVLOG(1) << __func__ << ": enabling stream " << stream;
     stream->set_enabled(true, currTime);
   }
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index d714603..424fce8 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -1654,7 +1654,7 @@
       stream->set_enabled(false, currTime);
     }
   }
-  for (const auto& stream : enabled_streams) {
+  for (auto* stream : enabled_streams) {
     DCHECK(stream);
     DVLOG(1) << __func__ << ": enabling stream " << stream;
     stream->set_enabled(true, currTime);
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 6a2420a..627d54c 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -361,6 +361,7 @@
   vda_config.encryption_scheme = config_.encryption_scheme();
   vda_config.is_deferred_initialization_allowed = true;
   vda_config.initial_expected_coded_size = config_.coded_size();
+  vda_config.color_space = config_.color_space_info();
 
 #if defined(OS_ANDROID) && BUILDFLAG(USE_PROPRIETARY_CODECS)
   // We pass the SPS and PPS on Android because it lets us initialize
@@ -897,14 +898,12 @@
     bool is_encrypted) {
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
   for (const auto& supported_profile : capabilities.supported_profiles) {
-    if (profile == supported_profile.profile) {
-      if (supported_profile.encrypted_only && !is_encrypted)
-        continue;
-
-      return IsCodedSizeSupported(coded_size,
-                                  supported_profile.min_resolution,
-                                  supported_profile.max_resolution);
-    }
+    if (profile != supported_profile.profile ||
+        (supported_profile.encrypted_only && !is_encrypted) ||
+        !IsCodedSizeSupported(coded_size, supported_profile.min_resolution,
+                              supported_profile.max_resolution))
+      continue;
+    return true;
   }
   return false;
 }
diff --git a/media/filters/h264_parser.cc b/media/filters/h264_parser.cc
index c0887fd..b5ebf48 100644
--- a/media/filters/h264_parser.cc
+++ b/media/filters/h264_parser.cc
@@ -130,12 +130,7 @@
         video_full_range_flag ? gfx::ColorSpace::RangeID::FULL
                               : gfx::ColorSpace::RangeID::LIMITED);
   } else {
-    // TODO(ccameron/hubbe): Add a uniform way to handle default video frames.
-    return gfx::ColorSpace(
-        gfx::ColorSpace::PrimaryID::BT709, gfx::ColorSpace::TransferID::BT709,
-        gfx::ColorSpace::MatrixID::BT709,
-        video_full_range_flag ? gfx::ColorSpace::RangeID::FULL
-                              : gfx::ColorSpace::RangeID::LIMITED);
+    return gfx::ColorSpace();
   }
 }
 
diff --git a/media/filters/source_buffer_state.cc b/media/filters/source_buffer_state.cc
index 868abd7..30436e8b 100644
--- a/media/filters/source_buffer_state.cc
+++ b/media/filters/source_buffer_state.cc
@@ -146,7 +146,7 @@
   init_cb_ = init_cb;
 
   std::vector<std::string> expected_codecs_parsed;
-  ParseCodecString(expected_codecs, &expected_codecs_parsed, false);
+  SplitCodecsToVector(expected_codecs, &expected_codecs_parsed, false);
 
   std::vector<AudioCodec> expected_acodecs;
   std::vector<VideoCodec> expected_vcodecs;
@@ -795,7 +795,7 @@
 }
 
 void SourceBufferState::SetStreamMemoryLimits() {
-  auto cmd_line = base::CommandLine::ForCurrentProcess();
+  auto* cmd_line = base::CommandLine::ForCurrentProcess();
 
   std::string audio_buf_limit_switch =
       cmd_line->GetSwitchValueASCII(switches::kMSEAudioBufferSizeLimit);
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc
index a3ebb2d1..7d0963b1 100644
--- a/media/gpu/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -2130,7 +2130,10 @@
   // Attempt to retrieve an output frame from the decoder. If we have one,
   // return and proceed when the output frame is processed. If we don't have a
   // frame then we are done.
-  DoDecode(config_change_detector_->current_color_space());
+  gfx::ColorSpace color_space = config_change_detector_->current_color_space();
+  if (!color_space.IsValid())
+    color_space = config_.color_space;
+  DoDecode(color_space);
   if (OutputSamplesPresent())
     return;
 
@@ -2180,6 +2183,8 @@
   }
 
   gfx::ColorSpace color_space = config_change_detector_->current_color_space();
+  if (!color_space.IsValid())
+    color_space = config_.color_space;
 
   if (!inputs_before_decode_) {
     TRACE_EVENT_ASYNC_BEGIN0("gpu", "DXVAVideoDecodeAccelerator.Decoding",
diff --git a/media/gpu/ipc/common/media_param_traits_macros.h b/media/gpu/ipc/common/media_param_traits_macros.h
index 6904202..b77189c 100644
--- a/media/gpu/ipc/common/media_param_traits_macros.h
+++ b/media/gpu/ipc/common/media_param_traits_macros.h
@@ -12,6 +12,7 @@
 #include "media/video/jpeg_decode_accelerator.h"
 #include "media/video/video_decode_accelerator.h"
 #include "media/video/video_encode_accelerator.h"
+#include "ui/gfx/ipc/color/gfx_param_traits.h"
 #include "ui/gfx/ipc/geometry/gfx_param_traits.h"
 
 IPC_ENUM_TRAITS_MAX_VALUE(media::JpegDecodeAccelerator::Error,
@@ -29,6 +30,7 @@
   IPC_STRUCT_TRAITS_MEMBER(supported_output_formats)
   IPC_STRUCT_TRAITS_MEMBER(sps)
   IPC_STRUCT_TRAITS_MEMBER(pps)
+  IPC_STRUCT_TRAITS_MEMBER(color_space)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(media::CreateVideoEncoderParams)
diff --git a/media/remoting/proto_utils.cc b/media/remoting/proto_utils.cc
index 30114d0..3431f3e 100644
--- a/media/remoting/proto_utils.cc
+++ b/media/remoting/proto_utils.cc
@@ -358,7 +358,7 @@
 void ConvertCdmKeyInfoToProto(
     const CdmKeysInfo& keys_information,
     pb::CdmClientOnSessionKeysChange* key_change_message) {
-  for (const auto& info : keys_information) {
+  for (auto* info : keys_information) {
     pb::CdmKeyInformation* key = key_change_message->add_key_information();
     key->set_key_id(info->key_id.data(), info->key_id.size());
     key->set_status(ToProtoCdmKeyInformation(info->status).value());
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index ff180076..97af30bb 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -169,6 +169,9 @@
     // Each SPS and PPS is prefixed with the Annex B framing bytes: 0, 0, 0, 1.
     std::vector<uint8_t> sps;
     std::vector<uint8_t> pps;
+
+    // Color space specified by the container.
+    gfx::ColorSpace color_space;
   };
 
   // Interface for collaborating with picture interface to provide memory for
diff --git a/mojo/public/cpp/bindings/lib/message.cc b/mojo/public/cpp/bindings/lib/message.cc
index be19cf3..68337d1 100644
--- a/mojo/public/cpp/bindings/lib/message.cc
+++ b/mojo/public/cpp/bindings/lib/message.cc
@@ -106,13 +106,13 @@
 }
 
 uint32_t Message::payload_num_interface_ids() const {
-  auto array_pointer =
+  auto* array_pointer =
       version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
   return array_pointer ? static_cast<uint32_t>(array_pointer->size()) : 0;
 }
 
 const uint32_t* Message::payload_interface_ids() const {
-  auto array_pointer =
+  auto* array_pointer =
       version() < 2 ? nullptr : header_v2()->payload_interface_ids.Get();
   return array_pointer ? array_pointer->storage() : nullptr;
 }
@@ -174,7 +174,7 @@
   DCHECK(header_v2()->payload_interface_ids.is_null());
 
   size_t size = associated_endpoint_handles_.size();
-  auto data = internal::Array_Data<uint32_t>::New(size, buffer());
+  auto* data = internal::Array_Data<uint32_t>::New(size, buffer());
   header_v2()->payload_interface_ids.Set(data);
 
   for (size_t i = 0; i < size; ++i) {
diff --git a/mojo/public/cpp/bindings/lib/message_header_validator.cc b/mojo/public/cpp/bindings/lib/message_header_validator.cc
index 56be241..9f8c6278 100644
--- a/mojo/public/cpp/bindings/lib/message_header_validator.cc
+++ b/mojo/public/cpp/bindings/lib/message_header_validator.cc
@@ -64,7 +64,7 @@
   if (header->version < 2)
     return true;
 
-  auto header_v2 = static_cast<const internal::MessageHeaderV2*>(header);
+  auto* header_v2 = static_cast<const internal::MessageHeaderV2*>(header);
   // For the payload pointer:
   // - Check that the pointer can be safely decoded.
   // - Claim one byte that the pointer points to. It makes sure not only the
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 59a9924..2272d7b0 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1099,7 +1099,7 @@
 
   CookieList cookie_list;
   cookie_list.reserve(cookie_ptrs.size());
-  for (const auto& cookie_ptr : cookie_ptrs)
+  for (auto* cookie_ptr : cookie_ptrs)
     cookie_list.push_back(*cookie_ptr);
 
   return cookie_list;
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index 8ca3acaf..384527a0 100644
--- a/net/cookies/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -158,7 +158,7 @@
       "2039 April 15 21:01:22", "2038 April 15 21:01:22",
   };
 
-  for (const auto& test : kTests) {
+  for (auto* test : kTests) {
     base::Time parsed_time = cookie_util::ParseCookieExpirationTime(test);
     EXPECT_FALSE(parsed_time.is_null());
 
@@ -183,7 +183,7 @@
       "1969 March 3 21:01:22", "1600 April 15 21:01:22",
   };
 
-  for (const auto& test : kTests) {
+  for (auto* test : kTests) {
     base::Time parsed_time = cookie_util::ParseCookieExpirationTime(test);
     EXPECT_FALSE(parsed_time.is_null());
 
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index edc71ff..c7a93f0 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -136,7 +136,7 @@
 
   void UnthrottleAllRequests() {
     std::set<TestThrottle*> outstanding_throttles_copy(outstanding_throttles_);
-    for (auto& throttle : outstanding_throttles_copy) {
+    for (auto* throttle : outstanding_throttles_copy) {
       if (throttle->IsBlocked())
         throttle->Unthrottle();
     }
diff --git a/net/http/http_response_headers_unittest.cc b/net/http/http_response_headers_unittest.cc
index 0c960af..3e0c251 100644
--- a/net/http/http_response_headers_unittest.cc
+++ b/net/http/http_response_headers_unittest.cc
@@ -1819,7 +1819,7 @@
       new HttpResponseHeaders(orig_headers));
 
   std::unordered_set<std::string> to_remove;
-  for (const auto& header : test.to_remove) {
+  for (auto* header : test.to_remove) {
     if (header)
       to_remove.insert(header);
   }
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc
index bb55d6ea..4fc8545c 100644
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -115,12 +115,6 @@
 
 class JobControllerPeer {
  public:
-  static void VerifyWaitingTimeForMainJob(
-      HttpStreamFactoryImpl::JobController* job_controller,
-      const base::TimeDelta& delay) {
-    EXPECT_EQ(delay, job_controller->main_job_wait_time_);
-  }
-
   static bool main_job_is_blocked(
       HttpStreamFactoryImpl::JobController* job_controller) {
     return job_controller->main_job_is_blocked_;
@@ -940,7 +934,7 @@
   job_controller_->OnStreamFailed(job_factory_.alternative_job(),
                                   ERR_NETWORK_CHANGED, SSLConfig());
   EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount());
-  test_task_runner->RunUntilIdle();
+  test_task_runner->FastForwardUntilNoTasksRemain();
 }
 
 // Test that main job is blocked for kMaxDelayTimeForMainJob(3s) if
@@ -1117,6 +1111,10 @@
 // Verifies that the main job is resumed properly after a delay when the
 // alternative proxy server job hangs.
 TEST_F(HttpStreamFactoryImplJobControllerTest, DelayedTCPAlternativeProxy) {
+  // Overrides the main thread's message loop with a mock tick clock so that we
+  // could verify the main job is resumed with appropriate delay.
+  base::ScopedMockTimeMessageLoopTaskRunner test_task_runner;
+
   // Using hanging resolver will cause the alternative job to hang indefinitely.
   HangingResolver* resolver = new HangingResolver();
   session_deps_.host_resolver.reset(resolver);
@@ -1146,38 +1144,32 @@
   EXPECT_TRUE(job_controller_->alternative_job());
   EXPECT_TRUE(JobControllerPeer::main_job_is_blocked(job_controller_));
 
-  // The alternative proxy server job stalls when connecting to the alternative
-  // proxy server, and controller should resume the main job after delay.
-  // Verify the waiting time for delayed main job.
-  EXPECT_CALL(*job_factory_.main_job(), Resume())
-      .WillOnce(Invoke(testing::CreateFunctor(
-          &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
-          base::TimeDelta::FromMicroseconds(15))));
+  // Alternative proxy server job will start in the next message loop.
+  EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount());
 
-  // This message loop should cause the alternative proxy server job to start,
-  // and schedule resumption of the main job.
-  base::RunLoop().RunUntilIdle();
+  EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(0);
+  // Run tasks with no remaining delay, this will start the alternative proxy
+  // server job. The alternative proxy server job stalls when connecting to the
+  // alternative proxy server, and should schedule a task to resume the main job
+  // after delay. That task will be queued.
+  test_task_runner->RunUntilIdle();
+  EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount());
+
+  // Move forward the delay and verify the main job is resumed.
+  EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
+  test_task_runner->FastForwardBy(base::TimeDelta::FromMicroseconds(15));
   EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_));
 
-  // Wait for the Resume to post.
-  base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
-
-  // This message loop should cause the main job to resume.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(JobControllerPeer::main_job_is_blocked(job_controller_));
-
-  JobControllerPeer::VerifyWaitingTimeForMainJob(
-      job_controller_, base::TimeDelta::FromMicroseconds(0));
-
-  // Since the main job did not complete successfully, the alternative proxy
-  // server should not be marked as bad.
+  test_task_runner->RunUntilIdle();
   EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid());
   EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations());
+  EXPECT_FALSE(test_task_runner->HasPendingTask());
 }
 
 // Verifies that the alternative proxy server job fails immediately, and the
 // main job is not blocked.
 TEST_F(HttpStreamFactoryImplJobControllerTest, FailAlternativeProxy) {
+  base::ScopedMockTimeMessageLoopTaskRunner test_task_runner;
   // Using failing resolver will cause the alternative job to fail.
   FailingHostResolver* resolver = new FailingHostResolver();
   session_deps_.host_resolver.reset(resolver);
@@ -1204,23 +1196,25 @@
   EXPECT_TRUE(job_controller_->main_job()->is_waiting());
   EXPECT_TRUE(job_controller_->alternative_job());
 
+  EXPECT_EQ(1u, test_task_runner->GetPendingTaskCount());
+
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, _)).Times(0);
 
   // Since the alternative proxy server job is started in the next message loop,
   // the main job would remain blocked until the alternative proxy starts, and
   // fails.
-  EXPECT_CALL(*job_factory_.main_job(), Resume())
-      .WillOnce(Invoke(testing::CreateFunctor(
-          &JobControllerPeer::VerifyWaitingTimeForMainJob, job_controller_,
-          base::TimeDelta::FromMicroseconds(0))));
+  EXPECT_CALL(*job_factory_.main_job(), Resume()).Times(1);
 
-  base::RunLoop().RunUntilIdle();
+  // Run tasks with no remaining delay.
+  test_task_runner->RunUntilIdle();
+
   EXPECT_FALSE(job_controller_->alternative_job());
   EXPECT_TRUE(job_controller_->main_job()->is_waiting());
   // Since the main job did not complete successfully, the alternative proxy
   // server should not be marked as bad.
   EXPECT_TRUE(test_proxy_delegate()->alternative_proxy_server().is_valid());
   EXPECT_EQ(1, test_proxy_delegate()->get_alternative_proxy_invocations());
+  EXPECT_FALSE(test_task_runner->HasPendingTask());
 }
 
 TEST_F(HttpStreamFactoryImplJobControllerTest,
diff --git a/net/http2/decoder/payload_decoders/ping_payload_decoder.cc b/net/http2/decoder/payload_decoders/ping_payload_decoder.cc
index abe43d0a..d8edbb0 100644
--- a/net/http2/decoder/payload_decoders/ping_payload_decoder.cc
+++ b/net/http2/decoder/payload_decoders/ping_payload_decoder.cc
@@ -34,7 +34,7 @@
     // This supports the claim that this decoder is (mostly) non-buffering.
     static_assert(sizeof(Http2PingFields) == kOpaqueSize,
                   "If not, then can't enter this block!");
-    auto ping = reinterpret_cast<const Http2PingFields*>(db->cursor());
+    auto* ping = reinterpret_cast<const Http2PingFields*>(db->cursor());
     if (frame_header.IsAck()) {
       state->listener()->OnPingAck(frame_header, *ping);
     } else {
diff --git a/net/http2/hpack/decoder/hpack_decoder_tables.cc b/net/http2/hpack/decoder/hpack_decoder_tables.cc
index fb8f47b4..61e7970 100644
--- a/net/http2/hpack/decoder/hpack_decoder_tables.cc
+++ b/net/http2/hpack/decoder/hpack_decoder_tables.cc
@@ -10,7 +10,7 @@
 namespace {
 
 std::vector<HpackStringPair>* MakeStaticTable() {
-  auto ptr = new std::vector<HpackStringPair>();
+  auto* ptr = new std::vector<HpackStringPair>();
   ptr->reserve(kFirstDynamicTableIndex);
   ptr->emplace_back("", "");
 
diff --git a/net/http2/hpack/huffman/http2_hpack_huffman_decoder.cc b/net/http2/hpack/huffman/http2_hpack_huffman_decoder.cc
index 45c32c08..189d34a 100644
--- a/net/http2/hpack/huffman/http2_hpack_huffman_decoder.cc
+++ b/net/http2/hpack/huffman/http2_hpack_huffman_decoder.cc
@@ -368,7 +368,7 @@
 
   // Top up |accumulator_| until there isn't room for a whole byte.
   size_t bytes_used = 0;
-  auto ptr = reinterpret_cast<const uint8_t*>(input.data());
+  auto* ptr = reinterpret_cast<const uint8_t*>(input.data());
   do {
     auto b = static_cast<HuffmanAccumulator>(*ptr++);
     free_cnt -= 8;
diff --git a/net/proxy/mojo_proxy_resolver_impl_unittest.cc b/net/proxy/mojo_proxy_resolver_impl_unittest.cc
index 87a6427..0565a1a 100644
--- a/net/proxy/mojo_proxy_resolver_impl_unittest.cc
+++ b/net/proxy/mojo_proxy_resolver_impl_unittest.cc
@@ -170,7 +170,7 @@
     std::unique_ptr<ProxyResolver::Request>* request,
     std::unique_ptr<Bindings> bindings) {
   pending_jobs_.push_back(base::WrapUnique(new Job()));
-  auto pending_job = pending_jobs_.back().get();
+  auto* pending_job = pending_jobs_.back().get();
   pending_job->url = url;
   pending_job->results = results;
   pending_job->SetCallback(callback);
diff --git a/net/quic/core/quic_stream_sequencer_buffer_test.cc b/net/quic/core/quic_stream_sequencer_buffer_test.cc
index fa71edf..e3be181 100644
--- a/net/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -128,7 +128,7 @@
   std::list<Gap> gaps = helper_->GetGaps();
   EXPECT_EQ(800u, gaps.front().end_offset);
   EXPECT_EQ(1824u, gaps.back().begin_offset);
-  auto frame_map = helper_->frame_arrival_time_map();
+  auto* frame_map = helper_->frame_arrival_time_map();
   EXPECT_EQ(1u, frame_map->size());
   EXPECT_EQ(800u, frame_map->begin()->first);
   EXPECT_EQ(t, (*frame_map)[800].timestamp);
@@ -167,7 +167,7 @@
             buffer_->OnStreamData(0, source, t2, &written, &error_details_));
   EXPECT_EQ(QUIC_OVERLAPPING_STREAM_DATA,
             buffer_->OnStreamData(1024, source, t2, &written, &error_details_));
-  auto frame_map = helper_->frame_arrival_time_map();
+  auto* frame_map = helper_->frame_arrival_time_map();
   EXPECT_EQ(1u, frame_map->size());
   EXPECT_EQ(t1, (*frame_map)[800].timestamp);
 }
@@ -198,7 +198,7 @@
   EXPECT_EQ(QUIC_NO_ERROR,
             buffer_->OnStreamData(1824, one_byte, clock_.ApproximateNow(),
                                   &written, &error_details_));
-  auto frame_map = helper_->frame_arrival_time_map();
+  auto* frame_map = helper_->frame_arrival_time_map();
   EXPECT_EQ(3u, frame_map->size());
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
diff --git a/net/quic/platform/api/quic_text_utils_test.cc b/net/quic/platform/api/quic_text_utils_test.cc
index 06b25620..758ad54 100644
--- a/net/quic/platform/api/quic_text_utils_test.cc
+++ b/net/quic/platform/api/quic_text_utils_test.cc
@@ -43,8 +43,8 @@
 TEST(QuicTextUtilsText, RemoveLeadingAndTrailingWhitespace) {
   string input;
 
-  for (auto input : {"text", " text", "  text", "text ", "text  ", " text ",
-                     "  text  ", "\r\n\ttext", "text\n\r\t"}) {
+  for (auto* input : {"text", " text", "  text", "text ", "text  ", " text ",
+                      "  text  ", "\r\n\ttext", "text\n\r\t"}) {
     StringPiece piece(input);
     QuicTextUtils::RemoveLeadingAndTrailingWhitespace(&piece);
     EXPECT_EQ("text", piece);
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 77f3059..929607d 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -82,7 +82,7 @@
 
 // Token Binding ProtocolVersions supported.
 const uint8_t kTbProtocolVersionMajor = 0;
-const uint8_t kTbProtocolVersionMinor = 10;
+const uint8_t kTbProtocolVersionMinor = 13;
 const uint8_t kTbMinProtocolVersionMajor = 0;
 const uint8_t kTbMinProtocolVersionMinor = 10;
 
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 11bb432f..442b548b 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -248,7 +248,7 @@
     SpdySerializedFrame serialized_headers_old_version =
         framer->SerializeHeaders(headers);
     framer->hpack_encoder_.reset(nullptr);
-    auto saved_debug_visitor = framer->debug_visitor_;
+    auto* saved_debug_visitor = framer->debug_visitor_;
     framer->debug_visitor_ = nullptr;
 
     std::vector<SpdySerializedFrame> frame_list;
diff --git a/net/spdy/spdy_header_block.cc b/net/spdy/spdy_header_block.cc
index a51532cf..32481174 100644
--- a/net/spdy/spdy_header_block.cc
+++ b/net/spdy/spdy_header_block.cc
@@ -270,7 +270,7 @@
   } else {
     DVLOG(1) << "Updating key: " << iter->first
              << " with value: " << value.second;
-    auto storage = GetStorage();
+    auto* storage = GetStorage();
     iter->second =
         HeaderValue(storage, iter->first, storage->Write(value.second));
   }
@@ -313,7 +313,7 @@
 
 void SpdyHeaderBlock::AppendHeader(const StringPiece key,
                                    const StringPiece value) {
-  auto storage = GetStorage();
+  auto* storage = GetStorage();
   auto backed_key = storage->Write(key);
   block_.emplace(make_pair(
       backed_key, HeaderValue(storage, backed_key, storage->Write(value))));
@@ -382,7 +382,7 @@
   if (fragments.empty()) {
     return 0;
   }
-  auto original_dst = dst;
+  auto* original_dst = dst;
   auto it = fragments.begin();
   memcpy(dst, it->data(), it->size());
   dst += it->size();
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index b014e51..1b469f48 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -382,7 +382,7 @@
   size_t cert_count = 0;
   size_t serialized_cert_size = 0;
   size_t num_active_sessions = 0;
-  for (const auto& session : sessions_) {
+  for (auto* session : sessions_) {
     StreamSocket::SocketMemoryStats stats;
     bool is_session_active = false;
     total_size += session->DumpMemoryStats(&stats, &is_session_active);
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 4995021c..106d80f 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -439,7 +439,7 @@
     FLAGS_quic_reloadable_flag_quic_use_cheap_stateless_rejects =
         GetParam().use_cheap_stateless_reject;
 
-    auto test_server = new QuicTestServer(
+    auto* test_server = new QuicTestServer(
         crypto_test_utils::ProofSourceForTesting(), server_config_,
         server_supported_versions_, &response_cache_);
     server_thread_.reset(new ServerThread(test_server, server_address_));
@@ -1824,7 +1824,7 @@
   QuicSpdySession* const client_session = client_->client()->session();
   QuicDispatcher* dispatcher =
       QuicServerPeer::GetDispatcher(server_thread_->server());
-  auto server_session = static_cast<QuicSpdySession*>(
+  auto* server_session = static_cast<QuicSpdySession*>(
       dispatcher->session_map().begin()->second.get());
   ExpectFlowControlsSynced(client_session->flow_controller(),
                            server_session->flow_controller());
diff --git a/net/url_request/url_request_context_getter.cc b/net/url_request/url_request_context_getter.cc
index 0bad748..7163f48 100644
--- a/net/url_request/url_request_context_getter.cc
+++ b/net/url_request/url_request_context_getter.cc
@@ -40,8 +40,10 @@
         // Can't force-delete the object here, because some derived classes
         // can only be deleted on the owning thread, so just emit a warning to
         // aid in debugging.
+#if !defined(NDEBUG)
         DLOG(WARNING) << "URLRequestContextGetter leaking due to no owning"
-                      << " thread.";
+                      << " thread. Created at: " << created_at.ToString();
+#endif  // !defined(NDEBUG)
         // Let LSan know we know this is a leak. https://crbug.com/594130
         ANNOTATE_LEAKING_OBJECT_PTR(this);
       }
diff --git a/net/url_request/url_request_context_getter.h b/net/url_request/url_request_context_getter.h
index 081c97c..5a41526 100644
--- a/net/url_request/url_request_context_getter.h
+++ b/net/url_request/url_request_context_getter.h
@@ -5,6 +5,7 @@
 #ifndef NET_URL_REQUEST_URL_REQUEST_CONTEXT_GETTER_H_
 #define NET_URL_REQUEST_URL_REQUEST_CONTEXT_GETTER_H_
 
+#include "base/debug/stack_trace.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
@@ -70,6 +71,10 @@
 
   base::ObserverList<URLRequestContextGetterObserver> observer_list_;
 
+#if !defined(NDEBUG)
+  base::debug::StackTrace created_at;
+#endif  // !defined(NDEBUG)
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
 };
 
diff --git a/remoting/host/host_extension_session_manager.cc b/remoting/host/host_extension_session_manager.cc
index ac06b4f..07f0a1ef 100644
--- a/remoting/host/host_extension_session_manager.cc
+++ b/remoting/host/host_extension_session_manager.cc
@@ -23,7 +23,7 @@
 
 std::string HostExtensionSessionManager::GetCapabilities() const {
   std::string capabilities;
-  for (const auto& extension : extensions_) {
+  for (auto* extension : extensions_) {
     const std::string& capability = extension->capability();
     if (capability.empty()) {
       continue;
@@ -44,7 +44,7 @@
 
   client_stub_ = client_stub;
 
-  for (const auto& extension : extensions_) {
+  for (auto* extension : extensions_) {
     // If the extension requires a capability that was not negotiated then do
     // not instantiate it.
     if (!extension->capability().empty() &&
diff --git a/remoting/protocol/jingle_session.cc b/remoting/protocol/jingle_session.cc
index bb3eb73f..1b1343f7 100644
--- a/remoting/protocol/jingle_session.cc
+++ b/remoting/protocol/jingle_session.cc
@@ -769,14 +769,14 @@
   if (!message.attachments) {
     return;
   }
-  for (const auto& plugin : plugins_) {
+  for (auto* plugin : plugins_) {
     plugin->OnIncomingMessage(*(message.attachments));
   }
 }
 
 void JingleSession::AddPluginAttachments(JingleMessage* message) {
   DCHECK(message);
-  for (const auto& plugin : plugins_) {
+  for (auto* plugin : plugins_) {
     std::unique_ptr<XmlElement> attachment = plugin->GetNextMessage();
     if (attachment) {
       message->AddAttachment(std::move(attachment));
diff --git a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index 00e9085d..e6c64de 100644
--- a/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -167,7 +167,7 @@
 
   size_t crash_key_length = nr.length() + arg1.length() + arg2.length() +
                             arg3.length() + arg4.length();
-  for (const auto& prefix : prefixes) {
+  for (auto* prefix : prefixes) {
     crash_key_length += strlen(prefix);
   }
   ++crash_key_length;  // For the trailing NUL byte.
@@ -178,7 +178,7 @@
   size_t offset = 0;
   for (size_t i = 0; i < arraysize(values); ++i) {
     const char* strings[2] = { prefixes[i], values[i] };
-    for (const auto& string : strings) {
+    for (auto* string : strings) {
       size_t string_len = strlen(string);
       memmove(&crash_key[offset], string, string_len);
       offset += string_len;
diff --git a/services/service_manager/public/cpp/lib/interface_registry.cc b/services/service_manager/public/cpp/lib/interface_registry.cc
index ba2ea2f9..9fb605d8 100644
--- a/services/service_manager/public/cpp/lib/interface_registry.cc
+++ b/services/service_manager/public/cpp/lib/interface_registry.cc
@@ -214,7 +214,7 @@
 
       std::stringstream details;
       Serialize(&details);
-      LOG(WARNING) << details.str();
+      DVLOG(1) << details.str();
     }
   } else {
     std::stringstream error;
@@ -226,7 +226,7 @@
 
     std::stringstream details;
     Serialize(&details);
-    LOG(WARNING) << details.str();
+    DVLOG(1) << details.str();
   }
 }
 
diff --git a/services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.cc b/services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
index d981ba1..827fd4e 100644
--- a/services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
+++ b/services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.cc
@@ -66,7 +66,7 @@
   if (!gpu_.is_bound())
     return;
   gpu_.reset();
-  for (auto& waiter : pending_allocation_waiters_)
+  for (auto* waiter : pending_allocation_waiters_)
     waiter->Signal();
   pending_allocation_waiters_.clear();
 }
diff --git a/services/ui/public/cpp/window_compositor_frame_sink.cc b/services/ui/public/cpp/window_compositor_frame_sink.cc
index 84a1419..01944e98 100644
--- a/services/ui/public/cpp/window_compositor_frame_sink.cc
+++ b/services/ui/public/cpp/window_compositor_frame_sink.cc
@@ -70,7 +70,7 @@
 
   gfx::Size frame_size = last_submitted_frame_size_;
   if (!frame.render_pass_list.empty())
-    frame_size = frame.render_pass_list[0]->output_rect.size();
+    frame_size = frame.render_pass_list.back()->output_rect.size();
   if (!local_surface_id_.is_valid() || frame_size != last_submitted_frame_size_)
     local_surface_id_ = id_allocator_.GenerateId();
 
diff --git a/services/ui/surfaces/display_output_surface.cc b/services/ui/surfaces/display_output_surface.cc
index e635a42..37604e7 100644
--- a/services/ui/surfaces/display_output_surface.cc
+++ b/services/ui/surfaces/display_output_surface.cc
@@ -65,11 +65,11 @@
 
 void DisplayOutputSurface::SwapBuffers(cc::OutputSurfaceFrame frame) {
   DCHECK(context_provider_);
-  if (frame.sub_buffer_rect == gfx::Rect(frame.size)) {
-    context_provider_->ContextSupport()->Swap();
-  } else {
+  if (frame.sub_buffer_rect) {
     context_provider_->ContextSupport()->PartialSwapBuffers(
-        frame.sub_buffer_rect);
+        *frame.sub_buffer_rect);
+  } else {
+    context_provider_->ContextSupport()->Swap();
   }
 }
 
diff --git a/services/ui/surfaces/display_output_surface_ozone.cc b/services/ui/surfaces/display_output_surface_ozone.cc
index ea218b2..e63a2e88 100644
--- a/services/ui/surfaces/display_output_surface_ozone.cc
+++ b/services/ui/surfaces/display_output_surface_ozone.cc
@@ -83,7 +83,8 @@
   DCHECK(reshape_size_ == frame.size);
   swap_size_ = reshape_size_;
 
-  buffer_queue_->SwapBuffers(frame.sub_buffer_rect);
+  buffer_queue_->SwapBuffers(frame.sub_buffer_rect ? *frame.sub_buffer_rect
+                                                   : gfx::Rect(swap_size_));
   DisplayOutputSurface::SwapBuffers(std::move(frame));
 }
 
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc
index 654b40aa..800cdd2 100644
--- a/services/ui/ws/server_window.cc
+++ b/services/ui/ws/server_window.cc
@@ -57,7 +57,7 @@
   // parent, as destroying an active transient child may otherwise attempt to
   // refocus us.
   Windows transient_children(transient_children_);
-  for (auto window : transient_children)
+  for (auto* window : transient_children)
     delete window;
   DCHECK(transient_children_.empty());
 
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index 7dfcf12..00f45758 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -782,7 +782,7 @@
 
   // FrameGenerator will add an appropriate reference for the new surface.
   DCHECK(display_manager_->GetDisplayContaining(window));
-  auto display = display_manager_->GetDisplayContaining(window);
+  auto* display = display_manager_->GetDisplayContaining(window);
   if (window == display->GetActiveRootWindow()) {
     display->platform_display()->GetFrameGenerator()->OnSurfaceCreated(
         surface_info);
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 0038c73..8545bb3 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -224,6 +224,10 @@
 #   define SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_CANVAS_HELPERS
+#define SK_SUPPORT_LEGACY_CANVAS_HELPERS
+#endif
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/testing/scripts/run_gpu_integration_test_as_googletest.py b/testing/scripts/run_gpu_integration_test_as_googletest.py
index fd48e06..765bdd1d 100755
--- a/testing/scripts/run_gpu_integration_test_as_googletest.py
+++ b/testing/scripts/run_gpu_integration_test_as_googletest.py
@@ -87,7 +87,7 @@
     rc = 0
     try:
       rc = common.run_command([sys.executable] + rest_args + sharding_args + [
-        '--write-abbreviated-json-results-to', args.isolated_script_test_output,
+        '--write-full-results-to', args.isolated_script_test_output
       ], env=env)
     except Exception:
       traceback.print_exc()
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index ec877c7..34a2cda 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -470,7 +470,10 @@
             ],
             "experiments": [
                 {
-                    "name": "Enabled"
+                    "name": "Enabled_Warmup",
+                    "params": {
+                        "enable_warmup": "true"
+                    }
                 }
             ]
         }
@@ -1391,6 +1394,25 @@
             ]
         }
     ],
+    "NetworkSchedulerYielding": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "win",
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NetworkSchedulerYielding"
+                    ]
+                }
+            ]
+        }
+    ],
     "NetworkTimeQueries": [
         {
             "platforms": [
@@ -1507,6 +1529,22 @@
             ]
         }
     ],
+    "OmniboxBundledExperimentV1": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Beta_Android_PhysWeb_QuerySuggest_Experiment",
+                    "params": {
+                        "PhysicalWebAfterTyping": "true",
+                        "PhysicalWebZeroSuggest": "true"
+                    }
+                }
+            ]
+        }
+    ],
     "OutOfProcessPac": [
         {
             "platforms": [
diff --git a/third_party/.gitignore b/third_party/.gitignore
new file mode 100644
index 0000000..6686cc2
--- /dev/null
+++ b/third_party/.gitignore
@@ -0,0 +1,199 @@
+# This file is needed for projects that has this directory as a separate Git
+# mirror in DEPS. Without it, a lot is wiped and re-downloaded for each sync.
+/__START__
+/accessibility-developer-tools/
+/accessibility_test_framework/lib/*.jar
+/adobe/flash/binaries
+/adobe/flash/symbols
+/amd/
+/android_protobuf/src
+/android_support_test_runner/lib/*.aar
+/android_support_test_runner/lib/*.jar
+/android_tools/
+/android_tools_internal/
+/android_webview_glue/src
+/angle
+/angle_dx11
+/apache-portable-runtime/src
+/apache_velocity/lib/*.jar
+/apache-win32/bin/*.exe
+/apache-win32/bin/*.dll
+/apache-win32/bin/iconv/*.so
+/apache-win32/modules/*.so
+/apache-win32/modules/*.dll
+/asan
+/bidichecker
+/bison
+/boringssl/src
+/bouncycastle/lib/*.jar
+/byte_buddy/lib/*.jar
+/cacheinvalidation/cacheinvalidation_unittests_run.xml
+/cardboard-java/src
+/catapult
+/ced/src
+/chromeos_login_manager
+/chromeos_text_input
+/chromite
+/cld_2/src
+/cld_3/src
+/colorama/src
+/cros
+/cros_system_api
+/custom_tabs_client/src
+/cygwin
+/deqp/src
+/directxsdk
+/dom_distiller_js/dist
+/drmemory/drmemory-windows-sfx.exe
+/drmemory/unpacked
+/elfutils/src
+/errorprone/lib
+/espresso/lib/*.jar
+/eyesfree/src
+/ffmpeg
+/findbugs
+/flac
+/flatbuffers/src
+/fontconfig/src
+/freetype-android/src
+/freetype2/src
+/gestures/gestures
+/gles2_conform
+/glslang/src
+/glslang-angle/src
+/gnu_binutils/
+/google_appengine_cloudstorage
+/google_toolbox_for_mac/src
+/googlemac
+/gvr-android-sdk/common_library.aar
+/gvr-android-sdk/libgvr_shim_static_arm.a
+/gvr-android-sdk/libgvr_shim_static_arm64.a
+/gvr-android-sdk/src
+/gperf
+/guava/lib/*.jar
+/hamcrest/lib/*.jar
+/hunspell_dictionaries
+/icu
+/icu4j/lib/*.jar
+/intellij/lib/*.jar
+/inspector_protocol
+/javax_inject/lib/*.jar
+/jsoncpp/source
+/jsr-305/src
+/junit/src
+/khronos_glcts
+/leakcanary/src
+/leveldatabase/src
+/leveldb
+/libc++-static/libc++.a
+/libaddressinput/src
+/libdrm/src
+/libevdev/src
+/libexif/sources
+/libFuzzer/src
+/libjingle/source
+/libjpeg_turbo
+/liblouis/src
+/libphonenumber/dist
+/libsrtp
+/libupnp
+/libvpx/source/libvpx
+/libwebm/source
+/libyuv
+/lighttpd
+/llvm
+/llvm-allocated-type
+/llvm-bootstrap
+/llvm-build
+/lss
+/mesa/src
+/mingw-w64
+/minigbm/src
+/mkl
+/mocha
+/mockito/src
+/nacl_sdk_binaries/
+/netty-tcnative/src
+/netty4/src
+/node/linux
+/node/mac
+/node/node_modules
+/node/*.tar.gz
+/node/win
+/nss
+/objenesis/lib/*.jar
+/omaha/src/omaha
+/openmax_dl/
+/openh264/src
+/ow2_asm/lib/*.jar
+/pdfsqueeze
+/pdfium
+/pefile
+/perl
+/ppapi
+/psyco_win32
+/pthreads-win32
+/py_trace_event/src
+/pyelftools
+/pyftpdlib/src
+/pylib
+/pymox/src
+/python_24
+/python_26
+/pywebsocket/src
+/pywebsocket/src
+/re2/src
+/requests/src
+/retrolambda/*.jar
+/robolectric/lib/*.jar
+/robolectric/robolectric
+/scan-build/src
+/scons-2.0.1
+/sfntly/src
+/shaderc/src
+/skia
+/smhasher/src
+/snappy/src
+/spirv-headers/src
+/SPIRV-Tools/src
+/spirv-tools-angle/src
+/sqlite4java/lib/**/*.dll
+/sqlite4java/lib/**/*.jar
+/sqlite4java/lib/**/*.jnilib
+/sqlite4java/lib/**/*.so
+/swiftshader/
+/syzygy
+/syzygy/binaries
+/tsan/
+/ub-uiautomator/lib
+/usb_ids
+/usrsctp/usrsctplib
+/v8-i18n
+/valgrind
+/vulkan-validation-layers/src
+/visualmetrics
+/wayland/src
+/wayland-protocols/src
+/wds/src
+/webdriver/pylib
+/webdriver/python/selenium
+/webgl
+/webgl/src
+/webpagereplay/
+/webrtc
+/widevine/cdm/chromeos
+/widevine/cdm/linux
+/widevine/cdm/mac
+/widevine/cdm/win
+/widevine/scripts
+/widevine/test/license_server
+/win_toolchain/.timestamps
+/win_toolchain/files
+/wix
+/xdg-utils
+/xulrunner-sdk
+/yasm/binaries
+/yasm/generate_files.xml
+/yasm/source/patched-yasm
+/yasm/yasm.xml
+
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
index 500bbcb..81f62a3 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/site-per-process
@@ -10,8 +10,8 @@
 crbug.com/669083 virtual/mojo-loading/http/tests/security/frameNavigation/xss-DENIED-top-navigation-without-user-gesture.html [ Failure ]
 
 # https://crbug.com/661725 - Propagating user gesture via postMessage doesn't work for OOPIFs
-crbug.com/661725 http/tests/security/frameNavigation/xss-ALLOWED-top-navigation-after-postMessage.html [ Timeout ]
-crbug.com/661725 virtual/mojo-loading/http/tests/security/frameNavigation/xss-ALLOWED-top-navigation-after-postMessage.html [ Timeout ]
+crbug.com/661725 http/tests/security/frameNavigation/xss-ALLOWED-top-navigation-after-postMessage.html [ Failure Timeout ]
+crbug.com/661725 virtual/mojo-loading/http/tests/security/frameNavigation/xss-ALLOWED-top-navigation-after-postMessage.html [ Failure Timeout ]
 
 # https://crbug.com/582245 - no exception, b/c BindingSecurity::shouldAllowAccessTo exits early when |!target|.
 crbug.com/582245 http/tests/security/xss-DENIED-getSVGDocument-iframe.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 822cf3a..bdacc30 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -135,6 +135,12 @@
 crbug.com/664852 virtual/gpu/fast/canvas/canvas-lost-gpu-context.html [ Pass Failure ]
 crbug.com/664852 virtual/gpu/fast/canvas/OffscreenCanvas-2d-drawImage.html [ Pass Failure ]
 
+# Added 2016-12-14
+crbug.com/674396 [ Win ] compositing/reflections/nested-reflection-transition.html [ Pass Failure ]
+
+# Added 2016-12-15
+crbug.com/674468 [ Trusty ] compositing/reflections/nested-reflection-transition.html [ Pass Failure ]
+
 # Added 2017-01-16
 crbug.com/681471 paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ]
 crbug.com/681471 virtual/disable-spinvalidation/paint/invalidation/media-audio-no-spurious-repaints.html [ Failure Pass Timeout ]
@@ -1663,6 +1669,10 @@
 crbug.com/618082 [ Win10 ] printing/thead-repeats-at-top-of-each-page.html [ Failure ]
 crbug.com/618082 [ Win10 ] virtual/threaded/printing/thead-repeats-at-top-of-each-page.html [ Failure ]
 
+crbug.com/695203 inspector/sources/debugger-breakpoints/debugger-reload-breakpoints-with-source-maps.html [ NeedsManualRebaseline ]
+crbug.com/695203 inspector/sources/debugger-breakpoints/possible-breakpoints.html [ NeedsManualRebaseline ]
+crbug.com/695203 inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html [ NeedsManualRebaseline ]
+
 crbug.com/690486 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-cjk.html [ Failure Pass ]
 
 crbug.com/474759 fast/writing-mode/vertical-rl-replaced-selection.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-cancelable.html b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-cancelable.html
new file mode 100644
index 0000000..94dda10
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/inputevents/inputevent-cancelable.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>InputEvent: cancelable</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<style>
+div {
+    width: 100px;
+    height: 100px;
+}
+</style>
+</head>
+<body>
+<div id="editable" contenteditable></div>
+<div id="editable1" contenteditable>EditableText</div>
+<div id="editable2" contenteditable></div>
+<script>
+function simulateDragDrop(dragElement, dropElement) {
+    if (dragElement.select) {
+        dragElement.select();
+    } else {
+        var selection = window.getSelection();
+        selection.collapse(dragElement, 0);
+        selection.extend(dragElement, 1);
+    }
+
+    eventSender.mouseMoveTo(dragElement.offsetLeft + dragElement.offsetWidth / 2,
+                            dragElement.offsetTop + dragElement.offsetHeight / 2);
+    eventSender.mouseDown();
+    eventSender.leapForward(600);
+    eventSender.mouseMoveTo(dropElement.offsetLeft + dropElement.offsetWidth / 2,
+                            dropElement.offsetTop + dropElement.offsetHeight / 2);
+    eventSender.mouseUp();
+}
+
+async_test(t => {
+    assert_not_equals(window.eventSender, undefined, 'This test requires eventSender.');
+    assert_not_equals(window.testRunner, undefined, 'This test requires testRunner.');
+    assert_not_equals(internals, undefined, 'This test requires internals.');
+    assert_not_equals(textInputController, undefined, 'This test requires textInputController.');
+
+    const editable = document.getElementById('editable');
+    const editable1 = document.getElementById('editable1');
+    const editable2 = document.getElementById('editable2');
+    const kNoncancelableInputTypes = [
+        'insertText', 'insertLineBreak', 'insertParagraph',
+        'insertCompositionText', 'insertReplacementText',
+        'deleteWordBackward', 'deleteWordForward',
+        'deleteLineBackward', 'deleteLineForward',
+        'deleteContentBackward', 'deleteContentForward',
+    ];
+
+    let lastBeforeInputType = '';
+    document.addEventListener('beforeinput', t.step_func(event => {
+        lastBeforeInputType = event.inputType;
+        assert_equals(kNoncancelableInputTypes.indexOf(event.inputType) === -1, event.cancelable);
+    }));
+
+    function testKeyDown(key, modifiers, inputType) {
+        lastBeforeInputType = '';
+        eventSender.keyDown(key, modifiers);
+        assert_equals(inputType, lastBeforeInputType, `${modifiers.toString()}+${key} should produce input type: ${inputType}`);
+    }
+
+    function testCommand(command, inputType) {
+        lastBeforeInputType = '';
+        testRunner.execCommand(command);
+        assert_equals(inputType, lastBeforeInputType, `${command} should produce input type: ${inputType}`);
+    }
+
+    // Typing
+    editable.focus();
+    testKeyDown('a', [], 'insertText');
+    testKeyDown('6', [], 'insertText');
+    testKeyDown('l', ['shiftKey'], 'insertText');
+    testKeyDown('w', ['shiftKey'], 'insertText');
+    testKeyDown('Enter', [], 'insertParagraph');
+    testKeyDown('Enter', ['shiftKey'], 'insertLineBreak');
+
+    // Deletion
+    const isMacOS = navigator.platform.indexOf('Mac') === 0;
+    const deleteWordModifier = isMacOS ? 'altKey' : 'ctrlKey';
+    editable.innerHTML = 'abc def</br>123 456';
+    const selection = window.getSelection();
+    selection.collapse(editable, 1); // End of first line.
+    testKeyDown('Backspace', [], 'deleteContentBackward');
+    testKeyDown('Delete', [], 'deleteContentForward');
+    testKeyDown('Backspace', [deleteWordModifier], 'deleteWordBackward');
+    testKeyDown('Delete', [deleteWordModifier], 'deleteWordForward');
+
+    // Format
+    editable.innerHTML = 'abc';
+    selection.collapse(editable, 0);
+    selection.extend(editable, 1);
+    testCommand('bold', 'formatBold');
+    testCommand('italic', 'formatItalic');
+    testCommand('underline', 'formatUnderline');
+    testCommand('strikeThrough', 'formatStrikeThrough');
+    testCommand('superscript', 'formatSuperscript');
+    testCommand('subscript', 'formatSubscript');
+
+    // Cut and paste
+    editable.innerHTML = 'abc';
+    selection.collapse(editable, 0);
+    selection.extend(editable, 1);
+    testKeyDown('Cut', [], 'deleteByCut');
+    testKeyDown('Paste', [], 'insertFromPaste');
+
+    // Drag and drop
+    simulateDragDrop(editable1, editable2);
+    assert_equals('insertFromDrop', lastBeforeInputType);
+
+    // Undo and redo
+    testCommand('undo', 'historyUndo');
+    testCommand('redo', 'historyRedo');
+
+    // Spell-checker
+    editable.innerHTML = 'appla';
+    selection.collapse(editable, 0);
+    selection.extend(editable, 1);
+    internals.setMarker(document, selection.getRangeAt(0), 'Spelling');
+    internals.replaceMisspelled(document, 'apple');
+    assert_equals('insertReplacementText', lastBeforeInputType);
+
+    // IME
+    editable.innerHTML = 'wo';
+    selection.collapse(editable, 0);
+    selection.extend(editable, 1);
+    textInputController.setComposition('word');
+    assert_equals('insertCompositionText', lastBeforeInputType);
+
+    t.done();
+}, 'Text input and IME related input types are non-cancelable.');
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html
index bed039a2..aef33f31 100644
--- a/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/CanvasCaptureMediaStream-capture-out-of-DOM-element.html
@@ -5,35 +5,51 @@
 
 async_test(t => {
   var canvas = document.createElement('canvas');
-
-  var recorder = new MediaRecorder(canvas.captureStream());
-  recorder.ondataavailable = function() {
-    t.step_func_done(function() {
-      assert_true(event.data.size > 0, 'Recorded data size should be > 0');
-    })();
-    recorder.stop();
-  }
-  recorder.start(0);
-
   var ctx = canvas.getContext('2d');
   ctx.fillStyle = 'green';
+  var recorder = new MediaRecorder(canvas.captureStream());
+  var frameCount = 0;
+
+  recorder.ondataavailable = function() {
+    t.step(function() {
+      assert_true(event.data.size > 0, 'Recorded data size should be > 0');
+    });
+
+    frameCount = frameCount + 1;
+    if (frameCount > 3) {
+      recorder.stop();
+      t.done();
+    } else {
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
+    }
+  }
+
+  recorder.start(0);
   ctx.fillRect(0, 0, canvas.width, canvas.height);
-}, "Verify that drawing to a 2D canvas that is not attached to the DOM dispatches a frame to an attached MediaRecorder." );
+}, "Verify that drawing to a 2D canvas that is not attached to the DOM dispatches frames to an attached MediaRecorder." );
 
 async_test(t => {
   var canvas = document.createElement('canvas');
-
+  var gl = canvas.getContext('webgl');
+  gl.clearColor(0, 1, 0, 1);
   var recorder = new MediaRecorder(canvas.captureStream());
+  var frameCount = 0;
+
   recorder.ondataavailable = function() {
-    t.step_func_done(function() {
+    t.step(function() {
       assert_true(event.data.size > 0, 'Recorded data size should be > 0');
-    })();
-    recorder.stop();
+    });
+
+    frameCount = frameCount + 1;
+    if (frameCount > 3) {
+      recorder.stop();
+      t.done();
+    } else {
+      gl.clear(gl.COLOR_BUFFER_BIT);
+    }
   }
   recorder.start(0);
 
-  var gl = canvas.getContext('webgl');
-  gl.clearColor(0, 1, 0, 1);
   gl.clear(gl.COLOR_BUFFER_BIT);
-}, "Verify that drawing to a webgl canvas that is not attached to the DOM dispatches a frame to an attached MediaRecorder." );
+}, "Verify that drawing to a webgl canvas that is not attached to the DOM dispatches frames to an attached MediaRecorder." );
 </script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-expected.txt
index 05e795b..350ba2a6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope-expected.txt
@@ -1,5 +1,22 @@
 
 
+Running: testIgnoreCaseAndIgnoreDynamicScript
+Search result #1: uiSourceCode.url = http://127.0.0.1:8000/inspector/search/resources/search.css
+  search match #1: lineNumber = 0, lineContent = 'div.searchTestUniqueString {'
+  search match #2: lineNumber = 4, lineContent = 'div.searchTestUniqueString:hover {'
+  search match #3: lineNumber = 5, lineContent = '    /* another searchTestUniqueString occurence */'
+Search result #2: uiSourceCode.url = http://127.0.0.1:8000/inspector/search/resources/search.html
+  search match #1: lineNumber = 4, lineContent = '<script>window.eval("function searchTestUniqueString() {}");</script>'
+  search match #2: lineNumber = 6, lineContent = '<div>searchTestUniqueString</div>'
+  search match #3: lineNumber = 8, lineContent = '<!-- searchTestUniqueString -->'
+  search match #4: lineNumber = 10, lineContent = '<div id="searchTestUniqueString">div text</div>'
+Search result #3: uiSourceCode.url = http://127.0.0.1:8000/inspector/search/resources/search.js
+  search match #1: lineNumber = 0, lineContent = 'function searchTestUniqueString()'
+  search match #2: lineNumber = 3, lineContent = '    // searchTestUniqueString two occurences on the same line searchTestUniqueString'
+  search match #3: lineNumber = 4, lineContent = '    // searchTestUniqueString on the next line.'
+  search match #4: lineNumber = 10, lineContent = '    searchTestUniqueString();'
+  search match #5: lineNumber = 11, lineContent = '    // SEARCHTestUniqueString();'
+
 Running: testIgnoreCase
 Search result #1: uiSourceCode.url = debugger:///VMXX
   search match #1: lineNumber = 0, lineContent = 'function searchTestUniqueString() {}'
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope.html b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope.html
index 97077f3..658c791 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/search/sources-search-scope.html
@@ -20,13 +20,22 @@
     function step2()
     {
         InspectorTest.runTestSuite([
-            function testIgnoreCase(next)
+            function testIgnoreCaseAndIgnoreDynamicScript(next)
             {
                 var query = "searchTest" + "UniqueString";
                 var searchConfig = new Workspace.SearchConfig(query, true, false);
                 InspectorTest.runSearchAndDumpResults(scope, searchConfig, next);
             },
 
+            function testIgnoreCase(next)
+            {
+                Common.settingForTest('searchInAnonymousAndContentScripts').set(true);
+                var query = "searchTest" + "UniqueString";
+                var searchConfig = new Workspace.SearchConfig(query, true, false);
+                InspectorTest.runSearchAndDumpResults(scope, searchConfig, next);
+            },
+
+
             function testCaseSensitive(next)
             {
                 var query = "searchTest" + "UniqueString";
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts-expected.txt
new file mode 100644
index 0000000..936351fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts-expected.txt
@@ -0,0 +1,29 @@
+Verify that removal of one of the multiple projects, all of which are associated with the same frame, doesn't lead navigator to discard the frame treenode.
+
+
+
+================================================
+Adding urls
+top
+  127.0.0.1:8000
+    inspector
+      sources
+        navigator-view-content-scripts.html
+      inspector-test.js
+  localhost:8080
+    LayoutTests/inspector/debugger/foo/bar
+      script.js
+
+
+================================================
+Removing contentScripts project
+top
+  127.0.0.1:8000
+    inspector
+      sources
+        navigator-view-content-scripts.html
+      inspector-test.js
+  localhost:8080
+    LayoutTests/inspector/debugger/foo/bar
+      script.js
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts.html b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts.html
new file mode 100644
index 0000000..a3f4835
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/navigator-view-content-scripts.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+
+<script>
+function test()
+{
+    function addUISourceCode(url, isContentScript)
+    {
+        var contentProvider = Common.StaticContentProvider.fromString(url, Common.resourceTypes.Script, "");
+        var networkProject = Bindings.NetworkProject.forTarget(InspectorTest.mainTarget);
+        var uiSourceCode = networkProject.addFile(contentProvider, InspectorTest.mainFrame(), isContentScript);
+        return uiSourceCode;
+    }
+
+    var rootURL = "http://localhost:8080/LayoutTests/inspector/debugger/";
+    var sourcesNavigatorView = new Sources.SourcesNavigatorView();
+    sourcesNavigatorView.show(UI.inspectorView.element);
+
+    InspectorTest.addResult("\n\n================================================");
+    InspectorTest.addResult("Adding urls");
+    addUISourceCode(rootURL + "foo/bar/script.js", false);
+    var contentUISourceCode = addUISourceCode(rootURL + "foo/bar/contentScript2.js?a=1", true);
+    InspectorTest.dumpNavigatorView(sourcesNavigatorView);
+
+    InspectorTest.addResult("\n\n================================================");
+    InspectorTest.addResult("Removing contentScripts project");
+    contentUISourceCode.project().removeProject();
+    InspectorTest.dumpNavigatorView(sourcesNavigatorView);
+    InspectorTest.completeTest();
+}
+</script>
+
+</head>
+<body onload="runTest()">
+<p>Verify that removal of one of the multiple projects, all of which are associated with the same
+frame, doesn't lead navigator to discard the frame treenode.</p>
+</p>
+</body>
+
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html b/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html
new file mode 100644
index 0000000..06afc29e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/usb/insecure-context.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script>
+'use strict';
+
+if (window.location.origin != get_host_info().UNAUTHENTICATED_ORIGIN) {
+  window.location = get_host_info().UNAUTHENTICATED_ORIGIN +
+                    window.location.pathname;
+} else {
+  test(t => {
+    assert_false(window.isSecureContext);
+    assert_true(navigator.usb == undefined);
+  }, 'navigator.usb is not present in an insecure context');
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/usb/secure-context.html b/third_party/WebKit/LayoutTests/http/tests/usb/secure-context.html
new file mode 100644
index 0000000..242f704
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/usb/secure-context.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/get-host-info.js"></script>
+<script>
+'use strict';
+
+if (window.location.origin != get_host_info().AUTHENTICATED_ORIGIN) {
+  window.location = get_host_info().AUTHENTICATED_ORIGIN +
+                    window.location.pathname;
+} else {
+  test(t => {
+    assert_true(window.isSecureContext);
+    assert_true(navigator.usb instanceof USB);
+  }, 'navigator.usb is present in an insecure context');
+}
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/incrementer.wasm b/third_party/WebKit/LayoutTests/http/tests/wasm/incrementer.wasm
index eba6007..47afcde 100644
--- a/third_party/WebKit/LayoutTests/http/tests/wasm/incrementer.wasm
+++ b/third_party/WebKit/LayoutTests/http/tests/wasm/incrementer.wasm
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/debugger-reload-breakpoints-with-source-maps-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/debugger-reload-breakpoints-with-source-maps-expected.txt
deleted file mode 100644
index bd15332..0000000
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/debugger-reload-breakpoints-with-source-maps-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Tests "reload" from within inspector window while on pause.
-
-
-Breakpoint sidebar pane before reload:
-source1.js:15    var handler = new ClickHandler();
-source1.js:17}
-Page reloaded.
-Breakpoint sidebar pane after reload:
-source1.js:15    var handler = new ClickHandler();
-source1.js:17}
-
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
index 14bac31c..16d03a1 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
@@ -3,11 +3,15 @@
 Locations for first line
 All locations
 location(2, 2)
+location(2, 10)
+location(2, 20)
 location(2, 31)
 location(2, 34)
+location(2, 36)
 location(2, 47)
 location(2, 49)
 location(3, 2)
+location(3, 10)
 location(4, 2)
 location(5, 0)
 Existing location by position
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
index 6070515..afae367 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
@@ -4,7 +4,9 @@
 Running: testAddRemoveBreakpoint
 Setting breakpoint
 breakpoint at 3
-  inline breakpoint at (3, 49)
+  inline breakpoint at (3, 20)
+  inline breakpoint at (3, 30) disabled
+  inline breakpoint at (3, 49) disabled
   inline breakpoint at (3, 56) disabled
 Toggle breakpoint
 
@@ -16,16 +18,22 @@
 Running: clickByInlineBreakpoint
 Setting breakpoint
 breakpoint at 3
-  inline breakpoint at (3, 49)
+  inline breakpoint at (3, 20)
+  inline breakpoint at (3, 30) disabled
+  inline breakpoint at (3, 49) disabled
   inline breakpoint at (3, 56) disabled
 Click by second breakpoint
 breakpoint at 3
-  inline breakpoint at (3, 49)
-  inline breakpoint at (3, 56)
+  inline breakpoint at (3, 20)
+  inline breakpoint at (3, 30)
+  inline breakpoint at (3, 49) disabled
+  inline breakpoint at (3, 56) disabled
 Click by first breakpoint
 breakpoint at 3
+  inline breakpoint at (3, 20) disabled
+  inline breakpoint at (3, 30)
   inline breakpoint at (3, 49) disabled
-  inline breakpoint at (3, 56)
+  inline breakpoint at (3, 56) disabled
 Click by second breakpoint
 
 Running: toggleBreakpointInAnotherLineWontRemoveExisting
@@ -36,7 +44,9 @@
   inline breakpoint at (4, 36) disabled
 Setting breakpoint in line 3
 breakpoint at 3
-  inline breakpoint at (3, 49)
+  inline breakpoint at (3, 20)
+  inline breakpoint at (3, 30) disabled
+  inline breakpoint at (3, 49) disabled
   inline breakpoint at (3, 56) disabled
 breakpoint at 4
   inline breakpoint at (4, 9)
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html
index 8edd25c..42de865 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network/timeline-network-resource-details.html
@@ -35,7 +35,11 @@
             var rows = element.querySelectorAll(".timeline-details-view-row");
             for (var i = 0; i < rows.length; ++i) {
                 var title = rows[i].firstChild.firstChild.textContent;
-                var value = rows[i].lastChild.firstChild.textContent;
+                var value = rows[i].lastChild.firstChild;
+                if (value.children && value.children.length)
+                  value = Array.from(value.children, element => element.textContent).slice(1).join('');
+                else
+                  value = value.textContent;
                 if (title === "Duration" || title === "Mime Type")
                     value = typeof value;
                 if (/^file:\/\//.test(value))
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-expected.txt
index 363e3a4..d1b55da 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-expected.txt
@@ -8,8 +8,8 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
-          "rect": [0, 200, 440, 140],
-          "reason": "content box change"
+          "rect": [0, 280, 440, 60],
+          "reason": "incremental"
         },
         {
           "object": "LayoutBlockFlow (positioned) DIV id='target1' class='content-box'",
@@ -17,6 +17,11 @@
           "reason": "incremental"
         },
         {
+          "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
+          "rect": [380, 200, 60, 140],
+          "reason": "incremental"
+        },
+        {
           "object": "LayoutBlockFlow (positioned) DIV id='target1' class='content-box'",
           "rect": [380, 0, 60, 140],
           "reason": "incremental"
@@ -31,7 +36,7 @@
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
-      "reason": "content box change"
+      "reason": "incremental"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
index f700373f..0ba51d1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-sizing-padding-keeping-size-expected.txt
@@ -4,7 +4,29 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "drawsContent": true
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
+          "rect": [0, 200, 100, 100],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='target1' class='content-box'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='target1' class='content-box'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='target2' class='border-box'",
+      "reason": "style change"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-content-size-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-content-size-expected.txt
index f90b469..c4d681d 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-content-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-content-size-expected.txt
@@ -9,12 +9,12 @@
         {
           "object": "LayoutBlockFlow (positioned) DIV id='target2' class='outer'",
           "rect": [0, 200, 140, 140],
-          "reason": "background obscuration change"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow (positioned) DIV id='target1' class='outer'",
-          "rect": [0, 100, 140, 40],
-          "reason": "incremental"
+          "rect": [0, 0, 140, 140],
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow DIV class='inner'",
@@ -25,11 +25,6 @@
           "object": "LayoutBlockFlow DIV class='inner'",
           "rect": [0, 200, 100, 100],
           "reason": "bounds change"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV id='target1' class='outer'",
-          "rect": [100, 0, 40, 140],
-          "reason": "incremental"
         }
       ]
     }
@@ -37,11 +32,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutBlockFlow (positioned) DIV id='target1' class='outer'",
-      "reason": "incremental"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow (positioned) DIV id='target2' class='outer'",
-      "reason": "background obscuration change"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow DIV class='inner'",
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-visual-size-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-visual-size-expected.txt
index 608272df..7263731 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-visual-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/padding-keeping-visual-size-expected.txt
@@ -9,20 +9,29 @@
         {
           "object": "LayoutBlockFlow (positioned) DIV id='target2' class='outer'",
           "rect": [0, 200, 100, 100],
-          "reason": "background obscuration change"
+          "reason": "style change"
         },
         {
           "object": "LayoutBlockFlow DIV class='inner'",
           "rect": [0, 200, 100, 100],
           "reason": "bounds change"
+        },
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='target1' class='outer'",
+          "rect": [0, 0, 100, 100],
+          "reason": "style change"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow (positioned) DIV id='target1' class='outer'",
+      "reason": "style change"
+    },
+    {
       "object": "LayoutBlockFlow (positioned) DIV id='target2' class='outer'",
-      "reason": "background obscuration change"
+      "reason": "style change"
     },
     {
       "object": "LayoutBlockFlow DIV class='inner'",
diff --git a/third_party/WebKit/LayoutTests/presentation/presentation-onreceiverconnection.html b/third_party/WebKit/LayoutTests/presentation/presentation-onreceiverconnection.html
new file mode 100644
index 0000000..b7f550a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/presentation/presentation-onreceiverconnection.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/mojo-helpers.js"></script>
+<script src="resources/presentation-service-mock.js"></script>
+<script>
+
+async_test(t => {
+  internals.settings.setPresentationReceiver(true);
+  t.add_cleanup(_ => { internals.settings.setPresentationReceiver(false); });
+
+  presentationServiceMock.then(mockService => {
+    // Invoke mockService.setClient().
+    const receiver = navigator.presentation.receiver;
+
+    // Make sure it is invoked after calling setClient().
+    setTimeout(() => {
+      const url = 'http://example.com/a.html';
+      const id = 'fakeSessionId';
+      mockService.onReceiverConnectionAvailable(url, id);
+
+      receiver.connectionList.then(
+        t.step_func_done(list => {
+          assert_equals(list.connections.length, 1);
+          assert_equals(list.connections[0].url, url);
+          assert_equals(list.connections[0].id, id);
+      }));
+    });
+  });
+}, "Test presentation.receiver.connectionList resolves with incoming connection.");
+
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js b/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
index 3db3d1e..15007fe 100644
--- a/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
+++ b/third_party/WebKit/LayoutTests/presentation/resources/presentation-service-mock.js
@@ -8,9 +8,13 @@
     'presentationServiceMock',
     [
       'third_party/WebKit/public/platform/modules/presentation/presentation.mojom',
+      'url/mojo/url.mojom',
       'mojo/public/js/bindings',
     ]).then(mojo => {
-      let [ presentationService, bindings ] = mojo.modules;
+      let [ presentationService, url, bindings ] = mojo.modules;
+
+      class MockPresentationConnection {
+      };
 
       class PresentationServiceMock {
         constructor(interfaceProvider) {
@@ -23,6 +27,10 @@
               presentationService.PresentationService);
         }
 
+        setClient(client) {
+          this.client_ = client;
+        }
+
         startSession(urls) {
           return Promise.resolve({
               sessionInfo: { url: urls[0], id: 'fakesession' },
@@ -36,6 +44,22 @@
               error: null,
           });
         }
+
+        onReceiverConnectionAvailable(strUrl, id) {
+          const mojoUrl = new url.Url();
+          mojoUrl.url = strUrl;
+          const controllerConnectionPtr = new presentationService.PresentationConnectionPtr();
+          const connectionBinding = new bindings.Binding(
+              presentationService.PresentationConnection,
+              new MockPresentationConnection(),
+              bindings.makeRequest(controllerConnectionPtr));
+          const receiverConnectionPtr = new presentationService.PresentationConnectionPtr();
+
+          this.client_.onReceiverConnectionAvailable(
+              { url: mojoUrl, id: id },
+              controllerConnectionPtr,
+              bindings.makeRequest(receiverConnectionPtr));
+        }
       }
 
       return new PresentationServiceMock(mojo.frameInterfaces);
@@ -47,9 +71,9 @@
   if (!('eventSender' in window))
     return;
 
-  var boundingRect = button.getBoundingClientRect();
-  var x = boundingRect.left + boundingRect.width / 2;
-  var y = boundingRect.top + boundingRect.height / 2;
+  const boundingRect = button.getBoundingClientRect();
+  const x = boundingRect.left + boundingRect.width / 2;
+  const y = boundingRect.top + boundingRect.height / 2;
 
   eventSender.mouseMoveTo(x, y);
   eventSender.mouseDown();
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential-expected.txt
deleted file mode 100644
index 34420e2..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test exponential distance model of AudioPannerNode.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS Number of impulses found matches number of panner nodes.
-PASS Distance gains are correct.
-PASS Distance test passed for distance model exponential
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
index b1a07da2..37cc0c3f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-exponential.html
@@ -1,36 +1,27 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!doctype html>
 <html>
   <head>
-    <script src="../../resources/js-test.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script> 
     <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audit.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
-    <div id="description"></div>
-    <div id="console"></div>
-
     <script>
-      description("Test exponential distance model of AudioPannerNode.");
+      let audit = Audit.createTaskRunner();
 
-      function runTest() {
-          if (window.testRunner) {
-              testRunner.dumpAsText();
-              testRunner.waitUntilDone();
-          }
-
-          window.jsTestIsAsync = true;
-
+      audit.define("test", (task, should) => {
+          task.describe("Exponential distance model for PannerNode");
           // Create offline audio context.
           context = new OfflineAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
 
-          createTestAndRun(context, "exponential");
-      }
+          createTestAndRun(context, "exponential", should)
+            .then(() => task.done());
+      });
 
-      runTest();
-      successfullyParsed = true;
-
+      audit.run();
     </script>
 
   </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse-expected.txt
deleted file mode 100644
index 5f35cdfc..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test inverse distance model of AudioPannerNode.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS Number of impulses found matches number of panner nodes.
-PASS Distance gains are correct.
-PASS Distance test passed for distance model inverse
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
index 49b7c3fe..3afb2a3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-inverse.html
@@ -1,36 +1,26 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!doctype html>
 <html>
   <head>
-    <script src="../../resources/js-test.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script> 
     <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audit.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
-    <div id="description"></div>
-    <div id="console"></div>
-
     <script>
-      description("Test inverse distance model of AudioPannerNode.");
+      let audit = Audit.createTaskRunner();
 
-      function runTest() {
-          if (window.testRunner) {
-              testRunner.dumpAsText();
-              testRunner.waitUntilDone();
-          }
-
-          window.jsTestIsAsync = true;
-
+      audit.define("test", (task, should) => {
           // Create offline audio context.
           context = new OfflineAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
 
-          createTestAndRun(context, "inverse");
-      }
+          createTestAndRun(context, "inverse", should)
+            .then(() => task.done());
+      });
 
-      runTest();
-      successfullyParsed = true;
-
+      audit.run();
     </script>
 
   </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear-expected.txt b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear-expected.txt
deleted file mode 100644
index adbde13..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Test linear distance model of AudioPannerNode.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS Number of impulses found matches number of panner nodes.
-PASS Distance gains are correct.
-PASS Distance test passed for distance model linear
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
index 335bf11..fb285a0f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/distance-linear.html
@@ -1,36 +1,27 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!doctype html>
 <html>
   <head>
-    <script src="../../resources/js-test.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script> 
     <script src="../resources/audit-util.js"></script>
-    <script src="../resources/audio-testing.js"></script>
+    <script src="../resources/audit.js"></script>
     <script src="../resources/distance-model-testing.js"></script>
   </head>
 
   <body>
-    <div id="description"></div>
-    <div id="console"></div>
-
     <script>
-      description("Test linear distance model of AudioPannerNode.");
+      let audit = Audit.createTaskRunner();
 
-      function runTest() {
-          if (window.testRunner) {
-              testRunner.dumpAsText();
-              testRunner.waitUntilDone();
-          }
-
-          window.jsTestIsAsync = true;
-
+      audit.define("test", (task, should) => {
+          task.describe("Linear distance model PannerNode");
           // Create offline audio context.
           context = new OfflineAudioContext(2, sampleRate * renderLengthSeconds, sampleRate);
 
-          createTestAndRun(context, "linear");
-      }
+          createTestAndRun(context, "linear", should)
+            .then(() => task.done());
+      });
 
-      runTest();
-      successfullyParsed = true;
-
+      audit.run();
     </script>
 
   </body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-expected.txt
deleted file mode 100644
index d815493..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests that WaveShaperNode applies proper non-linear distortion.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS WaveShaperNode properly applied non-linear distortion.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits-expected.txt
deleted file mode 100644
index 3c8dd60..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits-expected.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-Test WaveShaperNode including values outside the range of [-1,1]
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS -1.100000 -> 0.000000.
-PASS -1.000000 -> 0.000000.
-PASS -0.900000 -> 0.100000.
-PASS -0.800000 -> 0.200000.
-PASS -0.700000 -> 0.300000.
-PASS -0.600000 -> 0.400000.
-PASS -0.500000 -> 0.500000.
-PASS -0.400000 -> 0.600000.
-PASS -0.300000 -> 0.700000.
-PASS -0.200000 -> 0.800000.
-PASS -0.100000 -> 0.900000.
-PASS 0.000000 -> 1.000000.
-PASS 0.100000 -> 0.900000.
-PASS 0.200000 -> 0.800000.
-PASS 0.300000 -> 0.700000.
-PASS 0.400000 -> 0.600000.
-PASS 0.500000 -> 0.500000.
-PASS 0.600000 -> 0.400000.
-PASS 0.700000 -> 0.300000.
-PASS 0.800000 -> 0.200000.
-PASS 0.900000 -> 0.100000.
-PASS 1.000000 -> 0.000000.
-PASS 1.100000 -> 0.000000.
-PASS All outputs matched expected results.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
index eb9d4ff3..d49fa57 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-limits.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <html>
   <head>
-    <script src="../../resources/js-test.js"></script>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script> 
+    <script src="../resources/audit-util.js"></script>
+    <script src="../resources/audit.js"></script>
   </head>
 
   <body>
-    <div id="description"></div>
-    <div id="console"></div>
-
     <script>
-      description("Test WaveShaperNode including values outside the range of [-1,1]");
+      var audit = Audit.createTaskRunner();
 
       var context;
       var bufferData;
@@ -48,37 +48,22 @@
         return ref;
       }
 
-      function checkResult (event) {
-        outputData = event.renderedBuffer.getChannelData(0);
+      function checkResult (renderedBuffer, should) {
+        outputData = renderedBuffer.getChannelData(0);
         reference = generateReference();
         var success = true;
         // Verify that every output value matches our expected reference value.
         for (var k = 0; k < outputData.length; ++k) {
            var diff = outputData[k] - reference[k];
-           if (Math.abs(diff) <= diffThreshold) {
-              testPassed(bufferData[k].toFixed(decimals) + " -> " + outputData[k].toFixed(decimals) + ".");
-           } else {
-              testFailed(bufferData[k].toFixed(decimals) + " -> " + outputData[k].toFixed(decimals) + ", but expected " + reference[k].toFixed(decimals) + ".");
-              success = false;
-           }
+          should(Math.abs(diff),
+              "Max error mapping " + bufferData[k].toFixed(decimals) + " to " +
+              outputData[k].toFixed(decimals))
+            .beLessThanOrEqualTo(diffThreshold);
         }
-
-        if (success)
-          testPassed("All outputs matched expected results.");
-        else
-          testFailed("Some outputs did not match expected results.");
-
-        finishJSTest();
       }
 
-      function runTest () {
-        if (window.testRunner) {
-          testRunner.dumpAsText();
-          testRunner.waitUntilDone();
-        }
-
-        window.jsTestIsAsync = true;
-
+      audit.define("test", function (task, should) {
+        task.describe("Test WaveShaperNode including values outside the range of [-1,1]");
         context = new OfflineAudioContext(1, testFrames, sampleRate);
         // Create input values between -1.1 and 1.1
         var buffer = context.createBuffer(1, testFrames, context.sampleRate);
@@ -103,12 +88,12 @@
         shaper.connect(context.destination);
 
         source.start();
-        context.oncomplete = checkResult;
-        context.startRendering();
-      }
+        context.startRendering()
+          .then(buffer => checkResult(buffer, should))
+          .then(() => task.done());
+      });
 
-      runTest();
-      successfullyParsed = true;
+      audit.run();
     </script>
   </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x-expected.txt
deleted file mode 100644
index ffa3eab4..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests 2x WaveShaperNode oversampling.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS 2x WaveShaperNode oversampling within acceptable tolerance.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
index b023d1f..e34a33c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-2x.html
@@ -2,21 +2,16 @@
 
 <html>
 <head>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script> 
 <script src="../resources/audit-util.js"></script>
-<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audit.js"></script>
 <script type="text/javascript" src="../resources/mix-testing.js"></script>
 <script type="text/javascript" src="../resources/waveshaper-testing.js"></script>
 </head>
 
 <body>
-
-<div id="description"></div>
-<div id="console"></div>
-
 <script>
-description("Tests 2x WaveShaperNode oversampling.");
-
 var testParams = {
     "sampleRate": 44100,
     "oversample": "2x",
@@ -24,7 +19,8 @@
     // Should generate harmonics at 9000, 18000, 27000, 36000
     // The last two should be filtered out with the 2x oversampling.
     "fundamentalFrequency": 9000,
-    "acceptableAliasingThresholdDecibels": -75.3
+    "acceptableAliasingThresholdDecibels": -75.3,
+    description: "2x WaveShaperNode oversampling"
 };
 runWaveShaperOversamplingTest(testParams);
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x-expected.txt b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x-expected.txt
deleted file mode 100644
index c67d8215..0000000
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-Tests 4x WaveShaperNode oversampling.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS 4x WaveShaperNode oversampling within acceptable tolerance.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
index ac9b299..68a095f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper-oversample-4x.html
@@ -2,21 +2,16 @@
 
 <html>
 <head>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script> 
 <script src="../resources/audit-util.js"></script>
-<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audit.js"></script>
 <script type="text/javascript" src="../resources/mix-testing.js"></script>
 <script type="text/javascript" src="../resources/waveshaper-testing.js"></script>
 </head>
 
 <body>
-
-<div id="description"></div>
-<div id="console"></div>
-
 <script>
-description("Tests 4x WaveShaperNode oversampling.");
-
 var testParams = {
     "sampleRate": 44100,
     "oversample": "4x",
@@ -24,7 +19,8 @@
     // Should generate harmonics at 18000, 36000, 54000, 72000
     // All except for 18000 should be filtered out with the 4x oversampling.
     "fundamentalFrequency": 18000,
-    "acceptableAliasingThresholdDecibels": -79.9
+    "acceptableAliasingThresholdDecibels": -79.9,
+    description: "4x WaveShaperNode oversampling"
 };
 runWaveShaperOversamplingTest(testParams);
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
index 1330a23..3a42391 100644
--- a/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
+++ b/third_party/WebKit/LayoutTests/webaudio/WaveShaper/waveshaper.html
@@ -2,19 +2,16 @@
 
 <html>
 <head>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script> 
 <script src="../resources/audit-util.js"></script>
-<script src="../resources/audio-testing.js"></script>
+<script src="../resources/audit.js"></script>
 <script type="text/javascript" src="../resources/buffer-loader.js"></script>
 </head>
 
 <body>
-
-<div id="description"></div>
-<div id="console"></div>
-
 <script>
-description("Tests that WaveShaperNode applies proper non-linear distortion.");
+var audit = Audit.createTaskRunner();
 
 var sampleRate = 44100;
 var lengthInSeconds = 4;
@@ -60,9 +57,7 @@
     return curve;
 }
 
-function checkShapedCurve(event) {
-    var buffer = event.renderedBuffer;
-
+function checkShapedCurve(buffer, should) {
     var inputData = inputBuffer.getChannelData(0);
     var outputData = buffer.getChannelData(0);
 
@@ -90,23 +85,11 @@
         }
     }
 
-    if (success) {
-        testPassed("WaveShaperNode properly applied non-linear distortion.");
-    } else {
-        testFailed("WaveShaperNode did not properly apply non-linear distortion.");
-    }
-
-    finishJSTest();
+    should(success, "WaveShaperNode applied non-linear distortion correctly")
+      .beTrue();
 }
 
-function runTest() {
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
-    
-    window.jsTestIsAsync = true;
-        
+audit.define("test", function (task, should) {
     // Create offline audio context.
     context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate);
     
@@ -126,11 +109,12 @@
     
     source.start(0);
     
-    context.oncomplete = checkShapedCurve;
-    context.startRendering();
-}
+    context.startRendering()
+      .then(buffer => checkShapedCurve(buffer, should))
+      .then(task.done.bind(task));
+});
 
-runTest();
+audit.run();
 
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioworklet/audioworklet-testing.js b/third_party/WebKit/LayoutTests/webaudio/audioworklet/audioworklet-testing.js
index 4553fa30..f239ff3 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioworklet/audioworklet-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/audioworklet/audioworklet-testing.js
@@ -1,27 +1,19 @@
-/* @global internals, Should */
-
-// Check if |internals| and its |runtimeFlags.AudioWorklet| are available.
-//
-// The content_shell driven by run-webkit-tests.py is supposed to enable
-// all the experimental web platform features. The flags are exposed via
-// |internals.runtimeFlag|.
-//
-// See: https://www.chromium.org/blink/runtime-enabled-features
-function checkInternalsAndAudioWorkletRuntimeFlag(taskDone) {
-
-  var isInternals = Should('window.internals', window.internals).exist();
-
-  if (!isInternals) {
-    taskDone();
-    return false;
-  }
-
-  var isFlag = Should('window.internals.runtimeFlags.audioWorkletEnabled',
-    window.internals.runtimeFlags.audioWorkletEnabled).beEqualTo(true);
-
-  if (!isFlag) {
-    taskDone();
-  }
-
-  return isFlag;
+/**
+ * Check if |window.internals| and |window.internals.runtimeFlags.AudioWorklet|
+ * are available.
+ *
+ * The content_shell driven by run-webkit-tests.py is supposed to enable all the
+ * experimental web platform features. The flags are exposed via
+ * |internals.runtimeFlag|.
+ *
+ * See: https://www.chromium.org/blink/runtime-enabled-features
+ *
+ * @return {Boolean}
+ */
+function isAudioWorkletEnabled() {
+  return {
+    onContentShell: Boolean(window.internals) &&
+                    Boolean(window.internals.runtimeFlags.audioWorkletEnabled),
+    onBrowser: Boolean(window.Worklet) && Boolean(window.audioWorklet)
+  };
 }
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioworklet/window-audioworklet.html b/third_party/WebKit/LayoutTests/webaudio/audioworklet/window-audioworklet.html
index 9efda23..181e6ba5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioworklet/window-audioworklet.html
+++ b/third_party/WebKit/LayoutTests/webaudio/audioworklet/window-audioworklet.html
@@ -4,28 +4,35 @@
   <title>Checking window.audioWorklet</title>
   <script src="../../resources/testharness.js"></script>
   <script src="../../resources/testharnessreport.js"></script>
-  <script src="../resources/audit-util.js"></script>
-  <script src="../resources/audio-testing.js"></script>
+  <script src="../resources/audit.js"></script>
   <script src="audioworklet-testing.js"></script>
 </head>
 <body>
   <script>
-    var audit = Audit.createTaskRunner();
+    // This test requires AudioWorklet.
+    let audioWorkletStatus = isAudioWorkletEnabled();
 
-    audit.defineTask('window-audioworklet', function (taskDone) {
+    let audit = Audit.createTaskRunner();
 
-      // TODO: remove this check if AudioWorklet ships to the stable.
-      if (!checkInternalsAndAudioWorkletRuntimeFlag(taskDone))
-        return;
+    // Test if AudioWorklet exists.
+    audit.define({
+        label: 'window-audioworklet',
+        description: 'Test if AudioWorklet exists.',
+      }, (task, should) => {
+        // TODO(hongchan): remove this assertion when AudioWorklet is shipped.
+        should(audioWorkletStatus.onContentShell || 
+               audioWorkletStatus.onBrowser,
+               'AudioWorklet is available on ContentShell or Browser')
+            .beTrue();
 
-      Should('window.audioWorklet is an instance of Worklet',
-        window.audioWorklet instanceof Worklet).beEqualTo(true);
+        should(window.audioWorklet instanceof Worklet,
+               'window.audioWorklet is an instance of Worklet')
+            .beTrue();
 
-      taskDone();
+        task.done();
     });
 
-
-    audit.runTasks();
+    audit.run();
   </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
index 87c61261..17b4c0c9 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions-expected.txt
@@ -1,193 +1,239 @@
-CONSOLE WARNING: line 1: The provided value 'fancy' is not a valid enum value of type ChannelCountMode.
-CONSOLE WARNING: line 1: The provided value 'undefined' is not a valid enum value of type ChannelInterpretation.
-CONSOLE WARNING: line 1: The provided value '9x' is not a valid enum value of type OverSampleType.
-CONSOLE WARNING: line 1: The provided value 'junk' is not a valid enum value of type ChannelCountMode.
-CONSOLE WARNING: line 1: The provided value 'junk' is not a valid enum value of type ChannelCountMode.
-Tests DOM exception messages
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-PASS context.createBuffer(99, 1, context.sampleRate) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The number of channels provided (99) is outside the range [1, 32]..
-PASS context.createBuffer(0, 1, context.sampleRate) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The number of channels provided (0) is outside the range [1, 32]..
-PASS context.createBuffer(1, 1, 1) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (1) is outside the range [3000, 384000]..
-PASS context.createBuffer(1, 1, 2999) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (2999) is outside the range [3000, 384000]..
-PASS context.createBuffer(1, 1, 384001) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (384001) is outside the range [3000, 384000]..
-PASS context.createBuffer(1, 1, 1e6) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (1.00000e+6) is outside the range [3000, 384000]..
-PASS context.createBuffer(1, 1, 3000) did not throw exception.
-PASS context.createBuffer(1, 1, 192000) did not throw exception.
-PASS context.createBuffer(1, 1, 384000) did not throw exception.
-PASS context.createBuffer(1, 0, context.sampleRate) threw exception NotSupportedError: Failed to execute 'createBuffer' on 'BaseAudioContext': The number of frames provided (0) is less than or equal to the minimum bound (0)..
-PASS context.createBuffer(new ArrayBuffer(100), true) threw exception TypeError: Failed to execute 'createBuffer' on 'BaseAudioContext': 3 arguments required, but only 2 present..
-PASS context.createMediaElementSource(null) threw exception TypeError: Failed to execute 'createMediaElementSource' on 'BaseAudioContext': parameter 1 is not of type 'HTMLMediaElement'..
-PASS context.createMediaStreamSource(null) threw exception TypeError: Failed to execute 'createMediaStreamSource' on 'BaseAudioContext': parameter 1 is not of type 'MediaStream'..
-PASS context.createScriptProcessor(1, 1, 1) threw exception IndexSizeError: Failed to execute 'createScriptProcessor' on 'BaseAudioContext': buffer size (1) must be 0 or a power of two between 256 and 16384..
-PASS context.createScriptProcessor(4096, 100, 1) threw exception IndexSizeError: Failed to execute 'createScriptProcessor' on 'BaseAudioContext': number of input channels (100) exceeds maximum (32)..
-PASS context.createScriptProcessor(4096, 1, 100) threw exception IndexSizeError: Failed to execute 'createScriptProcessor' on 'BaseAudioContext': number of output channels (100) exceeds maximum (32)..
-PASS context.createScriptProcessor() did not throw exception.
-PASS context.createScriptProcessor(0) did not throw exception.
-PASS context.createChannelSplitter(0) threw exception IndexSizeError: Failed to execute 'createChannelSplitter' on 'BaseAudioContext': The number of outputs provided (0) is outside the range [1, 32]..
-PASS context.createChannelSplitter(99) threw exception IndexSizeError: Failed to execute 'createChannelSplitter' on 'BaseAudioContext': The number of outputs provided (99) is outside the range [1, 32]..
-PASS context.createChannelMerger(0) threw exception IndexSizeError: Failed to execute 'createChannelMerger' on 'BaseAudioContext': The number of inputs provided (0) is outside the range [1, 32]..
-PASS context.createChannelMerger(99) threw exception IndexSizeError: Failed to execute 'createChannelMerger' on 'BaseAudioContext': The number of inputs provided (99) is outside the range [1, 32]..
-PASS context.createPeriodicWave(null, null) threw exception TypeError: Failed to execute 'createPeriodicWave' on 'BaseAudioContext': parameter 1 is not of type 'Float32Array'..
-PASS context.createPeriodicWave(new Float32Array(10), null) threw exception TypeError: Failed to execute 'createPeriodicWave' on 'BaseAudioContext': parameter 2 is not of type 'Float32Array'..
-PASS context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100)) did not throw exception.
-PASS context.createPeriodicWave(new Float32Array(8192), new Float32Array(8192)) did not throw exception.
-PASS context.createPeriodicWave(new Float32Array(10000), new Float32Array(10000)) did not throw exception.
-PASS context.createPeriodicWave(new Float32Array(10), new Float32Array(7)) threw exception IndexSizeError: Failed to execute 'createPeriodicWave' on 'BaseAudioContext': length of real array (10) and length of imaginary array (7) must match..
-PASS node.fftSize = 42 threw exception IndexSizeError: Failed to set the 'fftSize' property on 'AnalyserNode': The value provided (42) is not a power of two..
-PASS node.fftSize is not 42
-PASS node.fftSize = 16 threw exception IndexSizeError: Failed to set the 'fftSize' property on 'AnalyserNode': The FFT size provided (16) is outside the range [32, 32768]..
-PASS node.fftSize is not 16
-PASS node.fftSize = 32768 did not throw exception.
-PASS node.fftSize = 65536 threw exception IndexSizeError: Failed to set the 'fftSize' property on 'AnalyserNode': The FFT size provided (65536) is outside the range [32, 32768]..
-PASS node.fftSize is not 65536
-PASS node.minDecibels = -10 threw exception IndexSizeError: Failed to set the 'minDecibels' property on 'AnalyserNode': The minDecibels provided (-10) is greater than the maximum bound (-30)..
-PASS node.minDecibels is not -10
-PASS node.maxDecibels = -150 threw exception IndexSizeError: Failed to set the 'maxDecibels' property on 'AnalyserNode': The maxDecibels provided (-150) is less than the minimum bound (-100)..
-PASS node.maxDecibels is not -150
-PASS node.minDecibels = -30 threw exception IndexSizeError: Failed to set the 'minDecibels' property on 'AnalyserNode': The minDecibels provided (-30) is greater than or equal to the maximum bound (-30)..
-PASS node.minDecibels is not -30
-PASS node.maxDecibels = -100 threw exception IndexSizeError: Failed to set the 'maxDecibels' property on 'AnalyserNode': The maxDecibels provided (-100) is less than or equal to the minimum bound (-100)..
-PASS node.maxDecibels is not -100
-PASS node.smoothingTimeConstant = -0.1 threw exception IndexSizeError: Failed to set the 'smoothingTimeConstant' property on 'AnalyserNode': The smoothing value provided (-0.1) is outside the range [0, 1]..
-PASS node.smoothingTimeConstant is not -0.1
-PASS node.smoothingTimeConstant = 1.5 threw exception IndexSizeError: Failed to set the 'smoothingTimeConstant' property on 'AnalyserNode': The smoothing value provided (1.5) is outside the range [0, 1]..
-PASS node.smoothingTimeConstant is not 1.5
-PASS node.getFloatFrequencyData(null) threw exception TypeError: Failed to execute 'getFloatFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'..
-PASS node.getByteFrequencyData(null) threw exception TypeError: Failed to execute 'getByteFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'..
-PASS node.getFloatTimeDomainData(null) threw exception TypeError: Failed to execute 'getFloatTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'..
-PASS node.getByteTimeDomainData(null) threw exception TypeError: Failed to execute 'getByteTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'..
-PASS node.getChannelData(2) threw exception IndexSizeError: Failed to execute 'getChannelData' on 'AudioBuffer': channel index (2) exceeds number of channels (1).
-PASS node.connect(null, 0, 0) threw exception TypeError: Failed to execute 'connect' on 'AudioNode': parameter 1 is not of type 'AudioNode'..
-PASS node.connect(context.destination, 100, 0) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1)..
-PASS node.connect(context.destination, 0, 100) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': input index (100) exceeds number of inputs (1)..
-PASS node.connect(node2.gain, 100) threw exception IndexSizeError: Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1)..
-PASS node.disconnect(99) threw exception IndexSizeError: Failed to execute 'disconnect' on 'AudioNode': The output index provided (99) is outside the range [0, 0]..
-PASS node.connect(otherContext.destination) threw exception InvalidAccessError: Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context..
-PASS node.channelCount = 99 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, 32]..
-PASS node.channelCount is not 99
-PASS node.channelCountMode = 'fancy' did not throw exception.
-PASS Invalid channelCountMode value did not change mode
-PASS node.channelInterpretation = mode did not throw exception.
-PASS Invalid channelInterpration value did not change mode
-PASS context.destination.channelCount = 99 threw IndexSizeError exception on invalid channel count.
-PASS param.setValueCurveAtTime(null, 0, 0) threw exception TypeError: Failed to execute 'setValueCurveAtTime' on 'AudioParam': parameter 1 is not of type 'Float32Array'..
-PASS node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1)) did not throw exception.
-PASS node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1)) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 1 is not of type 'Float32Array'..
-PASS node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1)) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 2 is not of type 'Float32Array'..
-PASS node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null) threw exception TypeError: Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 3 is not of type 'Float32Array'..
-PASS new OfflineAudioContext(32, 100, context.sampleRate) did not throw exception.
-PASS new OfflineAudioContext(99, 100, context.sampleRate) threw exception IndexSizeError: Failed to construct 'OfflineAudioContext': The number of channels provided (99) is outside the range [0, 32]..
-PASS new OfflineAudioContext(1, 100, 1) threw exception IndexSizeError: Failed to construct 'OfflineAudioContext': The sampleRate provided (1) is outside the range [3000, 384000]..
-PASS new OfflineAudioContext(1, 100, 1e6) threw exception IndexSizeError: Failed to construct 'OfflineAudioContext': The sampleRate provided (1.00000e+6) is outside the range [3000, 384000]..
-PASS new OfflineAudioContext(1, -88200000000000, 44100) threw exception NotSupportedError: Failed to construct 'OfflineAudioContext': OfflineAudioContext(1, 1448390656, 44100).
-PASS node.oversample = '9x' did not throw exception.
-PASS Invalid oversample value did not change node.oversample
-PASS node.curve = {} threw exception TypeError: Failed to set the 'curve' property on 'WaveShaperNode': The provided value is not of type 'Float32Array'..
-PASS node.curve = new Float32Array(1) threw exception InvalidAccessError: Failed to set the 'curve' property on 'WaveShaperNode': The curve length provided (1) is less than the minimum bound (2)..
-PASS node.curve is null
-PASS node.curve = new Float32Array(2) did not throw exception.
-PASS node.curve = null did not throw exception.
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.buffer = context.createBuffer(1, 10, context.sampleRate) threw exception InvalidStateError: Failed to set the 'buffer' property on 'AudioBufferSourceNode': Cannot set buffer after it has been already been set.
-PASS source.start(-1) threw exception InvalidAccessError: Failed to execute 'start' on 'AudioBufferSourceNode': The start time provided (-1) is less than the minimum bound (0)..
-PASS source.start(Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(-Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(NaN) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, -Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, NaN) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, -1) threw exception InvalidStateError: Failed to execute 'start' on 'AudioBufferSourceNode': The offset provided (-1) is less than the minimum bound (0)..
-PASS source.start(1, -Number.MIN_VALUE) threw exception InvalidStateError: Failed to execute 'start' on 'AudioBufferSourceNode': The offset provided (-4.94066e-324) is less than the minimum bound (0)..
-PASS source.start(1, 1, Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, 1, -Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, 1, NaN) threw exception TypeError: Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite..
-PASS source.start(1, 1, -1) threw exception InvalidStateError: Failed to execute 'start' on 'AudioBufferSourceNode': The duration provided (-1) is less than the minimum bound (0)..
-PASS source.start(1, 1, -Number.MIN_VALUE) threw exception InvalidStateError: Failed to execute 'start' on 'AudioBufferSourceNode': The duration provided (-4.94066e-324) is less than the minimum bound (0)..
-PASS source.start() did not throw exception.
-PASS source.stop(-Number.MIN_VALUE) threw exception InvalidAccessError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The stop time provided (-4.94066e-324) is less than the minimum bound (0)..
-PASS source.stop(Infinity) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop(-Infinity) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop(NaN) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop() did not throw exception.
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.start(0, 0) did not throw exception.
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.start(0, -1/Infinity) did not throw exception.
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.start() did not throw exception.
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.stop() threw exception InvalidStateError: Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first..
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.start() did not throw exception.
-PASS source.start() threw exception InvalidStateError: Failed to execute 'start' on 'AudioBufferSourceNode': cannot call start more than once..
-PASS source = context.createBufferSource() did not throw exception.
-PASS source.buffer = buffer did not throw exception.
-PASS source.start() did not throw exception.
-PASS source.stop() did not throw exception.
-PASS source = context.createOscillator() did not throw exception.
-PASS source.start(-Number.MIN_VALUE) threw exception InvalidAccessError: Failed to execute 'start' on 'AudioScheduledSourceNode': The start time provided (-4.94066e-324) is less than the minimum bound (0)..
-PASS source.start(Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.start(-Infinity) threw exception TypeError: Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.start(NaN) threw exception TypeError: Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.start() did not throw exception.
-PASS source.stop(-Number.MIN_VALUE) threw exception InvalidAccessError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The stop time provided (-4.94066e-324) is less than the minimum bound (0)..
-PASS source.stop(Infinity) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop(-Infinity) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop(NaN) threw exception TypeError: Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite..
-PASS source.stop() did not throw exception.
-PASS osc = context.createOscillator() did not throw exception.
-PASS osc.stop() threw exception InvalidStateError: Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first..
-PASS osc1 = context.createOscillator() did not throw exception.
-PASS osc1.start() did not throw exception.
-PASS osc1.stop() did not throw exception.
-PASS osc.setPeriodicWave(null) threw exception TypeError: Failed to execute 'setPeriodicWave' on 'OscillatorNode': parameter 1 is not of type 'PeriodicWave'..
-PASS node.gain.exponentialRampToValueAtTime(-1, 0.1) did not throw exception.
-PASS node.gain.exponentialRampToValueAtTime(0, 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45)..
-PASS node.gain.exponentialRampToValueAtTime(1e-100, 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45)..
-PASS node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1) did not throw exception.
-PASS node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1) threw exception InvalidAccessError: Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45)..
-PASS oc = new OfflineAudioContext(1, 44100, 44100) did not throw exception.
-PASS conv = oc.createConvolver() did not throw exception.
-PASS conv.buffer = {} threw exception TypeError: Failed to set the 'buffer' property on 'ConvolverNode': The provided value is not of type 'AudioBuffer'..
-PASS conv.buffer = oc.createBuffer(1, 100, 22050) threw exception NotSupportedError: Failed to set the 'buffer' property on 'ConvolverNode': The buffer sample rate of 22050 does not match the context rate of 44100 Hz..
-PASS conv.buffer is null
-PASS panner.channelCount = 1 did not throw exception.
-PASS panner.channelCount = 2 did not throw exception.
-PASS panner.channelCount = 0 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': The channelCount provided (0) is outside the range [1, 2]..
-PASS panner.channelCount is not 0
-PASS panner.channelCount = 3 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': The channelCount provided (3) is outside the range [1, 2]..
-PASS panner.channelCount is not 3
-PASS panner.channelCountMode = 'max' threw exception NotSupportedError: Failed to set the 'channelCountMode' property on 'AudioNode': Panner: 'max' is not allowed.
-PASS panner.channelCountMode is not 'max'
-PASS panner.channelCountMode = 'explicit' did not throw exception.
-PASS panner.channelCountMode = 'clamped-max' did not throw exception.
-PASS panner.channelCountMode = 'junk' did not throw exception.
-PASS script = context.createScriptProcessor(256, 3) did not throw exception.
-PASS script.channelCount is 3
-PASS script.channelCountMode is "explicit"
-PASS script.channelCount = 3 did not throw exception.
-PASS script.channelCount = 1 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': channelCount cannot be changed from 3 to 1.
-PASS script.channelCount is not 1
-PASS script.channelCount = 7 threw exception NotSupportedError: Failed to set the 'channelCount' property on 'AudioNode': channelCount cannot be changed from 3 to 7.
-PASS script.channelCount is not 7
-PASS script.channelCountMode = 'explicit' did not throw exception.
-PASS script.channelCountMode = 'max' threw exception NotSupportedError: Failed to set the 'channelCountMode' property on 'AudioNode': channelCountMode cannot be changed from 'explicit' to 'max'.
-PASS script.channelCountMode is not 'max'
-PASS script.channelCountMode = 'clamped-max' threw exception NotSupportedError: Failed to set the 'channelCountMode' property on 'AudioNode': channelCountMode cannot be changed from 'explicit' to 'clamped-max'.
-PASS script.channelCountMode is not 'clamped-max'
-PASS script.channelCountMode = 'junk' did not throw exception.
-PASS osc.noteOn is undefined.
-PASS osc.noteOff is undefined.
-PASS source.noteOn is undefined.
-PASS source.noteOff is undefined.
-PASS successfullyParsed is true
-
-TEST COMPLETE
+CONSOLE ERROR: line 39: [audit.js] this test requires the explicit comparison with the expected result when it runs with run-webkit-tests.
+CONSOLE WARNING: line 308: The provided value 'fancy' is not a valid enum value of type ChannelCountMode.
+CONSOLE WARNING: line 312: The provided value 'undefined' is not a valid enum value of type ChannelInterpretation.
+CONSOLE WARNING: line 442: The provided value '9x' is not a valid enum value of type OverSampleType.
+CONSOLE WARNING: line 645: The provided value 'junk' is not a valid enum value of type ChannelCountMode.
+CONSOLE WARNING: line 676: The provided value 'junk' is not a valid enum value of type ChannelCountMode.
+This is a testharness.js-based test.
+PASS # AUDIT TASK RUNNER STARTED. 
+PASS > [initialize]  
+PASS   context = new AudioContext() did not throw an exception. 
+PASS   otherContext = new AudioContext() did not throw an exception. 
+PASS < [initialize] All assertions passed. (total 2 assertions) 
+PASS > [createBuffer]  
+PASS   context.createBuffer(99, 1, context.sampleRate) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The number of channels provided (99) is outside the range [1, 32].". 
+PASS   context.createBuffer(0, 1, context.sampleRate) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The number of channels provided (0) is outside the range [1, 32].". 
+PASS   context.createBuffer(1, 1, 1) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (1) is outside the range [3000, 384000].". 
+PASS   context.createBuffer(1, 1, 2999) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (2999) is outside the range [3000, 384000].". 
+PASS   context.createBuffer(1, 1, 384001) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (384001) is outside the range [3000, 384000].". 
+PASS   context.createBuffer(1, 1, 1e6) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The sample rate provided (1.00000e+6) is outside the range [3000, 384000].". 
+PASS   context.createBuffer(1, 1, 3000) did not throw an exception. 
+PASS   context.createBuffer(1, 1, 192000) did not throw an exception. 
+PASS   context.createBuffer(1, 1, 384000) did not throw an exception. 
+PASS   context.createBuffer(1, 0, context.sampleRate) threw NotSupportedError: "Failed to execute 'createBuffer' on 'BaseAudioContext': The number of frames provided (0) is less than or equal to the minimum bound (0).". 
+PASS   context.createBuffer(new ArrayBuffer(100), true) threw TypeError: "Failed to execute 'createBuffer' on 'BaseAudioContext': 3 arguments required, but only 2 present.". 
+PASS < [createBuffer] All assertions passed. (total 11 assertions) 
+PASS > [createMediaElementSource]  
+PASS   context.createMediaElementSource(null) threw TypeError: "Failed to execute 'createMediaElementSource' on 'BaseAudioContext': parameter 1 is not of type 'HTMLMediaElement'.". 
+PASS < [createMediaElementSource] All assertions passed. (total 1 assertions) 
+PASS > [createMediaStreamSource]  
+PASS   context.createMediaStreamSource(null) threw TypeError: "Failed to execute 'createMediaStreamSource' on 'BaseAudioContext': parameter 1 is not of type 'MediaStream'.". 
+PASS < [createMediaStreamSource] All assertions passed. (total 1 assertions) 
+PASS > [createScriptProcessor]  
+PASS   context.createScriptProcessor(1, 1, 1) threw IndexSizeError: "Failed to execute 'createScriptProcessor' on 'BaseAudioContext': buffer size (1) must be 0 or a power of two between 256 and 16384.". 
+PASS   context.createScriptProcessor(4096, 100, 1) threw IndexSizeError: "Failed to execute 'createScriptProcessor' on 'BaseAudioContext': number of input channels (100) exceeds maximum (32).". 
+PASS   context.createScriptProcessor(4096, 1, 100) threw IndexSizeError: "Failed to execute 'createScriptProcessor' on 'BaseAudioContext': number of output channels (100) exceeds maximum (32).". 
+PASS   context.createScriptProcessor() did not throw an exception. 
+PASS   context.createScriptProcessor(0) did not throw an exception. 
+PASS < [createScriptProcessor] All assertions passed. (total 5 assertions) 
+PASS > [createChannelSplitter]  
+PASS   context.createChannelSplitter(0) threw IndexSizeError: "Failed to execute 'createChannelSplitter' on 'BaseAudioContext': The number of outputs provided (0) is outside the range [1, 32].". 
+PASS   context.createChannelSplitter(99) threw IndexSizeError: "Failed to execute 'createChannelSplitter' on 'BaseAudioContext': The number of outputs provided (99) is outside the range [1, 32].". 
+PASS   context.createChannelMerger(0) threw IndexSizeError: "Failed to execute 'createChannelMerger' on 'BaseAudioContext': The number of inputs provided (0) is outside the range [1, 32].". 
+PASS < [createChannelSplitter] All assertions passed. (total 3 assertions) 
+PASS > [createChannelMerger]  
+PASS   context.createChannelMerger(99) threw IndexSizeError: "Failed to execute 'createChannelMerger' on 'BaseAudioContext': The number of inputs provided (99) is outside the range [1, 32].". 
+PASS < [createChannelMerger] All assertions passed. (total 1 assertions) 
+PASS > [createPeriodicWave]  
+PASS   context.createPeriodicWave(null, null) threw TypeError: "Failed to execute 'createPeriodicWave' on 'BaseAudioContext': parameter 1 is not of type 'Float32Array'.". 
+PASS   context.createPeriodicWave(new Float32Array(10), null) threw TypeError: "Failed to execute 'createPeriodicWave' on 'BaseAudioContext': parameter 2 is not of type 'Float32Array'.". 
+PASS   context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100)) did not throw an exception. 
+PASS   context.createPeriodicWave(new Float32Array(8192), new Float32Array(8192)) did not throw an exception. 
+PASS   context.createPeriodicWave(new Float32Array(10000), new Float32Array(10000)) did not throw an exception. 
+PASS   context.createPeriodicWave(new Float32Array(10), new Float32Array(7)) threw IndexSizeError: "Failed to execute 'createPeriodicWave' on 'BaseAudioContext': length of real array (10) and length of imaginary array (7) must match.". 
+PASS < [createPeriodicWave] All assertions passed. (total 6 assertions) 
+PASS > [createAnalyser]  
+PASS   AnalyserNode.fftSize = 42 threw IndexSizeError: "Failed to set the 'fftSize' property on 'AnalyserNode': The value provided (42) is not a power of two.". 
+PASS   AnalyserNode.fftSize is not equal to 42. 
+PASS   AnalyserNode.fftSize = 16 threw IndexSizeError: "Failed to set the 'fftSize' property on 'AnalyserNode': The FFT size provided (16) is outside the range [32, 32768].". 
+PASS   AnalyserNode.fftSize is not equal to 16. 
+PASS   AnalyserNode.fftSize = 32768 did not throw an exception. 
+PASS   AnalyserNode.fftSize = 65536 threw IndexSizeError: "Failed to set the 'fftSize' property on 'AnalyserNode': The FFT size provided (65536) is outside the range [32, 32768].". 
+PASS   AnalyserNode.fftSize is not equal to 65536. 
+PASS   AnalyserNode.minDecibels = -10 threw IndexSizeError: "Failed to set the 'minDecibels' property on 'AnalyserNode': The minDecibels provided (-10) is greater than the maximum bound (-30).". 
+PASS   AnalyserNode.minDecibels is not equal to -10. 
+PASS   AnalyserNode.maxDecibels = -150 threw IndexSizeError: "Failed to set the 'maxDecibels' property on 'AnalyserNode': The maxDecibels provided (-150) is less than the minimum bound (-100).". 
+PASS   AnalyserNode.maxDecibels is not equal to -150. 
+PASS   AnalyserNode.minDecibels = -30 threw IndexSizeError: "Failed to set the 'minDecibels' property on 'AnalyserNode': The minDecibels provided (-30) is greater than or equal to the maximum bound (-30).". 
+PASS   AnalyserNode.minDecibels is not equal to -30. 
+PASS   AnalyserNode.maxDecibels = -100 threw IndexSizeError: "Failed to set the 'maxDecibels' property on 'AnalyserNode': The maxDecibels provided (-100) is less than or equal to the minimum bound (-100).". 
+PASS   AnalyserNode.maxDecibels is not equal to -100. 
+PASS   AnalyserNode.smoothingTimeConstant = -0.1 threw IndexSizeError: "Failed to set the 'smoothingTimeConstant' property on 'AnalyserNode': The smoothing value provided (-0.1) is outside the range [0, 1].". 
+PASS   AnalyserNode.smoothingTimeConstant is not equal to -0.1. 
+PASS   AnalyserNode.smoothingTimeConstant = 1.5 threw IndexSizeError: "Failed to set the 'smoothingTimeConstant' property on 'AnalyserNode': The smoothing value provided (1.5) is outside the range [0, 1].". 
+PASS   AnalyserNode.smoothingTimeConstant is not equal to 1.5. 
+PASS   AnalyserNode.getFloatFrequencyData(null) threw TypeError: "Failed to execute 'getFloatFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'.". 
+PASS   AnalyserNode.getByteFrequencyData(null) threw TypeError: "Failed to execute 'getByteFrequencyData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'.". 
+PASS   AnalyserNode.getFloatTimeDomainData(null) threw TypeError: "Failed to execute 'getFloatTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Float32Array'.". 
+PASS   AnalyserNode.getByteTimeDomainData(null) threw TypeError: "Failed to execute 'getByteTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'.". 
+PASS   AudioBuffer.getChannelData(2) threw IndexSizeError: "Failed to execute 'getChannelData' on 'AudioBuffer': channel index (2) exceeds number of channels (1)". 
+PASS < [createAnalyser] All assertions passed. (total 24 assertions) 
+PASS > [Init test nodes]  
+PASS   node = context.createGain() did not throw an exception. 
+PASS   node2 = context.createGain() did not throw an exception. 
+PASS < [Init test nodes] All assertions passed. (total 2 assertions) 
+PASS > [connections]  
+PASS   node.connect(null, 0, 0) threw TypeError: "Failed to execute 'connect' on 'AudioNode': parameter 1 is not of type 'AudioNode'.". 
+PASS   node.connect(context.destination, 100, 0) threw IndexSizeError: "Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1).". 
+PASS   node.connect(context.destination, 0, 100) threw IndexSizeError: "Failed to execute 'connect' on 'AudioNode': input index (100) exceeds number of inputs (1).". 
+PASS   node.connect(node2.gain, 100) threw IndexSizeError: "Failed to execute 'connect' on 'AudioNode': output index (100) exceeds number of outputs (1).". 
+PASS   node.disconnect(99) threw IndexSizeError: "Failed to execute 'disconnect' on 'AudioNode': The output index provided (99) is outside the range [0, 0].". 
+PASS   node.connect(otherContext.destination) threw InvalidAccessError: "Failed to execute 'connect' on 'AudioNode': cannot connect to a destination belonging to a different audio context.". 
+PASS < [connections] All assertions passed. (total 6 assertions) 
+PASS > [channel-stuff]  
+PASS   GainNode.channelCount = 99 threw NotSupportedError: "Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, 32].". 
+PASS   GainNode.channelCount is not equal to 99. 
+PASS   node.channelCountMode = "fancy" did not throw an exception. 
+PASS   node.channelCountMode is equal to max. 
+PASS   node.channelInterpretation = mode did not throw an exception. 
+PASS   node.channelInterpretation is equal to speakers. 
+PASS   context.destination.channelCount = 99 threw IndexSizeError: "Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, 2].". 
+PASS < [channel-stuff] All assertions passed. (total 7 assertions) 
+PASS > [audioparam]  
+PASS   param.setValueCurveAtTime(null, 0, 0) threw TypeError: "Failed to execute 'setValueCurveAtTime' on 'AudioParam': parameter 1 is not of type 'Float32Array'.". 
+PASS   node.gain.exponentialRampToValueAtTime(-1, 0.1) did not throw an exception. 
+PASS   node.gain.exponentialRampToValueAtTime(0, 0.1) threw InvalidAccessError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45).". 
+PASS   node.gain.exponentialRampToValueAtTime(1e-100, 0.1) threw InvalidAccessError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45).". 
+PASS   node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1) did not throw an exception. 
+PASS   node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1) threw InvalidAccessError: "Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': The float target value provided (0) should not be in the range (-1.40130e-45, 1.40130e-45).". 
+PASS < [audioparam] All assertions passed. (total 6 assertions) 
+PASS > [biquad]  
+PASS   node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1)) did not throw an exception. 
+PASS   node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1)) threw TypeError: "Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 1 is not of type 'Float32Array'.". 
+PASS   node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1)) threw TypeError: "Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 2 is not of type 'Float32Array'.". 
+PASS   node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null) threw TypeError: "Failed to execute 'getFrequencyResponse' on 'BiquadFilterNode': parameter 3 is not of type 'Float32Array'.". 
+PASS < [biquad] All assertions passed. (total 4 assertions) 
+PASS > [offline-audio-context]  
+PASS   new OfflineAudioContext(32, 100, context.sampleRate) did not throw an exception. 
+PASS   new OfflineAudioContext(99, 100, context.sampleRate) threw IndexSizeError: "Failed to construct 'OfflineAudioContext': The number of channels provided (99) is outside the range [0, 32].". 
+PASS   new OfflineAudioContext(1, 100, 1) threw IndexSizeError: "Failed to construct 'OfflineAudioContext': The sampleRate provided (1) is outside the range [3000, 384000].". 
+PASS   new OfflineAudioContext(1, 100, 1e6) threw IndexSizeError: "Failed to construct 'OfflineAudioContext': The sampleRate provided (1.00000e+6) is outside the range [3000, 384000].". 
+PASS   new OfflineAudioContext(1, -88200000000000, 44100) threw NotSupportedError: "Failed to construct 'OfflineAudioContext': OfflineAudioContext(1, 1448390656, 44100)". 
+PASS < [offline-audio-context] All assertions passed. (total 5 assertions) 
+PASS > [waveshaper]  
+PASS   node.oversample = "9x" did not throw an exception. 
+PASS   node.oversample is equal to none. 
+PASS   node.curve = {} threw TypeError: "Failed to set the 'curve' property on 'WaveShaperNode': The provided value is not of type 'Float32Array'.". 
+PASS   node.curve = new Float32Array(1) threw InvalidAccessError: "Failed to set the 'curve' property on 'WaveShaperNode': The curve length provided (1) is less than the minimum bound (2).". 
+PASS   node.curve is equal to ${expected}. 
+PASS   node.curve = new Float32Array(2) did not throw an exception. 
+PASS   node.curve = null did not throw an exception. 
+PASS < [waveshaper] All assertions passed. (total 7 assertions) 
+PASS > [audio-buffer-source]  
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.buffer = context.createBuffer(1, 10, context.sampleRate) threw InvalidStateError: "Failed to set the 'buffer' property on 'AudioBufferSourceNode': Cannot set buffer after it has been already been set". 
+PASS   source.start(-1) threw InvalidAccessError: "Failed to execute 'start' on 'AudioBufferSourceNode': The start time provided (-1) is less than the minimum bound (0).". 
+PASS   source.start(Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(-Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(NaN) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, -Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, NaN) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, -1) threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': The offset provided (-1) is less than the minimum bound (0).". 
+PASS   source.start(1, -Number.MIN_VALUE) threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': The offset provided (-4.94066e-324) is less than the minimum bound (0).". 
+PASS   source.start(1, 1, Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, 1, -Infinity) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, 1, NaN) threw TypeError: "Failed to execute 'start' on 'AudioBufferSourceNode': The provided double value is non-finite.". 
+PASS   source.start(1, 1, -1) threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': The duration provided (-1) is less than the minimum bound (0).". 
+PASS   source.start(1, 1, -Number.MIN_VALUE) threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': The duration provided (-4.94066e-324) is less than the minimum bound (0).". 
+PASS   source.start() did not throw an exception. 
+PASS   source.stop(-Number.MIN_VALUE) threw InvalidAccessError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The stop time provided (-4.94066e-324) is less than the minimum bound (0).". 
+PASS   source.stop(Infinity) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop(-Infinity) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop(NaN) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop() did not throw an exception. 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.start(0, 0) did not throw an exception. 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.start(0, -1/Infinity) did not throw an exception. 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.start() did not throw an exception. 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.stop() threw InvalidStateError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first.". 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.start() did not throw an exception. 
+PASS   source.start() threw InvalidStateError: "Failed to execute 'start' on 'AudioBufferSourceNode': cannot call start more than once.". 
+PASS   source = context.createBufferSource() did not throw an exception. 
+PASS   source.buffer = buffer did not throw an exception. 
+PASS   source.start() did not throw an exception. 
+PASS   source.stop() did not throw an exception. 
+PASS < [audio-buffer-source] All assertions passed. (total 42 assertions) 
+PASS > [oscillator]  
+PASS   source = context.createOscillator() did not throw an exception. 
+PASS   source.start(-Number.MIN_VALUE) threw InvalidAccessError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The start time provided (-4.94066e-324) is less than the minimum bound (0).". 
+PASS   source.start(Infinity) threw TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.start(-Infinity) threw TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.start(NaN) threw TypeError: "Failed to execute 'start' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.start() did not throw an exception. 
+PASS   source.stop(-Number.MIN_VALUE) threw InvalidAccessError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The stop time provided (-4.94066e-324) is less than the minimum bound (0).". 
+PASS   source.stop(Infinity) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop(-Infinity) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop(NaN) threw TypeError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': The provided double value is non-finite.". 
+PASS   source.stop() did not throw an exception. 
+PASS   osc = context.createOscillator() did not throw an exception. 
+PASS   osc.stop() threw InvalidStateError: "Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first.". 
+PASS   osc1 = context.createOscillator() did not throw an exception. 
+PASS   osc1.start() did not throw an exception. 
+PASS   osc1.stop() did not throw an exception. 
+PASS   osc.setPeriodicWave(null) threw TypeError: "Failed to execute 'setPeriodicWave' on 'OscillatorNode': parameter 1 is not of type 'PeriodicWave'.". 
+PASS < [oscillator] All assertions passed. (total 17 assertions) 
+PASS > [convolver]  
+PASS   oc = new OfflineAudioContext(1, 44100, 44100) did not throw an exception. 
+PASS   conv = oc.createConvolver() did not throw an exception. 
+PASS   conv.buffer = {} threw TypeError: "Failed to set the 'buffer' property on 'ConvolverNode': The provided value is not of type 'AudioBuffer'.". 
+PASS   conv.buffer = oc.createBuffer(1, 100, 22050) threw NotSupportedError: "Failed to set the 'buffer' property on 'ConvolverNode': The buffer sample rate of 22050 does not match the context rate of 44100 Hz.". 
+PASS   conv.buffer is equal to ${expected}. 
+PASS < [convolver] All assertions passed. (total 5 assertions) 
+PASS > [panner]  
+PASS   panner.channelCount = 1 did not throw an exception. 
+PASS   panner.channelCount = 2 did not throw an exception. 
+PASS   PannerNode.channelCount = 0 threw NotSupportedError: "Failed to set the 'channelCount' property on 'AudioNode': The channelCount provided (0) is outside the range [1, 2].". 
+PASS   PannerNode.channelCount is not equal to 0. 
+PASS   PannerNode.channelCount = 3 threw NotSupportedError: "Failed to set the 'channelCount' property on 'AudioNode': The channelCount provided (3) is outside the range [1, 2].". 
+PASS   PannerNode.channelCount is not equal to 3. 
+PASS   PannerNode.channelCountMode = max threw NotSupportedError: "Failed to set the 'channelCountMode' property on 'AudioNode': Panner: 'max' is not allowed". 
+PASS   PannerNode.channelCountMode is not equal to max. 
+PASS   panner.channelCountMode = "explicit" did not throw an exception. 
+PASS   panner.channelCountMode = "clamped-max" did not throw an exception. 
+PASS   panner.channelCountMode = "junk" did not throw an exception. 
+PASS < [panner] All assertions passed. (total 11 assertions) 
+PASS > [script-processor]  
+PASS   script = context.createScriptProcessor(256, 3) did not throw an exception. 
+PASS   script.channelCount is equal to 3. 
+PASS   script.channelCountMode is equal to explicit. 
+PASS   script.channelCount = 3 did not throw an exception. 
+PASS   ScriptProcessorNode.channelCount = 1 threw NotSupportedError: "Failed to set the 'channelCount' property on 'AudioNode': channelCount cannot be changed from 3 to 1". 
+PASS   ScriptProcessorNode.channelCount is not equal to 1. 
+PASS   ScriptProcessorNode.channelCount = 7 threw NotSupportedError: "Failed to set the 'channelCount' property on 'AudioNode': channelCount cannot be changed from 3 to 7". 
+PASS   ScriptProcessorNode.channelCount is not equal to 7. 
+PASS   script.channelCountMode = "explicit" did not throw an exception. 
+PASS   ScriptProcessorNode.channelCountMode = max threw NotSupportedError: "Failed to set the 'channelCountMode' property on 'AudioNode': channelCountMode cannot be changed from 'explicit' to 'max'". 
+PASS   ScriptProcessorNode.channelCountMode is not equal to max. 
+PASS   ScriptProcessorNode.channelCountMode = clamped-max threw NotSupportedError: "Failed to set the 'channelCountMode' property on 'AudioNode': channelCountMode cannot be changed from 'explicit' to 'clamped-max'". 
+PASS   ScriptProcessorNode.channelCountMode is not equal to clamped-max. 
+PASS   script.channelCountMode = "junk" did not throw an exception. 
+PASS < [script-processor] All assertions passed. (total 14 assertions) 
+PASS > [misc]  
+PASS   osc.noteOn is equal to undefined. 
+PASS   osc.noteOff is equal to undefined. 
+PASS   source.noteOn is equal to undefined. 
+PASS   source.noteOff is equal to undefined. 
+PASS < [misc] All assertions passed. (total 4 assertions) 
+PASS # AUDIT TASK RUNNER FINISHED: 22 tasks ran successfully. 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
index b1c8667..1ed09766 100644
--- a/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
+++ b/third_party/WebKit/LayoutTests/webaudio/dom-exceptions.html
@@ -1,336 +1,698 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!doctype html>
 <html>
 <head>
-<script src="../resources/js-test.js"></script>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script> 
 <script src="resources/audit-util.js"></script>
-<script src="resources/audio-testing.js"></script>
+<script src="resources/audit.js"></script>
 <script src="resources/biquad-testing.js"></script>
 </head>
 
 <body>
-
-<div id="description"></div>
-<div id="console"></div>
 <script>
-description("Tests DOM exception messages");
+let audit = Audit.createTaskRunner({requireResultFile: true});
 
-var context;
-var otherContext;
-var node;
-var node2;
-var mode;
-var panner;
-var script;
+let otherContext;
+let node;
+let node2;
+let mode;
+let panner;
+let script;
 
-function shouldThrowAndBeUnchanged(attr, value) {
-    shouldThrow(attr + " = " + value);
-    shouldNotBe(attr, value);
+function shouldThrowAndBeUnchanged(should, node, attr, value) {
+  should(
+      () => node[attr] = value,
+      node.constructor.name + '.' + attr + ' = ' + value)
+      .throw();
+  should(node[attr], node.constructor.name + '.' + attr).notBeEqualTo(value);
 }
 
-function runTest() {
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-    }
+audit.define('initialize', (task, should) => {
+  task.describe('Initialize contexts for testing');
 
+  should(() => {
     context = new AudioContext();
-    otherContext = new AudioContext();
+  }, 'context = new AudioContext()').notThrow();
 
-    // Test creation of various objects
+  should(() => {
+    otherContext = new AudioContext(); },
+      'otherContext = new AudioContext()')
+      .notThrow();
 
-    // Invalid number of channels: NotSupportedError
-    shouldThrow("context.createBuffer(99, 1, context.sampleRate)");
-    shouldThrow("context.createBuffer(0, 1, context.sampleRate)");
-    // Invalid sample rate: NotSupportedError
-    shouldThrow("context.createBuffer(1, 1, 1)");
-    shouldThrow("context.createBuffer(1, 1, 2999)");
-    shouldThrow("context.createBuffer(1, 1, 384001)");
-    shouldThrow("context.createBuffer(1, 1, 1e6)");
-    // Check valid values from crbug.com/344375
-    shouldNotThrow("context.createBuffer(1, 1, 3000)");
-    shouldNotThrow("context.createBuffer(1, 1, 192000)");
-    shouldNotThrow("context.createBuffer(1, 1, 384000)");
-    // Invalid number of frames: NotSupportedError
-    shouldThrow("context.createBuffer(1, 0, context.sampleRate)");
-    // 2-arg createBuffer not allowed.
-    shouldThrow("context.createBuffer(new ArrayBuffer(100), true)");
-    // Invalid sources (unspecified error)
-    shouldThrow("context.createMediaElementSource(null)");
-    shouldThrow("context.createMediaStreamSource(null)");
-    // Invalid buffer size: IndexSizeError
-    shouldThrow("context.createScriptProcessor(1, 1, 1)");
-    // Invalid number of inputs and outputs: IndexSizeError
-    shouldThrow("context.createScriptProcessor(4096, 100, 1)");
-    shouldThrow("context.createScriptProcessor(4096, 1, 100)");
-    shouldNotThrow("context.createScriptProcessor()");
-    shouldNotThrow("context.createScriptProcessor(0)");
+  task.done();
+});
 
-    // Invalid number of channels: IndexSizeError
-    shouldThrow("context.createChannelSplitter(0)");
-    shouldThrow("context.createChannelSplitter(99)");
-    shouldThrow("context.createChannelMerger(0)");
-    shouldThrow("context.createChannelMerger(99)");
-    // Invalid real/imag arrays: IndexSizeError
-    shouldThrow("context.createPeriodicWave(null, null)");
-    shouldThrow("context.createPeriodicWave(new Float32Array(10), null)");
-    // Verify that we can use large arrays with no limit. Roughly.
-    shouldNotThrow("context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100))");
-    shouldNotThrow("context.createPeriodicWave(new Float32Array(8192), new Float32Array(8192))");
-    shouldNotThrow("context.createPeriodicWave(new Float32Array(10000), new Float32Array(10000))");
-    // Real and imaginary arrays must have the same size: IndexSizeError
-    shouldThrow("context.createPeriodicWave(new Float32Array(10), new Float32Array(7))");
+audit.define('createBuffer', (task, should) => {
+  task.describe('createBuffer');
+
+  // Invalid number of channels: NotSupportedError
+  should(
+      () => context.createBuffer(99, 1, context.sampleRate),
+      'context.createBuffer(99, 1, context.sampleRate)')
+      .throw('NotSupportedError');
+  should(
+      () => context.createBuffer(0, 1, context.sampleRate),
+      'context.createBuffer(0, 1, context.sampleRate)')
+      .throw('NotSupportedError');
+  // Invalid sample rate: NotSupportedError
+  should(() => context.createBuffer(1, 1, 1), 'context.createBuffer(1, 1, 1)')
+      .throw('NotSupportedError');
+  should(
+      () => context.createBuffer(1, 1, 2999),
+      'context.createBuffer(1, 1, 2999)')
+      .throw('NotSupportedError');
+  should(
+      () => context.createBuffer(1, 1, 384001),
+      'context.createBuffer(1, 1, 384001)')
+      .throw('NotSupportedError');
+  should(
+      () => context.createBuffer(1, 1, 1e6), 'context.createBuffer(1, 1, 1e6)')
+      .throw('NotSupportedError');
+  // Check valid values from crbug.com/344375
+  should(
+      () => context.createBuffer(1, 1, 3000),
+      'context.createBuffer(1, 1, 3000)')
+      .notThrow();
+  should(
+      () => context.createBuffer(1, 1, 192000),
+      'context.createBuffer(1, 1, 192000)')
+      .notThrow();
+  should(
+      () => context.createBuffer(1, 1, 384000),
+      'context.createBuffer(1, 1, 384000)')
+      .notThrow();
+  // Invalid number of frames: NotSupportedError
+  should(
+      () => context.createBuffer(1, 0, context.sampleRate),
+      'context.createBuffer(1, 0, context.sampleRate)')
+      .throw('NotSupportedError');
+  // 2-arg createBuffer not allowed.
+  should(
+      () => context.createBuffer(new ArrayBuffer(100), true),
+      'context.createBuffer(new ArrayBuffer(100), true)')
+      .throw('TypeError');
+
+  task.done();
+});
+
+audit.define('createMediaElementSource', (task, should) => {
+  task.describe('createMediaElementSource');
+
+  // Invalid sources (unspecified error)
+  should(
+      () => context.createMediaElementSource(null),
+      'context.createMediaElementSource(null)')
+      .throw();
+  task.done();
+});
+
+audit.define('createMediaStreamSource', (task, should) => {
+  task.describe('createMediaStreamSource');
+
+  // Invalid sources (unspecified error)
+  should(
+      () => context.createMediaStreamSource(null),
+      'context.createMediaStreamSource(null)')
+      .throw();
+
+  task.done();
+});
+
+audit.define('createScriptProcessor', (task, should) => {
+  task.describe('createScriptProcessor');
+
+  // Invalid buffer size: IndexSizeError
+  should(
+      () => context.createScriptProcessor(1, 1, 1),
+      'context.createScriptProcessor(1, 1, 1)')
+      .throw('IndexSizeError');
+  // Invalid number of inputs and outputs: IndexSizeError
+  should(
+      () => context.createScriptProcessor(4096, 100, 1),
+      'context.createScriptProcessor(4096, 100, 1)')
+      .throw('IndexSizeError');
+  should(
+      () => context.createScriptProcessor(4096, 1, 100),
+      'context.createScriptProcessor(4096, 1, 100)')
+      .throw('IndexSizeError');
+  should(
+      () => context.createScriptProcessor(), 'context.createScriptProcessor()')
+      .notThrow();
+  should(
+      () => context.createScriptProcessor(0),
+      'context.createScriptProcessor(0)')
+      .notThrow();
+
+  task.done();
+});
+
+audit.define('createChannelSplitter', (task, should) => {
+  task.describe('createChannelSplitter');
+
+  // Invalid number of channels: IndexSizeError
+  should(
+      () => context.createChannelSplitter(0),
+      'context.createChannelSplitter(0)')
+      .throw('IndexSizeError');
+  should(
+      () => context.createChannelSplitter(99),
+      'context.createChannelSplitter(99)')
+      .throw('IndexSizeError');
+  should(() => context.createChannelMerger(0), 'context.createChannelMerger(0)')
+      .throw('IndexSizeError');
+
+  task.done();
+});
+
+audit.define('createChannelMerger', (task, should) => {
+  task.describe('createChannelMerger');
+
+  // Invalid number of channels: IndexSizeError
+  should(
+      () => context.createChannelMerger(99), 'context.createChannelMerger(99)')
+      .throw('IndexSizeError');
+
+  task.done();
+});
+
+audit.define('createPeriodicWave', (task, should) => {
+  task.describe('createPeriodicWave');
+
+  // Invalid real/imag arrays: IndexSizeError
+  should(
+      () => context.createPeriodicWave(null, null),
+      'context.createPeriodicWave(null, null)')
+      .throw('TypeError');
+  should(
+      () => context.createPeriodicWave(new Float32Array(10), null),
+      'context.createPeriodicWave(new Float32Array(10), null)')
+      .throw('TypeError');
+  // Verify that we can use large arrays with no limit. Roughly.
+  should(
+      () => context.createPeriodicWave(
+          new Float32Array(4100), new Float32Array(4100)),
+      'context.createPeriodicWave(new Float32Array(4100), new Float32Array(4100))')
+      .notThrow();
+  should(
+      () => context.createPeriodicWave(
+          new Float32Array(8192), new Float32Array(8192)),
+      'context.createPeriodicWave(new Float32Array(8192), new Float32Array(8192))')
+      .notThrow();
+  should(
+      () => context.createPeriodicWave(
+          new Float32Array(10000), new Float32Array(10000)),
+      'context.createPeriodicWave(new Float32Array(10000), new Float32Array(10000))')
+      .notThrow();
+  // Real and imaginary arrays must have the same size: IndexSizeError
+  should(
+      () =>
+          context.createPeriodicWave(new Float32Array(10), new Float32Array(7)),
+      'context.createPeriodicWave(new Float32Array(10), new Float32Array(7))')
+      .throw('IndexSizeError');
+
+  task.done();
+});
+
+audit.define('createAnalyser', (task, should) => {
+  task.describe('createAnalyser');
+
+  // Analysers
+  node = context.createAnalyser();
+  // Invalid fftSize: IndexSizeError
+  shouldThrowAndBeUnchanged(should, node, 'fftSize', '42');
+  shouldThrowAndBeUnchanged(should, node, 'fftSize', '16');
+  should(() => node.fftSize = 32768, 'AnalyserNode.fftSize = 32768').notThrow();
+  shouldThrowAndBeUnchanged(should, node, 'fftSize', '65536');
+
+  shouldThrowAndBeUnchanged(should, node, 'minDecibels', '-10');
+  shouldThrowAndBeUnchanged(should, node, 'maxDecibels', '-150');
+  shouldThrowAndBeUnchanged(should, node, 'minDecibels', '-30');
+  shouldThrowAndBeUnchanged(should, node, 'maxDecibels', '-100');
+
+  shouldThrowAndBeUnchanged(should, node, 'smoothingTimeConstant', '-0.1');
+  shouldThrowAndBeUnchanged(should, node, 'smoothingTimeConstant', '1.5');
+
+  should(
+      () => node.getFloatFrequencyData(null),
+      'AnalyserNode.getFloatFrequencyData(null)')
+      .throw();
+  should(
+      () => node.getByteFrequencyData(null), node.constructor.name + '.getByteFrequencyData(null)')
+      .throw();
+  should(
+      () => node.getFloatTimeDomainData(null),
+      node.constructor.name + '.getFloatTimeDomainData(null)')
+      .throw();
+  should(
+      () => node.getByteTimeDomainData(null),
+      node.constructor.name + '.getByteTimeDomainData(null)')
+      .throw();
+
+  // AudioBuffers
+  node = context.createBuffer(1, 1, context.sampleRate);
+  // Invalid channel index: IndexSizeError
+  should(() => node.getChannelData(2), node.constructor.name + '.getChannelData(2)').throw();
+
+  task.done();
+});
+
+audit.define('Init test nodes', (task, should) => {
+  task.describe('Create test nodes');
+  should(() => { node = context.createGain(); },
+    'node = context.createGain()')
+    .notThrow();
+  should(() => { node2 = context.createGain(); },
+    'node2 = context.createGain()')
+    .notThrow();
+
+  task.done();
+});
+
+audit.define('connections', (task, should) => {
+  task.describe('AudioNode connections');
+
+  // AudioNode connections
+  // Invalid destination node (unspecified error)
+  should(() => node.connect(null, 0, 0), 'node.connect(null, 0, 0)').throw();
+  // Invalid input or output index: IndexSizeError
+  should(
+      () => node.connect(context.destination, 100, 0),
+      'node.connect(context.destination, 100, 0)')
+      .throw('IndexSizeError');
+  should(
+      () => node.connect(context.destination, 0, 100),
+      'node.connect(context.destination, 0, 100)')
+      .throw('IndexSizeError');
+  should(() => node.connect(node2.gain, 100), 'node.connect(node2.gain, 100)')
+      .throw('IndexSizeError');
+  should(() => node.disconnect(99), 'node.disconnect(99)')
+      .throw('IndexSizeError');
+  // Can't connect to a different context (unspecified error)
+  should(
+      () => node.connect(otherContext.destination),
+      'node.connect(otherContext.destination)')
+      .throw();
+
+  task.done();
+});
+
+audit.define('channel-stuff', (task, should) => {
+  task.describe('channelCount, channelCountMode, channelInterpretation');
+
+  // Invalid channel count: NotSupportedError
+  shouldThrowAndBeUnchanged(should, node, 'channelCount', '99');
+  // Invalid mode or interpretation (unspecified error)
+  currentMode = node.channelCountMode;
+  currentInterpretation = node.channelInterpretation;
+  should(
+      () => node.channelCountMode = 'fancy', 'node.channelCountMode = "fancy"')
+      .notThrow();
+  should(node.channelCountMode, 'node.channelCountMode').beEqualTo(currentMode);
+  should(
+      () => node.channelInterpretation = mode,
+      'node.channelInterpretation = mode')
+      .notThrow();
+  should(node.channelInterpretation, 'node.channelInterpretation')
+      .beEqualTo(currentInterpretation);
+  // Destination node channel count: should throw IndexSizeError on invalid
+  // channel count. shouldNotThrow() method cannot be used because the error
+  // message includes the number of channels, which can change depending on
+  // the actual attached hardware.
+  should(
+      () => context.destination.channelCount = 99,
+      'context.destination.channelCount = 99')
+      .throw('IndexSizeError');
+
+  task.done();
+});
+
+audit.define('audioparam', (task, should) => {
+  task.describe('Simple AudioParam');
+
+  // AudioParams
+  param = context.createGain().gain;
+  should(
+      () => param.setValueCurveAtTime(null, 0, 0),
+      'param.setValueCurveAtTime(null, 0, 0)')
+      .throw();
+
+  // exponentialRampToValue should throw only for "zero" target values.
+  should(
+      () => node.gain.exponentialRampToValueAtTime(-1, 0.1),
+      'node.gain.exponentialRampToValueAtTime(-1, 0.1)')
+      .notThrow();
+  should(
+      () => node.gain.exponentialRampToValueAtTime(0, 0.1),
+      'node.gain.exponentialRampToValueAtTime(0, 0.1)')
+      .throw();
+  // 1e-100 is 0 when converted to a single precision float.
+  should(
+      () => node.gain.exponentialRampToValueAtTime(1e-100, 0.1),
+      'node.gain.exponentialRampToValueAtTime(1e-100, 0.1)')
+      .throw();
+  // See crbug.com/459391.
+  // Math.pow(2, -149) = 1.401298464324817e-45 is the double-float value of the
+  // least positive single float number. We do it this way to make sure no
+  // round-off or conversion
+  // errors happen when reading 1.401298464324817e-45.
+  should(
+      () => node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1),
+      'node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1)')
+      .notThrow();
+  // Math.pow(2, -150) = 7.006492321624085d-46 is the largest double float value
+  // such that
+  // conversion to a float produces 0.  Any larger value would produce a
+  // non-zero value when
+  // converted to a single float.
+  should(
+      () => node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1),
+      'node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1)')
+      .throw();
+
+  task.done();
+});
+
+audit.define('biquad', (task, should) => {
+  task.describe('BiquadFilter');
+
+  // BiquadFilterNode
+  node = context.createBiquadFilter();
+  should(
+      () => node.getFrequencyResponse(
+          new Float32Array(1), new Float32Array(1), new Float32Array(1)),
+      'node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1))')
+      .notThrow();
+  should(
+      () => node.getFrequencyResponse(
+          null, new Float32Array(1), new Float32Array(1)),
+      'node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))')
+      .throw();
+  should(
+      () => node.getFrequencyResponse(
+          new Float32Array(1), null, new Float32Array(1)),
+      'node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))')
+      .throw();
+  should(
+      () => node.getFrequencyResponse(
+          new Float32Array(1), new Float32Array(1), null),
+      'node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)')
+      .throw();
+
+  task.done();
+});
+
+audit.define('offline-audio-context', (task, should) => {
+  task.describe('OfflineAudioContext');
+
+  // OfflineAudioContext
+  // Max supported channels
+  should(
+      () => new OfflineAudioContext(32, 100, context.sampleRate),
+      'new OfflineAudioContext(32, 100, context.sampleRate)')
+      .notThrow();
+  // Invalid number of channels (unspecified error)
+  should(
+      () => new OfflineAudioContext(99, 100, context.sampleRate),
+      'new OfflineAudioContext(99, 100, context.sampleRate)')
+      .throw();
+  // Invalid sample rate. (unspecified error)
+  should(
+      () => new OfflineAudioContext(1, 100, 1),
+      'new OfflineAudioContext(1, 100, 1)')
+      .throw();
+  should(
+      () => new OfflineAudioContext(1, 100, 1e6),
+      'new OfflineAudioContext(1, 100, 1e6)')
+      .throw();
+  // Invalid frame length (crbug.com/351277)
+  should(
+      () => new OfflineAudioContext(1, -88200000000000, 44100),
+      'new OfflineAudioContext(1, -88200000000000, 44100)')
+      .throw();
+
+  task.done();
+});
+
+audit.define('waveshaper', (task, should) => {
+  task.describe('WaveShaper');
+
+  // WaveShaper types
+  node = context.createWaveShaper();
+  currentOversample = node.oversample;
+  should(() => node.oversample = '9x', 'node.oversample = "9x"').notThrow();
+  should(node.oversample, 'node.oversample').beEqualTo(currentOversample);
+  should(() => node.curve = {}, 'node.curve = {}').throw();
+  should(
+      () => node.curve = new Float32Array(1),
+      'node.curve = new Float32Array(1)')
+      .throw();
+  should(node.curve, 'node.curve').beEqualTo(null);
+  should(
+      () => node.curve = new Float32Array(2),
+      'node.curve = new Float32Array(2)')
+      .notThrow();
+  should(() => node.curve = null, 'node.curve = null').notThrow();
+
+  task.done();
+});
+
+audit.define('audio-buffer-source', (task, should) => {
+  task.describe('AudioBufferSource start/stop');
+
+  // Start/stop for AudioBufferSourceNodes
+  buffer = context.createBuffer(1, 1, context.sampleRate);
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(
+      () => source.buffer = context.createBuffer(1, 10, context.sampleRate),
+      'source.buffer = context.createBuffer(1, 10, context.sampleRate)')
+      .throw();
+  should(() => source.start(-1), 'source.start(-1)').throw();
+  should(() => source.start(Infinity), 'source.start(Infinity)').throw();
+  should(() => source.start(-Infinity), 'source.start(-Infinity)').throw();
+  should(() => source.start(NaN), 'source.start(NaN)').throw();
+  should(() => source.start(1, Infinity), 'source.start(1, Infinity)').throw();
+  should(() => source.start(1, -Infinity), 'source.start(1, -Infinity)')
+      .throw();
+  should(() => source.start(1, NaN), 'source.start(1, NaN)').throw();
+  should(() => source.start(1, -1), 'source.start(1, -1)').throw();
+  should(
+      () => source.start(1, -Number.MIN_VALUE),
+      'source.start(1, -Number.MIN_VALUE)')
+      .throw();
+  should(() => source.start(1, 1, Infinity), 'source.start(1, 1, Infinity)')
+      .throw();
+  should(() => source.start(1, 1, -Infinity), 'source.start(1, 1, -Infinity)')
+      .throw();
+  should(() => source.start(1, 1, NaN), 'source.start(1, 1, NaN)').throw();
+  should(() => source.start(1, 1, -1), 'source.start(1, 1, -1)').throw();
+  should(
+      () => source.start(1, 1, -Number.MIN_VALUE),
+      'source.start(1, 1, -Number.MIN_VALUE)')
+      .throw();
+  should(() => source.start(), 'source.start()').notThrow();
+  should(() => source.stop(-Number.MIN_VALUE), 'source.stop(-Number.MIN_VALUE)')
+      .throw();
+  should(() => source.stop(Infinity), 'source.stop(Infinity)').throw();
+  should(() => source.stop(-Infinity), 'source.stop(-Infinity)').throw();
+  should(() => source.stop(NaN), 'source.stop(NaN)').throw();
+  should(() => source.stop(), 'source.stop()').notThrow();
+
+  // Verify that start(0, 0) doesn't signal.
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(() => source.start(0, 0), 'source.start(0, 0)').notThrow();
+
+  // Verify that start(0, -0.0) doesn't signal.
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(() => source.start(0, -1 / Infinity), 'source.start(0, -1/Infinity)')
+      .notThrow();
+
+  // It's not clear from the spec, but I think it's valid to call start(). The
+  // spec is silent on
+  // what happens if we call stop() afterwards, so don't call it.
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.start(), 'source.start()').notThrow();
+
+  buffer = context.createBuffer(1, 1, context.sampleRate);
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(() => source.stop(), 'source.stop()').throw();
+
+  buffer = context.createBuffer(1, 1, context.sampleRate);
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(() => source.start(), 'source.start()').notThrow();
+  should(() => source.start(), 'source.start()').throw();
+
+  buffer = context.createBuffer(1, 1, context.sampleRate);
+  should(
+      () => source = context.createBufferSource(),
+      'source = context.createBufferSource()')
+      .notThrow();
+  should(() => source.buffer = buffer, 'source.buffer = buffer').notThrow();
+  should(() => source.start(), 'source.start()').notThrow();
+  should(() => source.stop(), 'source.stop()').notThrow();
+
+  task.done();
+});
+
+audit.define('oscillator', (task, should) => {
+  task.describe('Oscillator start/stop');
+
+  // Start/stop for OscillatorNodes
+  should(
+      () => source = context.createOscillator(),
+      'source = context.createOscillator()')
+      .notThrow();
+  should(
+      () => source.start(-Number.MIN_VALUE), 'source.start(-Number.MIN_VALUE)')
+      .throw();
+  should(() => source.start(Infinity), 'source.start(Infinity)').throw();
+  should(() => source.start(-Infinity), 'source.start(-Infinity)').throw();
+  should(() => source.start(NaN), 'source.start(NaN)').throw();
+  should(() => source.start(), 'source.start()').notThrow();
+  should(() => source.stop(-Number.MIN_VALUE), 'source.stop(-Number.MIN_VALUE)')
+      .throw();
+  should(() => source.stop(Infinity), 'source.stop(Infinity)').throw();
+  should(() => source.stop(-Infinity), 'source.stop(-Infinity)').throw();
+  should(() => source.stop(NaN), 'source.stop(NaN)').throw();
+  should(() => source.stop(), 'source.stop()').notThrow();
+
+  should(
+      () => osc = context.createOscillator(),
+      'osc = context.createOscillator()')
+      .notThrow();
+  should(() => osc.stop(), 'osc.stop()').throw();
+  should(
+      () => osc1 = context.createOscillator(),
+      'osc1 = context.createOscillator()')
+      .notThrow();
+  should(() => osc1.start(), 'osc1.start()').notThrow();
+  should(() => osc1.stop(), 'osc1.stop()').notThrow();
+
+  should(() => osc.setPeriodicWave(null), 'osc.setPeriodicWave(null)').throw();
 
 
-    // Analysers
-    node = context.createAnalyser();
-    // Invalid fftSize: IndexSizeError
-    shouldThrowAndBeUnchanged("node.fftSize", "42");
-    shouldThrowAndBeUnchanged("node.fftSize", "16");
-    shouldNotThrow("node.fftSize = 32768");
-    shouldThrowAndBeUnchanged("node.fftSize", "65536");
+  task.done();
+});
 
-    shouldThrowAndBeUnchanged("node.minDecibels", "-10");
-    shouldThrowAndBeUnchanged("node.maxDecibels", "-150");
-    shouldThrowAndBeUnchanged("node.minDecibels", "-30");
-    shouldThrowAndBeUnchanged("node.maxDecibels", "-100");
+audit.define('convolver', (task, should) => {
+  task.describe('Convolver');
 
-    shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "-0.1");
-    shouldThrowAndBeUnchanged("node.smoothingTimeConstant", "1.5");
+  // Convolver buffer rate must match context rate. Create on offline context so
+  // we
+  // specify the context rate exactly, in case the test is run on platforms with
+  // different
+  // HW sample rates.
+  should(
+      () => oc = new OfflineAudioContext(1, 44100, 44100),
+      'oc = new OfflineAudioContext(1, 44100, 44100)')
+      .notThrow();
+  should(() => conv = oc.createConvolver(), 'conv = oc.createConvolver()')
+      .notThrow();
+  should(() => conv.buffer = {}, 'conv.buffer = {}').throw();
+  should(
+      () => conv.buffer = oc.createBuffer(1, 100, 22050),
+      'conv.buffer = oc.createBuffer(1, 100, 22050)')
+      .throw();
+  // conv.buffer should be unchanged (null) because the above failed.
+  should(conv.buffer, 'conv.buffer').beEqualTo(null);
 
-    shouldThrow("node.getFloatFrequencyData(null)");
-    shouldThrow("node.getByteFrequencyData(null)");
-    shouldThrow("node.getFloatTimeDomainData(null)");
-    shouldThrow("node.getByteTimeDomainData(null)");
+  task.done();
+});
 
-    // AudioBuffers
-    node = context.createBuffer(1,1, context.sampleRate);
-    // Invalid channel index: IndexSizeError
-    shouldThrow("node.getChannelData(2)");
+audit.define('panner', (task, should) => {
+  task.describe('Panner');
 
-    // AudioNode connections
-    node = context.createGain();
-    node2 = context.createGain();
-    // Invalid destination node (unspecified error)
-    shouldThrow("node.connect(null, 0, 0)");
-    // Invalid input or output index: IndexSizeError
-    shouldThrow("node.connect(context.destination, 100, 0)");
-    shouldThrow("node.connect(context.destination, 0, 100)");
-    shouldThrow("node.connect(node2.gain, 100)");
-    shouldThrow("node.disconnect(99)");
-    // Can't connect to a different context (unspecified error)
-    shouldThrow("node.connect(otherContext.destination)");
+  // PannerNode channel count and mode
+  panner = context.createPanner();
+  // Channel count can only be set to 1 or 2.
+  should(() => panner.channelCount = 1, 'panner.channelCount = 1').notThrow();
+  should(() => panner.channelCount = 2, 'panner.channelCount = 2').notThrow();
+  shouldThrowAndBeUnchanged(should, panner, 'channelCount', 0);
+  shouldThrowAndBeUnchanged(should, panner, 'channelCount', 3);
+  // It is illegal to set the mode to 'max'
+  shouldThrowAndBeUnchanged(should, panner, 'channelCountMode', 'max');
+  should(
+      () => panner.channelCountMode = 'explicit',
+      'panner.channelCountMode = "explicit"')
+      .notThrow();
+  should(
+      () => panner.channelCountMode = 'clamped-max',
+      'panner.channelCountMode = "clamped-max"')
+      .notThrow();
+  should(
+      () => panner.channelCountMode = 'junk',
+      'panner.channelCountMode = "junk"')
+      .notThrow();
 
-    // Invalid channel count: NotSupportedError
-    shouldThrowAndBeUnchanged("node.channelCount", "99");
-    // Invalid mode or interpretation (unspecified error)
-    currentMode = node.channelCountMode;
-    currentInterpretation = node.channelInterpretation;
-    shouldNotThrow("node.channelCountMode = 'fancy'");
-    if (node.channelCountMode == currentMode)
-      testPassed("Invalid channelCountMode value did not change mode");
-    else
-      testFailed("node.channelCountMode incorrectly changed to invalid value " + node.channelCountMode);
-    shouldNotThrow("node.channelInterpretation = mode");
-    if (node.channelInterpretation == currentInterpretation)
-      testPassed("Invalid channelInterpration value did not change mode");
-    else
-      testFailed("node.channelInterpretation incorrectly changed to invalid value " + node.channelInterpreation);
+  task.done();
+});
 
-    // Destination node channel count: should throw IndexSizeError on invalid
-    // channel count. shouldNotThrow() method cannot be used because the error
-    // message includes the number of channels, which can change depending on
-    // the actual attached hardware.
-    try {
-        eval("context.destination.channelCount = 99");
-    } catch (e) {
-        if (e.message === "Failed to set the 'channelCount' property on 'AudioNode': The channel count provided (99) is outside the range [1, " + context.destination.maxChannelCount + "]." && e.name === "IndexSizeError")
-            testPassed("context.destination.channelCount = 99 threw IndexSizeError exception on invalid channel count.");
-        else
-            testFailed("context.destination.channelCount = 99 should throw IndexSizeError exception on invalid channel count.");
-    }
+audit.define('script-processor', (task, should) => {
+  task.describe('ScriptProcessor');
 
-    // AudioParams
-    param = context.createGain().gain;
-    shouldThrow("param.setValueCurveAtTime(null, 0, 0)");
+  // Test channel count and mode for a ScriptProcessor.
+  should(
+      () => script = context.createScriptProcessor(256, 3),
+      'script = context.createScriptProcessor(256, 3)')
+      .notThrow();
+  // Make sure the channelCount and mode are set correctly.
+  should(script.channelCount, 'script.channelCount').beEqualTo(3);
+  should(script.channelCountMode, 'script.channelCountMode')
+      .beEqualTo('explicit');
+  // Cannot change the channelCount or mode to anything else
+  should(() => script.channelCount = 3, 'script.channelCount = 3').notThrow();
+  shouldThrowAndBeUnchanged(should, script, 'channelCount', 1);
 
-    // BiquadFilterNode
-    node = context.createBiquadFilter();
-    shouldNotThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), new Float32Array(1))");
-    shouldThrow("node.getFrequencyResponse(null, new Float32Array(1), new Float32Array(1))");
-    shouldThrow("node.getFrequencyResponse(new Float32Array(1), null, new Float32Array(1))");
-    shouldThrow("node.getFrequencyResponse(new Float32Array(1), new Float32Array(1), null)");
+  shouldThrowAndBeUnchanged(should, script, 'channelCount', 7);
+  should(
+      () => script.channelCountMode = 'explicit',
+      'script.channelCountMode = "explicit"')
+      .notThrow();
+  shouldThrowAndBeUnchanged(should, script, 'channelCountMode', 'max');
+  shouldThrowAndBeUnchanged(should, script, 'channelCountMode', 'clamped-max');
+  should(
+      () => script.channelCountMode = 'junk',
+      'script.channelCountMode = "junk"')
+      .notThrow();
 
-    // Delay nodes are tested elsewhere, so don't duplicate that work here.
+  task.done();
+});
 
-    // OfflineAudioContext
-    // Max supported channels
-    shouldNotThrow("new OfflineAudioContext(32, 100, context.sampleRate)");
-    // Invalid number of channels (unspecified error)
-    shouldThrow("new OfflineAudioContext(99, 100, context.sampleRate)");
-    // Invalid sample rate. (unspecified error)
-    shouldThrow("new OfflineAudioContext(1, 100, 1)");
-    shouldThrow("new OfflineAudioContext(1, 100, 1e6)");
-    // Invalid frame length (crbug.com/351277)
-    shouldThrow("new OfflineAudioContext(1, -88200000000000, 44100)");
+audit.define('misc', (task, should) => {
+  task.describe('Miscellaneous');
 
-    // WaveShaper types
-    node = context.createWaveShaper();
-    currentOversample = node.oversample;
-    shouldNotThrow("node.oversample = '9x'");
-    if (node.oversample == currentOversample)
-      testPassed("Invalid oversample value did not change node.oversample");
-    else
-      testFailed("node.oversample incorrectly changed to invalid value " + node.oversample);
-    shouldThrow("node.curve = {}");
-    shouldThrow("node.curve = new Float32Array(1)");
-    shouldBeNull("node.curve");
-    shouldNotThrow("node.curve = new Float32Array(2)");
-    shouldNotThrow("node.curve = null");
+  // noteOn and noteOff don't exist anymore
+  should(osc.noteOn, 'osc.noteOn').beEqualTo(undefined);
+  should(osc.noteOff, 'osc.noteOff').beEqualTo(undefined);
+  should(source.noteOn, 'source.noteOn').beEqualTo(undefined);
+  should(source.noteOff, 'source.noteOff').beEqualTo(undefined);
 
-    // Start/stop for AudioBufferSourceNodes
-    buffer = context.createBuffer(1,1, context.sampleRate);
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldThrow("source.buffer = context.createBuffer(1, 10, context.sampleRate)");
-    shouldThrow("source.start(-1)");
-    shouldThrow("source.start(Infinity)");
-    shouldThrow("source.start(-Infinity)");
-    shouldThrow("source.start(NaN)");
-    shouldThrow("source.start(1, Infinity)");
-    shouldThrow("source.start(1, -Infinity)");
-    shouldThrow("source.start(1, NaN)");
-    shouldThrow("source.start(1, -1)");
-    shouldThrow("source.start(1, -Number.MIN_VALUE)");
-    shouldThrow("source.start(1, 1, Infinity)");
-    shouldThrow("source.start(1, 1, -Infinity)");
-    shouldThrow("source.start(1, 1, NaN)");
-    shouldThrow("source.start(1, 1, -1)");
-    shouldThrow("source.start(1, 1, -Number.MIN_VALUE)");
-    shouldNotThrow("source.start()");
-    shouldThrow("source.stop(-Number.MIN_VALUE)");
-    shouldThrow("source.stop(Infinity)");
-    shouldThrow("source.stop(-Infinity)");
-    shouldThrow("source.stop(NaN)");
-    shouldNotThrow("source.stop()");
+  task.done();
+});
 
-    // Verify that start(0, 0) doesn't signal.
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldNotThrow("source.start(0, 0)");
-
-    // Verify that start(0, -0.0) doesn't signal.
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldNotThrow("source.start(0, -1/Infinity)");
-
-    // It's not clear from the spec, but I think it's valid to call start(). The spec is silent on
-    // what happens if we call stop() afterwards, so don't call it.
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.start()");
-
-    buffer = context.createBuffer(1,1, context.sampleRate);
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldThrow("source.stop()");
-
-    buffer = context.createBuffer(1,1, context.sampleRate);
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldNotThrow("source.start()");
-    shouldThrow("source.start()");
-
-    buffer = context.createBuffer(1,1, context.sampleRate);
-    shouldNotThrow("source = context.createBufferSource()");
-    shouldNotThrow("source.buffer = buffer");
-    shouldNotThrow("source.start()");
-    shouldNotThrow("source.stop()");
-
-
-    // Start/stop for OscillatorNodes
-    shouldNotThrow("source = context.createOscillator()");
-    shouldThrow("source.start(-Number.MIN_VALUE)");
-    shouldThrow("source.start(Infinity)");
-    shouldThrow("source.start(-Infinity)");
-    shouldThrow("source.start(NaN)");
-    shouldNotThrow("source.start()");
-    shouldThrow("source.stop(-Number.MIN_VALUE)");
-    shouldThrow("source.stop(Infinity)");
-    shouldThrow("source.stop(-Infinity)");
-    shouldThrow("source.stop(NaN)");
-    shouldNotThrow("source.stop()");
-
-    shouldNotThrow("osc = context.createOscillator()");
-    shouldThrow("osc.stop()");
-    shouldNotThrow("osc1 = context.createOscillator()");
-    shouldNotThrow("osc1.start()");
-    shouldNotThrow("osc1.stop()");
-
-    shouldThrow("osc.setPeriodicWave(null)");
-
-    // exponentialRampToValue should throw only for "zero" target values.
-    node = context.createGain();
-    node.connect(context.destination);
-    shouldNotThrow("node.gain.exponentialRampToValueAtTime(-1, 0.1)");
-    shouldThrow("node.gain.exponentialRampToValueAtTime(0, 0.1)");
-    // 1e-100 is 0 when converted to a single precision float.
-    shouldThrow("node.gain.exponentialRampToValueAtTime(1e-100, 0.1)");
-    // See crbug.com/459391.
-    // Math.pow(2, -149) = 1.401298464324817e-45 is the double-float value of the
-    // least positive single float number. We do it this way to make sure no round-off or conversion
-    // errors happen when reading 1.401298464324817e-45.
-    shouldNotThrow("node.gain.exponentialRampToValueAtTime(Math.pow(2, -149), 0.1)");
-    // Math.pow(2, -150) = 7.006492321624085d-46 is the largest double float value such that
-    // conversion to a float produces 0.  Any larger value would produce a non-zero value when
-    // converted to a single float.
-    shouldThrow("node.gain.exponentialRampToValueAtTime(Math.pow(2, -150), 0.1)");
-
-    // Convolver buffer rate must match context rate. Create on offline context so we
-    // specify the context rate exactly, in case the test is run on platforms with different
-    // HW sample rates.
-    shouldNotThrow("oc = new OfflineAudioContext(1, 44100, 44100)");
-    shouldNotThrow("conv = oc.createConvolver()");
-    shouldThrow("conv.buffer = {}");
-    shouldThrow("conv.buffer = oc.createBuffer(1, 100, 22050)");
-    // conv.buffer should be unchanged (null) because the above failed.
-    shouldBeNull("conv.buffer");
-
-    // PannerNode channel count and mode
-    panner = context.createPanner();
-    // Channel count can only be set to 1 or 2.
-    shouldNotThrow("panner.channelCount = 1");
-    shouldNotThrow("panner.channelCount = 2");
-    shouldThrowAndBeUnchanged("panner.channelCount", "0");
-    shouldThrowAndBeUnchanged("panner.channelCount", "3");
-    // It is illegal to set the mode to 'max'
-    shouldThrowAndBeUnchanged("panner.channelCountMode", "'max'");
-    shouldNotThrow("panner.channelCountMode = 'explicit'");
-    shouldNotThrow("panner.channelCountMode = 'clamped-max'");
-    shouldNotThrow("panner.channelCountMode = 'junk'");
-
-    // Test channel count and mode for a ScriptProcessor.
-    shouldNotThrow("script = context.createScriptProcessor(256, 3)");
-    // Make sure the channelCount and mode are set correctly.
-    shouldBeEqualToNumber("script.channelCount", 3);
-    shouldBeEqualToString("script.channelCountMode", "explicit");
-    // Cannot change the channelCount or mode to anything else
-    shouldNotThrow("script.channelCount = 3");
-    shouldThrowAndBeUnchanged("script.channelCount", "1");
-
-    shouldThrowAndBeUnchanged("script.channelCount", "7");
-    shouldNotThrow("script.channelCountMode = 'explicit'");
-    shouldThrowAndBeUnchanged("script.channelCountMode", "'max'");
-    shouldThrowAndBeUnchanged("script.channelCountMode", "'clamped-max'");
-    shouldNotThrow("script.channelCountMode = 'junk'");
-
-    // noteOn and noteOff don't exist anymore
-    shouldBeUndefined("osc.noteOn");
-    shouldBeUndefined("osc.noteOff");
-    shouldBeUndefined("source.noteOn");
-    shouldBeUndefined("source.noteOff");
-}
-
-runTest();
-successfullyParsed = true;
-
+audit.run();
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/distance-model-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/distance-model-testing.js
index 933cc14..baff5d48c 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/distance-model-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/distance-model-testing.js
@@ -101,7 +101,7 @@
 
 // distanceModel should be the distance model string like
 // "linear", "inverse", or "exponential".
-function createTestAndRun(context, distanceModel) {
+function createTestAndRun(context, distanceModel, should) {
     // To test the distance models, we create a number of panners at
     // uniformly spaced intervals on the z-axis.  Each of these are
     // started at equally spaced time intervals.  After rendering the
@@ -111,8 +111,8 @@
 
     createGraph(context, distanceModel, nodesToCreate);
 
-    context.oncomplete = checkDistanceResult(distanceModel);
-    context.startRendering();
+    return context.startRendering()
+        .then(buffer => checkDistanceResult(buffer, distanceModel, should));
 }
 
 // The gain caused by the EQUALPOWER panning model, if we stay on the
@@ -121,86 +121,72 @@
     return Math.SQRT1_2;
 }
 
-function checkDistanceResult(model) {
-    return function(event) {
-        renderedBuffer = event.renderedBuffer;
-        renderedData = renderedBuffer.getChannelData(0);
+function checkDistanceResult(renderedBuffer, model, should) {
+    renderedData = renderedBuffer.getChannelData(0);
 
-        // The max allowed error between the actual gain and the expected
-        // value.  This is determined experimentally.  Set to 0 to see what
-        // the actual errors are.
-        var maxAllowedError = 3.3e-6;
+    // The max allowed error between the actual gain and the expected
+    // value.  This is determined experimentally.  Set to 0 to see
+    // what the actual errors are.
+    var maxAllowedError = 3.3e-6;
    
-        var success = true;
+    var success = true;
 
-        // Number of impulses we found in the rendered result.
-        var impulseCount = 0;
+    // Number of impulses we found in the rendered result.
+    var impulseCount = 0;
 
-        // Maximum relative error in the gain of the impulses.
-        var maxError = 0;
+    // Maximum relative error in the gain of the impulses.
+    var maxError = 0;
 
-        // Array of locations of the impulses that were not at the
-        // expected location.  (Contains the actual and expected frame
-        // of the impulse.)
-        var impulsePositionErrors = new Array();
+    // Array of locations of the impulses that were not at the
+    // expected location.  (Contains the actual and expected frame
+    // of the impulse.)
+    var impulsePositionErrors = new Array();
 
-        // Step through the rendered data to find all the non-zero points
-        // so we can find where our distance-attenuated impulses are.
-        // These are tested against the expected attenuations at that
-        // distance.
-        for (var k = 0; k < renderedData.length; ++k) {
-            if (renderedData[k] != 0) {
-                // Convert from string to index.
-                var distanceFunction = distanceModelFunction[model];
-                var expected = distanceFunction(panner[impulseCount], 0, 0, position[impulseCount]);
+    // Step through the rendered data to find all the non-zero points
+    // so we can find where our distance-attenuated impulses are.
+    // These are tested against the expected attenuations at that
+    // distance.
+    for (var k = 0; k < renderedData.length; ++k) {
+        if (renderedData[k] != 0) {
+            // Convert from string to index.
+            var distanceFunction = distanceModelFunction[model];
+            var expected =
+                distanceFunction(panner[impulseCount], 0, 0,
+                    position[impulseCount]);
 
-                // Adjust for the center-panning of the EQUALPOWER panning
-                // model that we're using.
-                expected *= equalPowerGain();
+            // Adjust for the center-panning of the EQUALPOWER panning
+            // model that we're using.
+            expected *= equalPowerGain();
 
-                var error = Math.abs(renderedData[k] - expected) / Math.abs(expected);
+            var error =
+                Math.abs(renderedData[k] - expected) / Math.abs(expected);
 
-                maxError = Math.max(maxError, Math.abs(error));
+            maxError = Math.max(maxError, Math.abs(error));
 
-                // Keep track of any impulses that aren't where we expect them
-                // to be.
-                var expectedOffset = timeToSampleFrame(time[impulseCount], sampleRate);
-                if (k != expectedOffset) {
-                    impulsePositionErrors.push({ actual : k, expected : expectedOffset});
-                }
-                ++impulseCount;
+            // Keep track of any impulses that aren't where we expect them
+            // to be.
+            var expectedOffset = timeToSampleFrame(time[impulseCount],
+                sampleRate);
+            if (k != expectedOffset) {
+                impulsePositionErrors.push({
+                    actual: k,
+                    expected: expectedOffset
+                });
             }
+            ++impulseCount;
         }
+    }
+    should(impulseCount, "Number of impulses")
+        .beEqualTo(nodesToCreate);
 
-        if (impulseCount == nodesToCreate) {
-            testPassed("Number of impulses found matches number of panner nodes.");
-        } else {
-            testFailed("Number of impulses is incorrect.  Found " + impulseCount + " but expected " + nodesToCreate + ".");
-            success = false;
-        }
+    should(maxError, "Max error in distance gains")
+        .beLessThanOrEqualTo(maxAllowedError);
 
-        if (maxError <= maxAllowedError) {
-            testPassed("Distance gains are correct.");
-        } else {
-            testFailed("Distance gains are incorrect.  Max rel error = " + maxError + " (maxAllowedError = " + maxAllowedError + ")");
-            success = false;
-        }
-
-        // Display any timing errors that we found.
-        if (impulsePositionErrors.length > 0) {
-            success = false;
-            testFailed(impulsePositionErrors.length + " timing errors found");
-            for (var k = 0; k < impulsePositionErrors.length; ++k) {
-                testFailed("Sample at frame " + impulsePositionErrors[k].actual + " but expected " + impulsePositionErrors[k].expected);
-            }
-        }
-
-        if (success) {
-            testPassed("Distance test passed for distance model " + model);
-        } else {
-            testFailed("Distance test failed for distance model " + model);
-        }
-
-        finishJSTest();
+    // Display any timing errors that we found.
+    if (impulsePositionErrors.length > 0) {
+        let actual = impulsePositionErrors.map(x => x.actual);
+        let expected = impulsePositionErrors.map(x => x.expected);
+        should(actual, "Actual impulse positions found")
+            .beEqualToArray(expected);
     }
 }
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js
index 923bb7d..b8b866fb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/waveshaper-testing.js
@@ -51,9 +51,7 @@
     return curve;
 }
 
-function checkShapedCurve(event) {
-    var buffer = event.renderedBuffer;
-
+function checkShapedCurve(buffer, should) {
     var outputData = buffer.getChannelData(0);
     var n = buffer.length;
 
@@ -114,15 +112,9 @@
 
     // console.log("worstDeltaInDecibels: " + worstDeltaInDecibels);
 
-    var success = worstDeltaInDecibels < acceptableAliasingThresholdDecibels;
-
-    if (success) {
-        testPassed(oversample + " WaveShaperNode oversampling within acceptable tolerance.");
-    } else {
-        testFailed(oversample + " WaveShaperNode oversampling not within acceptable tolerance.  Error = " + worstDeltaInDecibels + " dBFS");
-    }
-
-    finishJSTest();
+    should(worstDeltaInDecibels, oversample +
+            " WaveshaperNode oversampling error (in dBFS)")
+        .beLessThan(acceptableAliasingThresholdDecibels);
 }
 
 function createImpulseBuffer(context, sampleFrameLength) {
@@ -145,31 +137,33 @@
     fundamentalFrequency = testParams.fundamentalFrequency;
     acceptableAliasingThresholdDecibels = testParams.acceptableAliasingThresholdDecibels;
 
-    if (window.testRunner) {
-        testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
+    let audit = Audit.createTaskRunner();
 
-    window.jsTestIsAsync = true;
+    audit.define("test", function (task, should) {
+        task.describe(testParams.description);
 
-    // Create offline audio context.
-    var numberOfRenderFrames = sampleRate * lengthInSeconds;
-    context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate);
+        // Create offline audio context.
+        var numberOfRenderFrames = sampleRate * lengthInSeconds;
+        context = new OfflineAudioContext(1, numberOfRenderFrames, sampleRate);
 
-    // source -> waveshaper -> destination
-    var source = context.createBufferSource();
-    source.buffer = createToneBuffer(context, fundamentalFrequency, lengthInSeconds, 1);
+        // source -> waveshaper -> destination
+        var source = context.createBufferSource();
+        source.buffer = createToneBuffer(context, fundamentalFrequency, lengthInSeconds, 1);
 
-    // Apply a non-linear distortion curve.
-    waveshaper = context.createWaveShaper();
-    waveshaper.curve = generateWaveShapingCurve();
-    waveshaper.oversample = oversample;
+        // Apply a non-linear distortion curve.
+        waveshaper = context.createWaveShaper();
+        waveshaper.curve = generateWaveShapingCurve();
+        waveshaper.oversample = oversample;
 
-    source.connect(waveshaper);
-    waveshaper.connect(context.destination);
+        source.connect(waveshaper);
+        waveshaper.connect(context.destination);
 
-    source.start(0);
+        source.start(0);
 
-    context.oncomplete = checkShapedCurve;
-    context.startRendering();
+        context.startRendering()
+            .then(buffer => checkShapedCurve(buffer, should))
+            .then(() => task.done());
+      });
+
+    audit.run();
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/SerializationTag.h b/third_party/WebKit/Source/bindings/core/v8/SerializationTag.h
index 81b9b9a2..0c4e5438 100644
--- a/third_party/WebKit/Source/bindings/core/v8/SerializationTag.h
+++ b/third_party/WebKit/Source/bindings/core/v8/SerializationTag.h
@@ -12,6 +12,8 @@
 // begins with a complete VersionTag. If the stream does not begin with a
 // VersionTag, we assume that the stream is in format 0.
 
+// Tags which are not interpreted by Blink (but instead by V8) are omitted here.
+
 // This format is private to the implementation of SerializedScriptValue. Do not
 // rely on it externally. It is safe to persist a SerializedScriptValue as a
 // binary blob, but this code should always be used to interpret it.
@@ -35,20 +37,8 @@
 // GenerateFreshObjectTag/GenerateFreshArrayTag); these reference IDs are then
 // used with ObjectReferenceTag to tie the recursive knot.
 enum SerializationTag {
-  InvalidTag = '!',      // Causes deserialization to fail.
-  PaddingTag = '\0',     // Is ignored (but consumed).
-  UndefinedTag = '_',    // -> <undefined>
-  NullTag = '0',         // -> <null>
-  TrueTag = 'T',         // -> <true>
-  FalseTag = 'F',        // -> <false>
-  StringTag = 'S',       // string:RawString -> string
-  StringUCharTag = 'c',  // string:RawUCharString -> string
-  Int32Tag = 'I',        // value:ZigZag-encoded int32 -> Integer
-  Uint32Tag = 'U',       // value:uint32_t -> Integer
-  DateTag = 'D',         // value:double -> Date (ref)
   MessagePortTag = 'M',  // index:int -> MessagePort. Fills the result with
                          // transferred MessagePort.
-  NumberTag = 'N',       // value:double -> Number
   BlobTag = 'b',  // uuid:WebCoreString, type:WebCoreString, size:uint64_t ->
                   // Blob (ref)
   BlobIndexTag = 'i',      // index:int32_t -> Blob (ref)
@@ -63,36 +53,12 @@
   ImageDataTag = '#',  // width:uint32_t, height:uint32_t,
                        // pixelDataLength:uint32_t, data:byte[pixelDataLength]
                        // -> ImageData (ref)
-  // numProperties:uint32_t -> pops the last object from the open stack; fills
-  // it with the last numProperties name,value pairs pushed onto the
-  // deserialization stack
-  ObjectTag = '{',
-  // numProperties:uint32_t, length:uint32_t -> pops the last object from the
-  // open stack; fills it with the last numProperties name,value pairs pushed
-  // onto the deserialization stack
-  SparseArrayTag = '@',
-  // numProperties:uint32_t, length:uint32_t -> pops the last object from the
-  // open stack; fills it with the last length elements and numProperties
-  // name,value pairs pushed onto deserialization stack
-  DenseArrayTag = '$',
-  RegExpTag = 'R',  // pattern:RawString, flags:uint32_t -> RegExp (ref)
-  ArrayBufferTag =
-      'B',  // byteLength:uint32_t, data:byte[byteLength] -> ArrayBuffer (ref)
-  ArrayBufferTransferTag =
-      't',  // index:uint32_t -> ArrayBuffer. For ArrayBuffer transfer
   ImageBitmapTag = 'g',  // size:uint32_t, data:byte[size] -> ImageBitmap (ref)
   ImageBitmapTransferTag =
       'G',  // index:uint32_t -> ImageBitmap. For ImageBitmap transfer
   OffscreenCanvasTransferTag = 'H',  // index, width, height, id:uint32_t ->
                                      // OffscreenCanvas. For OffscreenCanvas
                                      // transfer
-  // subtag:byte, byteOffset:uint32_t, byteLength:uint32_t -> ArrayBufferView
-  // (ref).  Consumes an ArrayBuffer from the top of the deserialization stack.
-  ArrayBufferViewTag = 'V',
-  SharedArrayBufferTransferTag = 'u',  // index:uint32_t -> SharedArrayBuffer.
-                                       // For SharedArrayBuffer transfer
-  WasmModuleTag = 'W',
-  RawBytesTag = 'y',
   CryptoKeyTag = 'K',  // subtag:byte, props, usages:uint32_t,
                        // keyDataLength:uint32_t, keyData:byte[keyDataLength]
   //                 If subtag=AesKeyTag:
@@ -110,54 +76,11 @@
   //                     namedCurve:uint32_t
   RTCCertificateTag = 'k',   // length:uint32_t, pemPrivateKey:WebCoreString,
                              // pemCertificate:WebCoreString
-  ObjectReferenceTag = '^',  // ref:uint32_t -> reference table[ref]
-  GenerateFreshObjectTag = 'o',  // -> empty object allocated an object ID and
-                                 // pushed onto the open stack (ref)
-  GenerateFreshSparseArrayTag = 'a',  // length:uint32_t -> empty array[length]
-                                      // allocated an object ID and pushed onto
-                                      // the open stack (ref)
-  GenerateFreshDenseArrayTag = 'A',   // length:uint32_t -> empty array[length]
-                                      // allocated an object ID and pushed onto
-                                      // the open stack (ref)
-  ReferenceCountTag = '?',  // refTableSize:uint32_t -> If the reference table
-                            // is not refTableSize big, fails.
-  StringObjectTag = 's',    //  string:RawString -> new String(string) (ref)
-  NumberObjectTag = 'n',    // value:double -> new Number(value) (ref)
-  TrueObjectTag = 'y',      // new Boolean(true) (ref)
-  FalseObjectTag = 'x',     // new Boolean(false) (ref)
   CompositorProxyTag =
       'C',  // elementId:uint64_t, bitfields:uint32_t -> CompositorProxy (ref)
-  MapTag = ':',  // length:uint32_t -> pops the last object from the open stack
-                 // (it will be a Map);
-  //                              fills it with the last length elements pushed
-  //                              onto the deserialization stack, treating them
-  //                              as key/value pairs and passing them to
-  //                              Map::Set;
-  //                              length must be an even number.
-  SetTag = ',',  // length:uint32_t -> pops the last object from the open stack
-                 // (it will be a Set);
-  //                              fills it with the last length elements pushed
-  //                              onto the deserialization stack, using Set::Add
-  GenerateFreshMapTag = ';',   // -> empty Map allocated an object ID and pushed
-                               // onto the open stack (ref)
-  GenerateFreshSetTag = '\'',  // -> empty Set allocated an object ID and pushed
-                               // onto the open stack (ref)
   VersionTag = 0xFF  // version:uint32_t -> Uses this as the file version.
 };
 
-enum ArrayBufferViewSubTag {
-  ByteArrayTag = 'b',
-  UnsignedByteArrayTag = 'B',
-  UnsignedByteClampedArrayTag = 'C',
-  ShortArrayTag = 'w',
-  UnsignedShortArrayTag = 'W',
-  IntArrayTag = 'd',
-  UnsignedIntArrayTag = 'D',
-  FloatArrayTag = 'f',
-  DoubleArrayTag = 'F',
-  DataViewTag = '?'
-};
-
 }  // namespace blink
 
 #endif
diff --git a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
index 68a6afc8..44b9806b2 100644
--- a/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/serialization/V8ScriptValueDeserializer.cpp
@@ -319,7 +319,7 @@
   ExceptionState exceptionState(isolate, ExceptionState::UnknownContext,
                                 nullptr, nullptr);
   ScriptWrappable* wrappable = nullptr;
-  SerializationTag tag = PaddingTag;
+  SerializationTag tag = VersionTag;
   if (readTag(&tag))
     wrappable = readDOMObject(tag);
   if (!wrappable) {
diff --git a/third_party/WebKit/Source/bindings/modules/v8/ConditionalFeaturesForModules.cpp b/third_party/WebKit/Source/bindings/modules/v8/ConditionalFeaturesForModules.cpp
index d2e318c..e2dfd25 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/ConditionalFeaturesForModules.cpp
+++ b/third_party/WebKit/Source/bindings/modules/v8/ConditionalFeaturesForModules.cpp
@@ -57,7 +57,9 @@
                                           v8::Local<v8::Object>(),
                                           prototypeObject, interfaceObject);
     }
-    if (OriginTrials::webUSBEnabled(executionContext)) {
+    // Mimics the [SecureContext] extended attribute.
+    if (OriginTrials::webUSBEnabled(executionContext) &&
+        executionContext->isSecureContext()) {
       V8NavigatorPartial::installWebUSB(isolate, world, v8::Local<v8::Object>(),
                                         prototypeObject, interfaceObject);
     }
@@ -71,7 +73,9 @@
       V8WindowPartial::installImageCapture(isolate, world, instanceObject,
                                            prototypeObject, interfaceObject);
     }
-    if (OriginTrials::webUSBEnabled(executionContext)) {
+    // Mimics the [SecureContext] extended attribute.
+    if (OriginTrials::webUSBEnabled(executionContext) &&
+        executionContext->isSecureContext()) {
       V8WindowPartial::installWebUSB(isolate, world, instanceObject,
                                      prototypeObject, interfaceObject);
     }
diff --git a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
index 0284812..93b230c 100644
--- a/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
+++ b/third_party/WebKit/Source/core/css/CSSGlobalRuleSet.h
@@ -34,7 +34,10 @@
   bool isDirty() const { return m_isDirty; }
   void update(Document&);
 
-  const RuleFeatureSet& ruleFeatureSet() const { return m_features; }
+  const RuleFeatureSet& ruleFeatureSet() const {
+    RELEASE_ASSERT(m_features.isAlive());
+    return m_features;
+  }
   RuleSet* siblingRuleSet() const { return m_siblingRuleSet; }
   RuleSet* uncommonAttributeRuleSet() const {
     return m_uncommonAttributeRuleSet;
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.cpp b/third_party/WebKit/Source/core/css/RuleFeature.cpp
index 9a9dffcd..7dd11cba 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.cpp
+++ b/third_party/WebKit/Source/core/css/RuleFeature.cpp
@@ -248,6 +248,7 @@
 void extractInvalidationSets(InvalidationSet* invalidationSet,
                              DescendantInvalidationSet*& descendants,
                              SiblingInvalidationSet*& siblings) {
+  RELEASE_ASSERT(invalidationSet->isAlive());
   if (invalidationSet->type() == InvalidateDescendants) {
     descendants = toDescendantInvalidationSet(invalidationSet);
     siblings = nullptr;
@@ -271,17 +272,33 @@
   visitor->trace(rule);
 }
 
+RuleFeatureSet::RuleFeatureSet() : m_isAlive(true) {}
+
+RuleFeatureSet::~RuleFeatureSet() {
+  RELEASE_ASSERT(m_isAlive);
+
+  m_metadata.clear();
+  m_classInvalidationSets.clear();
+  m_attributeInvalidationSets.clear();
+  m_idInvalidationSets.clear();
+  m_pseudoInvalidationSets.clear();
+  m_universalSiblingInvalidationSet.clear();
+  m_nthInvalidationSet.clear();
+
+  m_isAlive = false;
+}
+
 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensureClassInvalidationSet(
     const AtomicString& className,
     InvalidationType type) {
-  DCHECK(!className.isEmpty());
+  RELEASE_ASSERT(!className.isEmpty());
   return ensureInvalidationSet(m_classInvalidationSets, className, type);
 }
 
 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensureAttributeInvalidationSet(
     const AtomicString& attributeName,
     InvalidationType type) {
-  DCHECK(!attributeName.isEmpty());
+  RELEASE_ASSERT(!attributeName.isEmpty());
   return ensureInvalidationSet(m_attributeInvalidationSets, attributeName,
                                type);
 }
@@ -289,14 +306,14 @@
 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensureIdInvalidationSet(
     const AtomicString& id,
     InvalidationType type) {
-  DCHECK(!id.isEmpty());
+  RELEASE_ASSERT(!id.isEmpty());
   return ensureInvalidationSet(m_idInvalidationSets, id, type);
 }
 
 ALWAYS_INLINE InvalidationSet& RuleFeatureSet::ensurePseudoInvalidationSet(
     CSSSelector::PseudoType pseudoType,
     InvalidationType type) {
-  DCHECK(pseudoType != CSSSelector::PseudoUnknown);
+  RELEASE_ASSERT(pseudoType != CSSSelector::PseudoUnknown);
   return ensureInvalidationSet(m_pseudoInvalidationSets, pseudoType, type);
 }
 
@@ -785,6 +802,7 @@
 
 RuleFeatureSet::SelectorPreMatch RuleFeatureSet::collectFeaturesFromRuleData(
     const RuleData& ruleData) {
+  RELEASE_ASSERT(m_isAlive);
   FeatureMetadata metadata;
   if (collectFeaturesFromSelector(ruleData.selector(), metadata) ==
       SelectorNeverMatches)
@@ -901,7 +919,9 @@
 }
 
 void RuleFeatureSet::add(const RuleFeatureSet& other) {
-  DCHECK(&other != this);
+  RELEASE_ASSERT(m_isAlive);
+  RELEASE_ASSERT(other.m_isAlive);
+  RELEASE_ASSERT(&other != this);
   for (const auto& entry : other.m_classInvalidationSets)
     ensureInvalidationSet(m_classInvalidationSets, entry.key,
                           entry.value->type())
@@ -935,6 +955,7 @@
 }
 
 void RuleFeatureSet::clear() {
+  RELEASE_ASSERT(m_isAlive);
   m_siblingRules.clear();
   m_uncommonAttributeRules.clear();
   m_metadata.clear();
diff --git a/third_party/WebKit/Source/core/css/RuleFeature.h b/third_party/WebKit/Source/core/css/RuleFeature.h
index f0f4fee2..92804c8 100644
--- a/third_party/WebKit/Source/core/css/RuleFeature.h
+++ b/third_party/WebKit/Source/core/css/RuleFeature.h
@@ -68,7 +68,8 @@
   WTF_MAKE_NONCOPYABLE(RuleFeatureSet);
 
  public:
-  RuleFeatureSet() {}
+  RuleFeatureSet();
+  ~RuleFeatureSet();
 
   void add(const RuleFeatureSet&);
   void clear();
@@ -159,6 +160,8 @@
 
   DECLARE_TRACE();
 
+  bool isAlive() const { return m_isAlive; }
+
  protected:
   InvalidationSet* invalidationSetForSimpleSelector(const CSSSelector&,
                                                     InvalidationType);
@@ -295,6 +298,9 @@
   MediaQueryResultList m_viewportDependentMediaQueryResults;
   MediaQueryResultList m_deviceDependentMediaQueryResults;
 
+  // If true, the RuleFeatureSet is alive and can be used.
+  unsigned m_isAlive : 1;
+
   friend class RuleFeatureSetTest;
 };
 
diff --git a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
index c9831e7..7f62a35 100644
--- a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.cpp
@@ -62,7 +62,8 @@
       m_customPseudoInvalid(false),
       m_treeBoundaryCrossing(false),
       m_insertionPointCrossing(false),
-      m_invalidatesSlotted(false) {}
+      m_invalidatesSlotted(false),
+      m_isAlive(true) {}
 
 bool InvalidationSet::invalidatesElement(Element& element) const {
   if (m_allDescendantsMightBeInvalid)
@@ -108,8 +109,10 @@
 }
 
 void InvalidationSet::combine(const InvalidationSet& other) {
-  DCHECK(&other != this);
-  DCHECK(type() == other.type());
+  RELEASE_ASSERT(m_isAlive);
+  RELEASE_ASSERT(other.m_isAlive);
+  RELEASE_ASSERT(&other != this);
+  RELEASE_ASSERT(type() == other.type());
   if (type() == InvalidateSiblings) {
     SiblingInvalidationSet& siblings = toSiblingInvalidationSet(*this);
     const SiblingInvalidationSet& otherSiblings =
@@ -204,28 +207,28 @@
 void InvalidationSet::addClass(const AtomicString& className) {
   if (wholeSubtreeInvalid())
     return;
-  DCHECK(!className.isEmpty());
+  RELEASE_ASSERT(!className.isEmpty());
   ensureClassSet().insert(className);
 }
 
 void InvalidationSet::addId(const AtomicString& id) {
   if (wholeSubtreeInvalid())
     return;
-  DCHECK(!id.isEmpty());
+  RELEASE_ASSERT(!id.isEmpty());
   ensureIdSet().insert(id);
 }
 
 void InvalidationSet::addTagName(const AtomicString& tagName) {
   if (wholeSubtreeInvalid())
     return;
-  DCHECK(!tagName.isEmpty());
+  RELEASE_ASSERT(!tagName.isEmpty());
   ensureTagNameSet().insert(tagName);
 }
 
 void InvalidationSet::addAttribute(const AtomicString& attribute) {
   if (wholeSubtreeInvalid())
     return;
-  DCHECK(!attribute.isEmpty());
+  RELEASE_ASSERT(!attribute.isEmpty());
   ensureAttributeSet().insert(attribute);
 }
 
diff --git a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
index e6f0d35..b47bb0c 100644
--- a/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
+++ b/third_party/WebKit/Source/core/css/invalidation/InvalidationSet.h
@@ -127,6 +127,8 @@
            !m_invalidatesSlotted;
   }
 
+  bool isAlive() const { return m_isAlive; }
+
   void toTracedValue(TracedValue*) const;
 
 #ifndef NDEBUG
@@ -163,6 +165,11 @@
  protected:
   explicit InvalidationSet(InvalidationType);
 
+  ~InvalidationSet() {
+    RELEASE_ASSERT(m_isAlive);
+    m_isAlive = false;
+  }
+
  private:
   void destroy();
 
@@ -205,6 +212,9 @@
 
   // If true, distributed nodes of <slot> elements need to be invalidated.
   unsigned m_invalidatesSlotted : 1;
+
+  // If true, the instance is alive and can be used.
+  unsigned m_isAlive : 1;
 };
 
 class CORE_EXPORT DescendantInvalidationSet final : public InvalidationSet {
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
index 79c4df3..ed0fa52c 100644
--- a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
+++ b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
@@ -286,15 +286,19 @@
       m_pendingInvalidationMap.get(&node);
   DCHECK(pendingInvalidations);
 
-  for (const auto& invalidationSet : pendingInvalidations->siblings())
+  for (const auto& invalidationSet : pendingInvalidations->siblings()) {
+    RELEASE_ASSERT(invalidationSet->isAlive());
     siblingData.pushInvalidationSet(toSiblingInvalidationSet(*invalidationSet));
+  }
 
   if (node.getStyleChangeType() >= SubtreeStyleChange)
     return;
 
   if (!pendingInvalidations->descendants().isEmpty()) {
-    for (const auto& invalidationSet : pendingInvalidations->descendants())
+    for (const auto& invalidationSet : pendingInvalidations->descendants()) {
+      RELEASE_ASSERT(invalidationSet->isAlive());
       recursionData.pushInvalidationSet(*invalidationSet);
+    }
     if (UNLIKELY(*s_tracingEnabled)) {
       TRACE_EVENT_INSTANT1(
           TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index 319324f..84465a9 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -79,6 +79,27 @@
   return os << *it;
 }
 
+InputEvent::EventCancelable inputTypeIsCancelable(
+    InputEvent::InputType inputType) {
+  using InputType = InputEvent::InputType;
+  switch (inputType) {
+    case InputType::InsertText:
+    case InputType::InsertLineBreak:
+    case InputType::InsertParagraph:
+    case InputType::InsertCompositionText:
+    case InputType::InsertReplacementText:
+    case InputType::DeleteWordBackward:
+    case InputType::DeleteWordForward:
+    case InputType::DeleteLineBackward:
+    case InputType::DeleteLineForward:
+    case InputType::DeleteContentBackward:
+    case InputType::DeleteContentForward:
+      return InputEvent::EventCancelable::NotCancelable;
+    default:
+      return InputEvent::EventCancelable::IsCancelable;
+  }
+}
+
 }  // namespace
 
 static bool needsLayoutTreeUpdate(const Node& node) {
@@ -2060,11 +2081,11 @@
     return DispatchEventResult::NotCanceled;
   // TODO(chongz): Pass appropriate |ranges| after it's defined on spec.
   // http://w3c.github.io/editing/input-events.html#dom-inputevent-inputtype
-  InputEvent* beforeInputEvent =
-      InputEvent::createBeforeInput(InputEvent::InputType::InsertText, data,
-                                    InputEvent::EventCancelable::IsCancelable,
-                                    InputEvent::EventIsComposing::NotComposing,
-                                    targetRangesForInputEvent(*target));
+  InputEvent* beforeInputEvent = InputEvent::createBeforeInput(
+      InputEvent::InputType::InsertText, data,
+      inputTypeIsCancelable(InputEvent::InputType::InsertText),
+      InputEvent::EventIsComposing::NotComposing,
+      targetRangesForInputEvent(*target));
   return target->dispatchEvent(beforeInputEvent);
 }
 
@@ -2077,7 +2098,7 @@
   if (!target)
     return DispatchEventResult::NotCanceled;
   InputEvent* beforeInputEvent = InputEvent::createBeforeInput(
-      inputType, nullAtom, InputEvent::EventCancelable::IsCancelable,
+      inputType, nullAtom, inputTypeIsCancelable(inputType),
       InputEvent::EventIsComposing::NotComposing, ranges);
   return target->dispatchEvent(beforeInputEvent);
 }
@@ -2101,7 +2122,7 @@
 
   if (hasRichlyEditableStyle(*(target->toNode())) || !dataTransfer) {
     beforeInputEvent = InputEvent::createBeforeInput(
-        inputType, dataTransfer, InputEvent::EventCancelable::IsCancelable,
+        inputType, dataTransfer, inputTypeIsCancelable(inputType),
         InputEvent::EventIsComposing::NotComposing,
         targetRangesForInputEvent(*target));
   } else {
@@ -2109,7 +2130,7 @@
     // TODO(chongz): Pass appropriate |ranges| after it's defined on spec.
     // http://w3c.github.io/editing/input-events.html#dom-inputevent-inputtype
     beforeInputEvent = InputEvent::createBeforeInput(
-        inputType, data, InputEvent::EventCancelable::IsCancelable,
+        inputType, data, inputTypeIsCancelable(inputType),
         InputEvent::EventIsComposing::NotComposing,
         targetRangesForInputEvent(*target));
   }
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
index 640f161..f45bead8 100644
--- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
@@ -69,7 +69,7 @@
 
 const PositionWithAffinity FrameCaret::caretPosition() const {
   const VisibleSelection& selection =
-      m_selectionEditor->visibleSelection<EditingStrategy>();
+      m_selectionEditor->computeVisibleSelectionInDOMTree();
   if (!selection.isCaret())
     return PositionWithAffinity();
   return PositionWithAffinity(selection.start(), selection.affinity());
@@ -149,7 +149,7 @@
   bool shouldPaintCaret =
       m_shouldPaintCaret && isActive() &&
       m_caretVisibility == CaretVisibility::Visible &&
-      m_selectionEditor->visibleSelection<EditingStrategy>().hasEditableStyle();
+      m_selectionEditor->computeVisibleSelectionInDOMTree().hasEditableStyle();
 
   m_displayItemClient->updateStyleAndLayoutIfNeeded(
       shouldPaintCaret ? caretPosition() : PositionWithAffinity());
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
index 50a58635..09d6169 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -204,27 +204,6 @@
   EXPECT_EQ_SELECTED_TEXT("Foo Bar");
 }
 
-// TODO(yosin): We should move |SelectionControllerTest" to
-// "SelectionControllerTest.cpp"
-class SelectionControllerTest : public EditingTestBase {
- protected:
-  SelectionControllerTest() = default;
-
-  const VisibleSelection& visibleSelectionInDOMTree() const {
-    return selection().computeVisibleSelectionInDOMTreeDeprecated();
-  }
-
-  const VisibleSelectionInFlatTree& visibleSelectionInFlatTree() const {
-    return selection().selectionInFlatTree();
-  }
-
-  void setNonDirectionalSelectionIfNeeded(const VisibleSelectionInFlatTree&,
-                                          TextGranularity);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SelectionControllerTest);
-};
-
 TEST_F(FrameSelectionTest, SelectAllWithUnselectableRoot) {
   Element* select = document().createElement("select");
   document().replaceChild(select, document().documentElement());
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
index 3835d067..04dd0915 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -71,18 +71,6 @@
   return *lifecycleContext();
 }
 
-template <>
-const VisibleSelection& SelectionEditor::visibleSelection<EditingStrategy>()
-    const {
-  return computeVisibleSelectionInDOMTree();
-}
-
-template <>
-const VisibleSelectionInFlatTree&
-SelectionEditor::visibleSelection<EditingInFlatTreeStrategy>() const {
-  return computeVisibleSelectionInFlatTree();
-}
-
 const VisibleSelection& SelectionEditor::computeVisibleSelectionInDOMTree()
     const {
   DCHECK_EQ(frame()->document(), document());
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.h b/third_party/WebKit/Source/core/editing/SelectionEditor.h
index e2f7f6e..cde5ee9 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.h
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.h
@@ -53,8 +53,6 @@
   bool isContentEditable() const;
   bool isContentRichlyEditable() const;
 
-  template <typename Strategy>
-  const VisibleSelectionTemplate<Strategy>& visibleSelection() const;
   const SelectionInDOMTree& selectionInDOMTree() const;
 
   const VisibleSelection& computeVisibleSelectionInDOMTree() const;
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index 3fbaa8b..60dde507 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -138,14 +138,6 @@
 
 template <typename Strategy>
 void VisibleSelectionTemplate<Strategy>::setBase(
-    const PositionTemplate<Strategy>& position) {
-  DCHECK(!needsLayoutTreeUpdate(position));
-  m_base = position;
-  validate();
-}
-
-template <typename Strategy>
-void VisibleSelectionTemplate<Strategy>::setBase(
     const VisiblePositionTemplate<Strategy>& visiblePosition) {
   DCHECK(visiblePosition.isValid());
   m_base = visiblePosition.deepEquivalent();
@@ -154,14 +146,6 @@
 
 template <typename Strategy>
 void VisibleSelectionTemplate<Strategy>::setExtent(
-    const PositionTemplate<Strategy>& position) {
-  DCHECK(!needsLayoutTreeUpdate(position));
-  m_extent = position;
-  validate();
-}
-
-template <typename Strategy>
-void VisibleSelectionTemplate<Strategy>::setExtent(
     const VisiblePositionTemplate<Strategy>& visiblePosition) {
   DCHECK(visiblePosition.isValid());
   m_extent = visiblePosition.deepEquivalent();
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h
index 6da5081c..d5b0fab 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.h
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -69,9 +69,7 @@
   // TODO(yosin): To make |VisibleSelection| as immutable object, we should
   // get rid of |setBase()| and |setExtent()| by replacing them with
   // |createVisibleSelection()|.
-  void setBase(const PositionTemplate<Strategy>&);
   void setBase(const VisiblePositionTemplate<Strategy>&);
-  void setExtent(const PositionTemplate<Strategy>&);
   void setExtent(const VisiblePositionTemplate<Strategy>&);
 
   SelectionTemplate<Strategy> asSelection() const;
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 29ddba6..552536d 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -183,7 +183,9 @@
       m_stickyPositionObjectCount(0),
       m_inputEventsScaleFactorForEmulation(1),
       m_layoutSizeFixedToFrameSize(true),
-      m_didScrollTimer(this, &FrameView::didScrollTimerFired),
+      m_didScrollTimer(TaskRunnerHelper::get(TaskType::UnspecedTimer, &frame),
+                       this,
+                       &FrameView::didScrollTimerFired),
       m_needsUpdateWidgetGeometries(false),
       m_horizontalScrollbarMode(ScrollbarAuto),
       m_verticalScrollbarMode(ScrollbarAuto),
@@ -830,6 +832,12 @@
   if (needsLayout())
     return;
 
+  // If the visualViewport supplies scrollbars, we won't get a paint
+  // invalidation from computeScrollbarExistence so we need to force one
+  // TODO(bokan): We should avoid computeScrollbarExistence otherwise.
+  if (visualViewportSuppliesScrollbars())
+    layoutViewItem.setMayNeedPaintInvalidation();
+
   // TODO(pdr): This should be refactored to just block scrollbar updates as
   // we are not in a scrollbar update here and m_inUpdateScrollbars has other
   // side effects. This scope is only for preventing a synchronous layout from
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index 924c7807..c042f64 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -1104,7 +1104,7 @@
   IntSize m_initialViewportSize;
   bool m_layoutSizeFixedToFrameSize;
 
-  Timer<FrameView> m_didScrollTimer;
+  TaskRunnerTimer<FrameView> m_didScrollTimer;
 
   Vector<IntRect> m_tickmarks;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index a55d1e43..d8baa35f 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -328,7 +328,6 @@
 void HTMLCanvasElement::finalizeFrame() {
   if (hasImageBuffer())
     m_imageBuffer->finalizeFrame();
-  m_context->incrementFrameCount();
   notifyListenersCanvasChanged();
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index a3a195c2..ee9fcef 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -262,7 +262,7 @@
   if (contentMIMEType.isEmpty())
     return true;
 
-  // 4.8.10.3 MIME types - In the absence of a specification to the contrary,
+  // 4.8.12.3 MIME types - In the absence of a specification to the contrary,
   // the MIME type "application/octet-stream" when used with parameters, e.g.
   // "application/octet-stream;codecs=theora", is a type that the user agent
   // knows it cannot render.
@@ -337,7 +337,7 @@
   if (type.isEmpty())
     return MIMETypeRegistry::IsNotSupported;
 
-  // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty
+  // 4.8.12.3 MIME types - The canPlayType(type) method must return the empty
   // string if type is a type that the user agent knows it cannot render or is
   // the type "application/octet-stream"
   if (type == "application/octet-stream")
@@ -739,7 +739,7 @@
   MIMETypeRegistry::SupportsType support = supportsType(ContentType(mimeType));
   String canPlay;
 
-  // 4.8.10.3
+  // 4.8.12.3
   switch (support) {
     case MIMETypeRegistry::IsNotSupported:
       canPlay = emptyString;
@@ -1227,7 +1227,8 @@
 }
 
 void HTMLMediaElement::deferLoad() {
-  // This implements the "optional" step 3 from the resource fetch algorithm.
+  // This implements the "optional" step 4 from the resource fetch algorithm
+  // "If mode is remote".
   DCHECK(!m_deferredLoadTimer.isActive());
   DCHECK_EQ(m_deferredLoadState, NotDeferred);
   // 1. Set the networkState to NETWORK_IDLE.
@@ -1249,7 +1250,7 @@
 void HTMLMediaElement::executeDeferredLoad() {
   DCHECK_GE(m_deferredLoadState, WaitingForTrigger);
 
-  // resource fetch algorithm step 3 - continued from deferLoad().
+  // resource fetch algorithm step 4 - continued from deferLoad().
 
   // 5. Wait for an implementation-defined event (e.g. the user requesting that
   // the media element begin playback).  This is assumed to be whatever 'event'
@@ -1300,7 +1301,7 @@
 }
 
 bool HTMLMediaElement::textTracksAreReady() const {
-  // 4.8.10.12.1 Text track model
+  // 4.8.12.11.1 Text track model
   // ...
   // The text tracks of a media element are ready if all the text tracks whose
   // mode was not in the disabled state when the element's resource selection
@@ -1434,7 +1435,7 @@
   m_loadState = WaitingForSource;
   m_currentSourceNode = nullptr;
 
-  // 4.8.13.5
+  // 4.8.12.5
   // The dedicated media source failure steps are the following steps:
 
   // 1 - Set the error attribute to a new MediaError object whose code attribute
@@ -1651,14 +1652,14 @@
     return;
 
   if (m_seeking) {
-    // 4.8.10.9, step 9 note: If the media element was potentially playing
+    // 4.8.12.9, step 9 note: If the media element was potentially playing
     // immediately before it started seeking, but seeking caused its readyState
     // attribute to change to a value lower than kHaveFutureData, then a waiting
     // will be fired at the element.
     if (wasPotentiallyPlaying && m_readyState < kHaveFutureData)
       scheduleEvent(EventTypeNames::waiting);
 
-    // 4.8.10.9 steps 12-14
+    // 4.8.12.9 steps 12-14
     if (m_readyState >= kHaveCurrentData)
       finishSeek();
   } else {
@@ -1670,7 +1671,7 @@
       // media time at the moment we ran out of data to play.
       setOfficialPlaybackPosition(currentPlaybackPosition());
 
-      // 4.8.10.8
+      // 4.8.12.8
       scheduleTimeupdateEvent(false);
       scheduleEvent(EventTypeNames::waiting);
     }
@@ -2113,7 +2114,7 @@
 }
 
 bool HTMLMediaElement::ended() const {
-  // 4.8.10.8 Playing the media resource
+  // 4.8.12.8 Playing the media resource
   // The ended attribute must return true if the media element has ended
   // playback and the direction of playback is forwards, and false otherwise.
   return endedPlayback() && getDirectionOfPlayback() == Forward;
@@ -2295,7 +2296,7 @@
     webMediaPlayer()->setBufferingStrategy(
         WebMediaPlayer::BufferingStrategy::Normal);
 
-  // 4.8.10.9. Playing the media resource
+  // 4.8.12.8. Playing the media resource
   if (m_networkState == kNetworkEmpty)
     invokeResourceSelectionAlgorithm();
 
@@ -2681,7 +2682,7 @@
 }
 
 void HTMLMediaElement::addTextTrack(WebInbandTextTrack* webTrack) {
-  // 4.8.10.12.2 Sourcing in-band text tracks
+  // 4.8.12.11.2 Sourcing in-band text tracks
   // 1. Associate the relevant data with a new text track and its corresponding
   // new TextTrack object.
   InbandTextTrack* textTrack = InbandTextTrack::create(webTrack);
@@ -2792,7 +2793,7 @@
 }
 
 void HTMLMediaElement::didAddTrackElement(HTMLTrackElement* trackElement) {
-  // 4.8.10.12.3 Sourcing out-of-band text tracks
+  // 4.8.12.11.3 Sourcing out-of-band text tracks
   // When a track element's parent element changes and the new parent is a media
   // element, then the user agent must add the track element's corresponding
   // text track to the media element's list of text tracks ... [continues in
@@ -2823,7 +2824,7 @@
   if (!m_textTracks)
     return;
 
-  // 4.8.10.12.3 Sourcing out-of-band text tracks
+  // 4.8.12.11.3 Sourcing out-of-band text tracks
   // When a track element's parent element changes and the old parent was a
   // media element, then the user agent must remove the track element's
   // corresponding text track from the media element's list of text tracks.
@@ -3060,7 +3061,7 @@
 
   cueTimeline().updateActiveCues(currentTime());
 
-  // 4.8.10.9 steps 12-14. Needed if no ReadyState change is associated with the
+  // 4.8.12.9 steps 12-14. Needed if no ReadyState change is associated with the
   // seek.
   if (m_seeking && m_readyState >= kHaveCurrentData &&
       !webMediaPlayer()->seeking())
@@ -3311,7 +3312,7 @@
   if (std::isnan(dur))
     return false;
 
-  // 4.8.10.8 Playing the media resource
+  // 4.8.12.8 Playing the media resource
 
   // A media element is said to have ended playback when the element's
   // readyState attribute is HAVE_METADATA or greater,
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
index ce4019c1..5db6d54 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.cpp
@@ -160,12 +160,11 @@
   Platform::current()->currentThread()->removeTaskObserver(this);
   m_finalizeFrameScheduled = false;
 
-  if (!canvas())
-    return;
-
   // The end of a script task that drew content to the canvas is the point
   // at which the current frame may be considered complete.
-  canvas()->finalizeFrame();
+  if (canvas())
+    canvas()->finalizeFrame();
+  finalizeFrame();
 }
 
 CanvasRenderingContext::ContextType CanvasRenderingContext::contextTypeFromId(
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index b420788..a7bc7ddc 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -134,6 +134,11 @@
   };
   virtual void loseContext(LostContextMode) {}
 
+  // This method gets called at the end of script tasks that modified
+  // the contents of the canvas (called didDraw). It marks the completion
+  // of a presentable frame.
+  virtual void finalizeFrame() {}
+
   // WebThread::TaskObserver implementation
   void didProcessTask() override;
   void willProcessTask() final {}
@@ -157,7 +162,6 @@
   virtual String getIdFromControl(const Element* element) { return String(); }
   virtual bool isAccelerationOptimalForCanvasContent() const { return true; }
   virtual void resetUsageTracking(){};
-  virtual void incrementFrameCount(){};
 
   // WebGL-specific interface
   virtual bool is3d() const { return false; }
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index a39c79d..30352db 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -312,6 +312,8 @@
     "ng/ng_layout_opportunity_iterator.h",
     "ng/ng_layout_opportunity_tree_node.cc",
     "ng/ng_layout_opportunity_tree_node.h",
+    "ng/ng_layout_result.cc",
+    "ng/ng_layout_result.h",
     "ng/ng_length_utils.cc",
     "ng/ng_length_utils.h",
     "ng/ng_line_builder.cc",
diff --git a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
index 2f6e37c7b..7eb001cc 100644
--- a/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
+++ b/third_party/WebKit/Source/core/layout/ng/layout_ng_block_flow.cc
@@ -27,7 +27,7 @@
   // passes (probably FirstChild(), etc).
   m_box = new NGBlockNode(this);
 
-  RefPtr<NGPhysicalFragment> fragment = m_box->Layout(constraint_space);
+  RefPtr<NGLayoutResult> result = m_box->Layout(constraint_space);
 
   if (isOutOfFlowPositioned()) {
     // In legacy layout, abspos differs from regular blocks in that abspos
@@ -44,7 +44,7 @@
     setLogicalTop(computedValues.m_position);
   }
 
-  for (auto& descendant : fragment->OutOfFlowDescendants())
+  for (auto& descendant : result->OutOfFlowDescendants())
     descendant->UseOldOutOfFlowPositioning();
   clearNeedsLayout();
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
index 96ed873..9a7fda3 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.cc
@@ -210,7 +210,9 @@
   // Calculate the float offset if needed.
   LayoutUnit float_offset;
   if (floating_object->exclusion_type == NGExclusion::kFloatRight) {
-    float_offset = opportunity.size.inline_size - float_fragment.InlineSize();
+    LayoutUnit float_margin_box_inline_size =
+        float_fragment.InlineSize() + floating_object->margins.InlineSum();
+    float_offset = opportunity.size.inline_size - float_margin_box_inline_size;
   }
 
   // Add the float as an exclusion.
@@ -227,12 +229,13 @@
 // and {@code floating_object}'s space and margins.
 void UpdateFloatingObjectLeftOffset(
     const NGConstraintSpace& new_parent_space,
-    const Persistent<NGFloatingObject>& floating_object) {
-  const auto& float_space = floating_object->space;
+    const Persistent<NGFloatingObject>& floating_object,
+    const NGLogicalOffset& float_logical_offset) {
   // TODO(glebl): We should use physical offset here.
-  floating_object->left_offset = float_space->BfcOffset().inline_offset -
-                                 new_parent_space.BfcOffset().inline_offset +
-                                 floating_object->margins.inline_start;
+  floating_object->left_offset =
+      floating_object->original_parent_space->BfcOffset().inline_offset -
+      new_parent_space.BfcOffset().inline_offset +
+      float_logical_offset.inline_offset;
 }
 
 // Positions pending floats stored on the fragment builder starting from
@@ -245,18 +248,19 @@
 
   for (auto& floating_object : builder->UnpositionedFloats()) {
     Member<NGConstraintSpace> float_space = floating_object->space;
-    Member<const NGConstraintSpace> float_parent_space =
-        floating_object->parent_space;
+    Member<const NGConstraintSpace> original_parent_space =
+        floating_object->original_parent_space;
 
     NGLogicalOffset origin_point = {float_space->BfcOffset().inline_offset,
                                     origin_point_block_offset};
     NGLogicalOffset from_offset = {
-        float_parent_space->BfcOffset().inline_offset, bfc_block_offset};
+        original_parent_space->BfcOffset().inline_offset, bfc_block_offset};
 
     NGLogicalOffset float_fragment_offset =
         PositionFloat(origin_point, from_offset, floating_object);
     builder->AddFloatingObject(floating_object, float_fragment_offset);
-    UpdateFloatingObjectLeftOffset(new_parent_space, floating_object);
+    UpdateFloatingObjectLeftOffset(new_parent_space, floating_object,
+                                   float_fragment_offset);
   }
   builder->MutableUnpositionedFloats().clear();
 }
@@ -352,7 +356,7 @@
   return {inline_offset, block_offset};
 }
 
-RefPtr<NGPhysicalFragment> NGBlockLayoutAlgorithm::Layout() {
+RefPtr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
   WTF::Optional<MinAndMaxContentSizes> sizes;
   if (NeedMinAndMaxContentSizes(ConstraintSpace(), Style()))
     sizes = ComputeMinAndMaxContentSizes();
@@ -449,12 +453,13 @@
       continue;
     }
 
-    RefPtr<NGPhysicalFragment> physical_fragment =
+    RefPtr<NGLayoutResult> layout_result =
         current_child_->Layout(space_for_current_child_);
 
-    FinishCurrentChildLayout(toNGPhysicalBoxFragment(physical_fragment.get()));
+    FinishCurrentChildLayout(layout_result);
 
-    if (!ProceedToNextUnfinishedSibling(physical_fragment.get()))
+    if (!ProceedToNextUnfinishedSibling(
+            layout_result->PhysicalFragment().get()))
       break;
   }
 
@@ -512,30 +517,31 @@
   NGFragmentBuilder wrapper_fragment_builder(NGPhysicalFragment::kFragmentBox,
                                              current_child);
   line_builder.CreateFragments(&wrapper_fragment_builder);
-  RefPtr<NGPhysicalBoxFragment> child_fragment =
+  RefPtr<NGLayoutResult> child_result =
       wrapper_fragment_builder.ToBoxFragment();
   line_builder.CopyFragmentDataToLayoutBlockFlow();
-  FinishCurrentChildLayout(child_fragment.get());
+  FinishCurrentChildLayout(child_result);
   current_child_ = nullptr;
 }
 
 void NGBlockLayoutAlgorithm::FinishCurrentChildLayout(
-    RefPtr<NGPhysicalBoxFragment> physical_fragment) {
-  NGBoxFragment fragment(ConstraintSpace().WritingMode(),
-                         physical_fragment.get());
+    RefPtr<NGLayoutResult> layout_result) {
+  NGBoxFragment fragment(
+      ConstraintSpace().WritingMode(),
+      toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()));
 
   // Pull out unpositioned floats to the current fragment. This may needed if
   // for example the child fragment could not position its floats because it's
   // empty and therefore couldn't determine its position in space.
   builder_->MutableUnpositionedFloats().appendVector(
-      physical_fragment->UnpositionedFloats());
+      layout_result->UnpositionedFloats());
 
   if (current_child_->Type() == NGLayoutInputNode::kLegacyBlock &&
       CurrentChildStyle().isFloating()) {
-    NGFloatingObject* floating_object =
-        new NGFloatingObject(physical_fragment.get(), space_for_current_child_,
-                             constraint_space_, toNGBlockNode(current_child_),
-                             CurrentChildStyle(), curr_child_margins_);
+    NGFloatingObject* floating_object = new NGFloatingObject(
+        layout_result->PhysicalFragment().get(), space_for_current_child_,
+        constraint_space_, toNGBlockNode(current_child_), CurrentChildStyle(),
+        curr_child_margins_);
     builder_->AddUnpositionedFloat(floating_object);
     // No need to postpone the positioning if we know the correct offset.
     if (builder_->BfcOffset()) {
@@ -600,7 +606,7 @@
                                      curr_child_margins_.InlineSum() +
                                      border_and_padding_.InlineSum());
 
-  builder_->AddChild(std::move(physical_fragment), logical_offset);
+  builder_->AddChild(layout_result, logical_offset);
 }
 
 bool NGBlockLayoutAlgorithm::ProceedToNextUnfinishedSibling(
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
index 74365e48..4eaeda5 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm.h
@@ -21,6 +21,7 @@
 class NGConstraintSpace;
 class NGConstraintSpaceBuilder;
 class NGInlineNode;
+class NGLayoutResult;
 class NGPhysicalFragment;
 
 // A class for general block layout (e.g. a <div> with no special style).
@@ -37,7 +38,7 @@
                          NGBreakToken* break_token = nullptr);
 
   Optional<MinAndMaxContentSizes> ComputeMinAndMaxContentSizes() const override;
-  RefPtr<NGPhysicalFragment> Layout() override;
+  RefPtr<NGLayoutResult> Layout() override;
 
  private:
   NGBoxStrut CalculateMargins(const NGConstraintSpace& space,
@@ -45,7 +46,7 @@
 
   // Creates a new constraint space for the current child.
   NGConstraintSpace* CreateConstraintSpaceForCurrentChild();
-  void FinishCurrentChildLayout(RefPtr<NGPhysicalBoxFragment>);
+  void FinishCurrentChildLayout(RefPtr<NGLayoutResult>);
 
   // Layout inline children.
   void LayoutInlineChildren(NGInlineNode*);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
index 518eaef..8b3ba8b 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -63,10 +63,10 @@
     NGBlockNode* node = new NGBlockNode(style_.get());
     node->SetFirstChild(first_child);
 
-    RefPtr<NGPhysicalFragment> fragment =
+    RefPtr<NGLayoutResult> result =
         NGBlockLayoutAlgorithm(node, space).Layout();
 
-    return toNGPhysicalBoxFragment(fragment.get());
+    return toNGPhysicalBoxFragment(result->PhysicalFragment().get());
   }
 
   std::pair<RefPtr<NGPhysicalBoxFragment>, NGConstraintSpace*>
@@ -77,9 +77,10 @@
     NGConstraintSpace* space =
         NGConstraintSpace::CreateFromLayoutObject(*block_flow);
 
-    RefPtr<NGPhysicalFragment> fragment =
+    RefPtr<NGLayoutResult> result =
         NGBlockLayoutAlgorithm(node, space).Layout();
-    return std::make_pair(toNGPhysicalBoxFragment(fragment.get()), space);
+    return std::make_pair(
+        toNGPhysicalBoxFragment(result->PhysicalFragment().get()), space);
   }
 
   MinAndMaxContentSizes RunComputeMinAndMax(NGBlockNode* first_child) {
@@ -815,8 +816,9 @@
   setBodyInnerHTML(R"HTML(
       <style>
         #container {
-          height: 200px;
-          width: 200px;
+          height: 300px;
+          width: 300px;
+          outline: blue solid;
         }
         #empty1 {
           margin: 20px;
@@ -826,7 +828,7 @@
           margin: 15px;
           padding: 0 15px;
         }
-        #float {
+        #left-float {
           float: left;
           height: 5px;
           width: 5px;
@@ -834,11 +836,19 @@
           margin: 10px;
           background-color: green;
         }
+        #right-float {
+          float: right;
+          height: 15px;
+          width: 15px;
+          margin: 15px 10px;
+          background-color: red;
+        }
       </style>
       <div id='container'>
         <div id='empty1'>
           <div id='empty2'>
-            <div id='float'></div>
+            <div id='left-float'></div>
+            <div id='right-float'></div>
           </div>
         </div>
       </div>
@@ -876,16 +886,26 @@
   int empty2_inline_offset = 35;
   EXPECT_THAT(LayoutUnit(empty2_inline_offset), empty2_fragment->LeftOffset());
 
-  ASSERT_EQ(1UL, container_fragment->PositionedFloats().size());
-  auto float_fragment = container_fragment->PositionedFloats().at(0)->fragment;
-  // 10 = float's padding
-  EXPECT_THAT(LayoutUnit(10), float_fragment->TopOffset());
-  // 25 = empty2's padding(15) + float's padding(10)
-  int float_inline_offset = 25;
-  EXPECT_THAT(float_fragment->LeftOffset(), LayoutUnit(float_inline_offset));
+  ASSERT_EQ(2UL, container_fragment->PositionedFloats().size());
+  RefPtr<NGPhysicalFragment> left_float_fragment =
+      container_fragment->PositionedFloats().at(0)->fragment;
+  // inline 25 = empty2's padding(15) + left float's margin(10)
+  // block 10 = left float's margin
+  EXPECT_THAT(NGPhysicalOffset(LayoutUnit(25), LayoutUnit(10)),
+              left_float_fragment->Offset());
+
+  auto right_float_fragment =
+      container_fragment->PositionedFloats().at(1)->fragment;
+  LayoutUnit right_float_offset = LayoutUnit(125);
+  // inline offset 150 = empty2's padding(15) + right float's margin(10) + right
+  // float offset(125)
+  // block offset 15 = right float's margin
+  EXPECT_THAT(
+      NGPhysicalOffset(LayoutUnit(25) + right_float_offset, LayoutUnit(15)),
+      right_float_fragment->Offset());
 
   // ** Verify layout tree **
-  Element* left_float = document().getElementById("float");
+  Element* left_float = document().getElementById("left-float");
   // 88 = body's margin(8) +
   // empty1's padding and margin + empty2's padding and margins + float's
   // padding
@@ -894,18 +914,28 @@
   EXPECT_THAT(body_top_offset + 10, left_float->offsetTop());
 
   // ** Legacy Floating objects **
-  Element* body = document().getElementsByTagName("body")->item(0);
+  // #container is the 1st non-empty block so floats are attached to it.
+  Element* container = document().getElementById("container");
   auto& floating_objects =
       const_cast<FloatingObjects*>(
-          toLayoutBlockFlow(body->layoutObject())->floatingObjects())
+          toLayoutBlockFlow(container->layoutObject())->floatingObjects())
           ->mutableSet();
-  ASSERT_EQ(1UL, floating_objects.size());
-  auto floating_object = floating_objects.takeFirst();
-  ASSERT_TRUE(floating_object->isPlaced());
+  ASSERT_EQ(2UL, floating_objects.size());
+  auto left_floating_object = floating_objects.takeFirst();
+  ASSERT_TRUE(left_floating_object->isPlaced());
   // 80 = float_inline_offset(25) + accumulative offset of empty blocks(35 + 20)
-  EXPECT_THAT(LayoutUnit(80), floating_object->x());
-  // 10 = float's padding
-  EXPECT_THAT(LayoutUnit(10), floating_object->y());
+  EXPECT_THAT(LayoutUnit(80), left_floating_object->x());
+  // 10 = left float's margin
+  EXPECT_THAT(LayoutUnit(10), left_floating_object->y());
+
+  auto right_floating_object = floating_objects.takeFirst();
+  ASSERT_TRUE(right_floating_object->isPlaced());
+  // 205 = float_inline_offset(25) +
+  //       accumulative offset of empty blocks(35 + 20)
+  //       + right float offset(125)
+  EXPECT_THAT(LayoutUnit(80) + right_float_offset, right_floating_object->x());
+  // 15 = right float's margin
+  EXPECT_THAT(LayoutUnit(15), right_floating_object->y());
 }
 
 // Verifies that left/right floating and regular blocks can be positioned
@@ -2034,10 +2064,11 @@
       <div id="empty-block2"></div>
     </div>
   )HTML");
-  Element* body = document().getElementsByTagName("body")->item(0);
+  // #container is the new parent for our float because it's height != 0.
+  Element* container = document().getElementById("container");
   auto& floating_objects =
       const_cast<FloatingObjects*>(
-          toLayoutBlockFlow(body->layoutObject())->floatingObjects())
+          toLayoutBlockFlow(container->layoutObject())->floatingObjects())
           ->mutableSet();
   ASSERT_EQ(1UL, floating_objects.size());
   auto floating_object = floating_objects.takeFirst();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index 3ba94b6..0d36522 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -14,6 +14,7 @@
 #include "core/layout/ng/ng_constraint_space_builder.h"
 #include "core/layout/ng/ng_fragment_builder.h"
 #include "core/layout/ng/ng_inline_node.h"
+#include "core/layout/ng/ng_layout_result.h"
 #include "core/layout/ng/ng_length_utils.h"
 #include "core/layout/ng/ng_writing_mode.h"
 #include "core/paint/PaintLayer.h"
@@ -24,15 +25,15 @@
 namespace {
 
 // Copies data back to the legacy layout tree for a given child fragment.
-void FragmentPositionUpdated(const NGPhysicalBoxFragment& box_fragment) {
-  LayoutBox* layout_box = toLayoutBox(box_fragment.GetLayoutObject());
+void FragmentPositionUpdated(const NGPhysicalFragment& fragment) {
+  LayoutBox* layout_box = toLayoutBox(fragment.GetLayoutObject());
   if (!layout_box)
     return;
 
   DCHECK(layout_box->parent()) << "Should be called on children only.";
 
-  layout_box->setX(box_fragment.LeftOffset());
-  layout_box->setY(box_fragment.TopOffset());
+  layout_box->setX(fragment.LeftOffset());
+  layout_box->setY(fragment.TopOffset());
 }
 
 // Similar to FragmentPositionUpdated but for floats.
@@ -76,22 +77,21 @@
 // included from a compilation unit that lacks the ComputedStyle definition.
 NGBlockNode::~NGBlockNode() {}
 
-RefPtr<NGPhysicalFragment> NGBlockNode::Layout(
+RefPtr<NGLayoutResult> NGBlockNode::Layout(
     NGConstraintSpace* constraint_space) {
   // Use the old layout code and synthesize a fragment.
   if (!CanUseNewLayout()) {
     DCHECK(layout_box_);
-    fragment_ = RunOldLayout(*constraint_space);
-    return fragment_;
+    layout_result_ = RunOldLayout(*constraint_space);
+    return layout_result_;
   }
 
-  RefPtr<NGPhysicalFragment> fragment =
+  layout_result_ =
       NGBlockLayoutAlgorithm(this, constraint_space, CurrentBreakToken())
           .Layout();
 
-  fragment_ = toNGPhysicalBoxFragment(fragment.get());
   CopyFragmentDataToLayoutBox(*constraint_space);
-  return fragment_;
+  return layout_result_;
 }
 
 MinAndMaxContentSizes NGBlockNode::ComputeMinAndMaxContentSizes() {
@@ -127,9 +127,11 @@
     return *maybe_sizes;
 
   // Have to synthesize this value.
-  RefPtr<NGPhysicalFragment> physical_fragment = Layout(constraint_space);
+  RefPtr<NGLayoutResult> layout_result = Layout(constraint_space);
+  NGPhysicalFragment* physical_fragment =
+      layout_result->PhysicalFragment().get();
   NGBoxFragment min_fragment(FromPlatformWritingMode(Style().getWritingMode()),
-                             toNGPhysicalBoxFragment(physical_fragment.get()));
+                             toNGPhysicalBoxFragment(physical_fragment));
   sizes.min_content = min_fragment.InlineOverflow();
 
   // Now, redo with infinite space for max_content
@@ -141,9 +143,10 @@
           .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
           .ToConstraintSpace(FromPlatformWritingMode(Style().getWritingMode()));
 
-  physical_fragment = Layout(constraint_space);
+  layout_result = Layout(constraint_space);
+  physical_fragment = layout_result->PhysicalFragment().get();
   NGBoxFragment max_fragment(FromPlatformWritingMode(Style().getWritingMode()),
-                             toNGPhysicalBoxFragment(physical_fragment.get()));
+                             toNGPhysicalBoxFragment(physical_fragment));
   sizes.max_content = max_fragment.InlineOverflow();
   return sizes;
 }
@@ -196,7 +199,8 @@
 }
 
 NGBreakToken* NGBlockNode::CurrentBreakToken() const {
-  return fragment_ ? fragment_->BreakToken() : nullptr;
+  return layout_result_ ? layout_result_->PhysicalFragment()->BreakToken()
+                        : nullptr;
 }
 
 DEFINE_TRACE(NGBlockNode) {
@@ -237,20 +241,23 @@
   if (!layout_box_)
     return;
 
-  layout_box_->setWidth(fragment_->Width());
-  layout_box_->setHeight(fragment_->Height());
+  NGPhysicalBoxFragment* fragment =
+      toNGPhysicalBoxFragment(layout_result_->PhysicalFragment().get());
+
+  layout_box_->setWidth(fragment->Width());
+  layout_box_->setHeight(fragment->Height());
   NGBoxStrut border_and_padding =
       ComputeBorders(Style()) + ComputePadding(constraint_space, Style());
   LayoutUnit intrinsic_logical_height =
       layout_box_->style()->isHorizontalWritingMode()
-          ? fragment_->HeightOverflow()
-          : fragment_->WidthOverflow();
+          ? fragment->HeightOverflow()
+          : fragment->WidthOverflow();
   intrinsic_logical_height -= border_and_padding.BlockSum();
   layout_box_->setIntrinsicContentLogicalHeight(intrinsic_logical_height);
 
   // We may still have unpositioned floats when we reach the root box.
   if (!layout_box_->parent()) {
-    for (const auto& floating_object : fragment_->PositionedFloats()) {
+    for (const auto& floating_object : fragment->PositionedFloats()) {
       FloatingObjectPositionedUpdated(floating_object, layout_box_);
     }
   }
@@ -269,12 +276,14 @@
     // Ensure the position of the children are copied across to the
     // LayoutObject tree.
   } else {
-    for (const auto& child_fragment : fragment_->Children()) {
+    for (const auto& child_fragment : fragment->Children()) {
       if (child_fragment->IsPlaced())
         FragmentPositionUpdated(toNGPhysicalBoxFragment(*child_fragment));
 
-      for (const auto& floating_object : child_fragment->PositionedFloats()) {
-        FloatingObjectPositionedUpdated(floating_object, layout_box_);
+      for (const auto& floating_object :
+           toNGPhysicalBoxFragment(child_fragment.get())->PositionedFloats()) {
+        FloatingObjectPositionedUpdated(
+            floating_object, toLayoutBox(child_fragment->GetLayoutObject()));
       }
     }
   }
@@ -287,7 +296,7 @@
   }
 }
 
-RefPtr<NGPhysicalBoxFragment> NGBlockNode::RunOldLayout(
+RefPtr<NGLayoutResult> NGBlockNode::RunOldLayout(
     const NGConstraintSpace& constraint_space) {
   NGLogicalSize available_size = constraint_space.PercentageResolutionSize();
   LayoutObject* containing_block = layout_box_->containingBlock();
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
index c25506c..1893195 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.h
@@ -8,6 +8,7 @@
 #include "core/CoreExport.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/ng/ng_layout_input_node.h"
+#include "core/layout/ng/ng_layout_result.h"
 #include "core/layout/ng/ng_physical_box_fragment.h"
 #include "platform/heap/Handle.h"
 
@@ -17,8 +18,8 @@
 class LayoutObject;
 class NGBreakToken;
 class NGConstraintSpace;
+class NGLayoutResult;
 struct NGLogicalOffset;
-class NGPhysicalFragment;
 struct MinAndMaxContentSizes;
 
 // Represents a node to be laid out.
@@ -33,8 +34,7 @@
 
   ~NGBlockNode() override;
 
-  RefPtr<NGPhysicalFragment> Layout(
-      NGConstraintSpace* constraint_space) override;
+  RefPtr<NGLayoutResult> Layout(NGConstraintSpace* constraint_space) override;
   NGLayoutInputNode* NextSibling() override;
   LayoutObject* GetLayoutObject() override;
 
@@ -53,17 +53,16 @@
   void SetNextSibling(NGLayoutInputNode*);
   void SetFirstChild(NGLayoutInputNode*);
 
-  void SetFragment(NGPhysicalBoxFragment* fragment) { fragment_ = fragment; }
   NGBreakToken* CurrentBreakToken() const;
   bool IsLayoutFinished() const {
-    return fragment_ && !fragment_->BreakToken();
+    return layout_result_ && !layout_result_->PhysicalFragment()->BreakToken();
   }
 
   DECLARE_VIRTUAL_TRACE();
 
   // Runs layout on layout_box_ and creates a fragment for the resulting
   // geometry.
-  RefPtr<NGPhysicalBoxFragment> RunOldLayout(const NGConstraintSpace&);
+  RefPtr<NGLayoutResult> RunOldLayout(const NGConstraintSpace&);
 
   // Called if this is an out-of-flow block which needs to be
   // positioned with legacy layout.
@@ -87,9 +86,9 @@
   Member<NGLayoutInputNode> next_sibling_;
   Member<NGLayoutInputNode> first_child_;
   // TODO(mstensho): An input node may produce multiple fragments, so this
-  // should probably be renamed to last_fragment_ or something like that, since
+  // should probably be renamed to last_result_ or something like that, since
   // the last fragment is all we care about when resuming layout.
-  RefPtr<NGPhysicalBoxFragment> fragment_;
+  RefPtr<NGLayoutResult> layout_result_;
 };
 
 DEFINE_TYPE_CASTS(NGBlockNode,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h b/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h
index d55ea63a..0792952 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_floating_object.h
@@ -27,7 +27,7 @@
                    const NGBoxStrut& margins)
       : fragment(fragment),
         space(space),
-        parent_space(parent_space),
+        original_parent_space(parent_space),
         node(node),
         margins(margins) {
     exclusion_type = NGExclusion::kFloatLeft;
@@ -42,7 +42,7 @@
 
   // Parent space is used so we can calculate the inline offset relative to
   // the original parent of this float.
-  Member<const NGConstraintSpace> parent_space;
+  Member<const NGConstraintSpace> original_parent_space;
   Member<NGBlockNode> node;
   NGExclusion::Type exclusion_type;
   EClear clear_type;
@@ -59,7 +59,7 @@
 
   DEFINE_INLINE_TRACE() {
     visitor->trace(space);
-    visitor->trace(parent_space);
+    visitor->trace(original_parent_space);
     visitor->trace(node);
   }
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
index 4b69057..eb08d9a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.cc
@@ -52,7 +52,7 @@
 }
 
 NGFragmentBuilder& NGFragmentBuilder::AddChild(
-    RefPtr<NGPhysicalFragment> child,
+    RefPtr<NGLayoutResult> child,
     const NGLogicalOffset& child_offset) {
   DCHECK_EQ(type_, NGPhysicalFragment::kFragmentBox)
       << "Only box fragments can have children";
@@ -67,6 +67,15 @@
         OutOfFlowPlacement{child_offset, oof_position});
   }
 
+  return AddChild(child->PhysicalFragment(), child_offset);
+}
+
+NGFragmentBuilder& NGFragmentBuilder::AddChild(
+    RefPtr<NGPhysicalFragment> child,
+    const NGLogicalOffset& child_offset) {
+  DCHECK_EQ(type_, NGPhysicalFragment::kFragmentBox)
+      << "Only box fragments can have children";
+
   children_.push_back(std::move(child));
   offsets_.push_back(child_offset);
 
@@ -143,7 +152,7 @@
   return *this;
 }
 
-RefPtr<NGPhysicalBoxFragment> NGFragmentBuilder::ToBoxFragment() {
+RefPtr<NGLayoutResult> NGFragmentBuilder::ToBoxFragment() {
   // TODO(layout-ng): Support text fragments
   DCHECK_EQ(type_, NGPhysicalFragment::kFragmentBox);
   DCHECK_EQ(offsets_.size(), children_.size());
@@ -170,11 +179,14 @@
     positioned_floats.push_back(floating_object);
   }
 
-  return adoptRef(new NGPhysicalBoxFragment(
+  RefPtr<NGPhysicalBoxFragment> fragment = adoptRef(new NGPhysicalBoxFragment(
       node_->GetLayoutObject(), physical_size,
-      overflow_.ConvertToPhysical(writing_mode_), children_,
-      out_of_flow_descendants_, out_of_flow_positions_, unpositioned_floats_,
-      positioned_floats_, bfc_offset_, end_margin_strut_, break_token));
+      overflow_.ConvertToPhysical(writing_mode_), children_, positioned_floats_,
+      bfc_offset_, end_margin_strut_, break_token));
+
+  return adoptRef(
+      new NGLayoutResult(std::move(fragment), out_of_flow_descendants_,
+                         out_of_flow_positions_, unpositioned_floats_));
 }
 
 RefPtr<NGPhysicalTextFragment> NGFragmentBuilder::ToTextFragment(
@@ -191,9 +203,7 @@
   return adoptRef(new NGPhysicalTextFragment(
       node_->GetLayoutObject(), toNGInlineNode(node_), index, start_offset,
       end_offset, size_.ConvertToPhysical(writing_mode_),
-      overflow_.ConvertToPhysical(writing_mode_), out_of_flow_descendants_,
-      out_of_flow_positions_, empty_unpositioned_floats,
-      empty_positioned_floats));
+      overflow_.ConvertToPhysical(writing_mode_)));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
index 31926de8..7e9338c 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_fragment_builder.h
@@ -13,7 +13,7 @@
 
 namespace blink {
 
-class NGPhysicalBoxFragment;
+class NGLayoutResult;
 class NGPhysicalTextFragment;
 
 class CORE_EXPORT NGFragmentBuilder final {
@@ -32,6 +32,7 @@
   NGFragmentBuilder& SetInlineOverflow(LayoutUnit);
   NGFragmentBuilder& SetBlockOverflow(LayoutUnit);
 
+  NGFragmentBuilder& AddChild(RefPtr<NGLayoutResult>, const NGLogicalOffset&);
   NGFragmentBuilder& AddChild(RefPtr<NGPhysicalFragment>,
                               const NGLogicalOffset&);
   NGFragmentBuilder& AddFloatingObject(NGFloatingObject*,
@@ -89,7 +90,7 @@
   // do not provide a setter here.
 
   // Creates the fragment. Can only be called once.
-  RefPtr<NGPhysicalBoxFragment> ToBoxFragment();
+  RefPtr<NGLayoutResult> ToBoxFragment();
   RefPtr<NGPhysicalTextFragment> ToTextFragment(unsigned index,
                                                 unsigned start_offset,
                                                 unsigned end_offset);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
index 017ffc4..9fa7c643 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.cc
@@ -241,7 +241,7 @@
   }
 }
 
-RefPtr<NGPhysicalFragment> NGInlineNode::Layout(NGConstraintSpace*) {
+RefPtr<NGLayoutResult> NGInlineNode::Layout(NGConstraintSpace*) {
   ASSERT_NOT_REACHED();
   return nullptr;
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
index 023f36cc..392ddc2 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node.h
@@ -26,8 +26,8 @@
 class NGLayoutInlineItem;
 class NGLayoutInlineItemRange;
 class NGLayoutInlineItemsBuilder;
+class NGLayoutResult;
 class NGLineBuilder;
-class NGPhysicalFragment;
 
 // Represents an inline node to be laid out.
 class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
@@ -37,7 +37,7 @@
 
   const ComputedStyle* BlockStyle() const { return block_style_.get(); }
 
-  RefPtr<NGPhysicalFragment> Layout(NGConstraintSpace*) override;
+  RefPtr<NGLayoutResult> Layout(NGConstraintSpace*) override;
   void LayoutInline(NGConstraintSpace*, NGLineBuilder*);
   NGInlineNode* NextSibling() override;
   LayoutObject* GetLayoutObject() override;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
index 874ce41..2568b2c 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_inline_node_test.cc
@@ -75,8 +75,10 @@
 
     NGFragmentBuilder fragment_builder(NGPhysicalFragment::kFragmentBox, node);
     line_builder.CreateFragments(&fragment_builder);
-    RefPtr<NGPhysicalBoxFragment> fragment = fragment_builder.ToBoxFragment();
-    for (const auto& child : fragment->Children()) {
+    RefPtr<NGLayoutResult> result = fragment_builder.ToBoxFragment();
+    for (const auto& child :
+         toNGPhysicalBoxFragment(result->PhysicalFragment().get())
+             ->Children()) {
       fragments_out->push_back(toNGPhysicalTextFragment(child.get()));
     }
   }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
index 99b8da2..bc2250c 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_algorithm.h
@@ -14,7 +14,7 @@
 namespace blink {
 
 struct MinAndMaxContentSizes;
-class NGPhysicalFragment;
+class NGLayoutResult;
 
 // Base class for all LayoutNG algorithms.
 class CORE_EXPORT NGLayoutAlgorithm {
@@ -24,10 +24,10 @@
   virtual ~NGLayoutAlgorithm() {}
 
   // Actual layout function. Lays out the children and descendents within the
-  // constraints given by the NGConstraintSpace. Returns a fragment with the
-  // resulting layout information.
+  // constraints given by the NGConstraintSpace. Returns a layout result with
+  // the resulting layout information.
   // TODO(layout-dev): attempt to make this function const.
-  virtual RefPtr<NGPhysicalFragment> Layout() = 0;
+  virtual RefPtr<NGLayoutResult> Layout() = 0;
 
   // Computes the min-content and max-content intrinsic sizes for the given box.
   // The result will not take any min-width, max-width or width properties into
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
index ed282c81..0c36cde 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_input_node.h
@@ -12,7 +12,7 @@
 
 class LayoutObject;
 class NGConstraintSpace;
-class NGPhysicalFragment;
+class NGLayoutResult;
 
 // Represents the input to a layout algorithm for a given node. The layout
 // engine should use the style, node type to determine which type of layout
@@ -24,8 +24,8 @@
 
   virtual ~NGLayoutInputNode(){};
 
-  // Performs layout on this input node, will return a new fragment.
-  virtual RefPtr<NGPhysicalFragment> Layout(NGConstraintSpace*) = 0;
+  // Performs layout on this input node, will return the layout result.
+  virtual RefPtr<NGLayoutResult> Layout(NGConstraintSpace*) = 0;
 
   // Returns the next sibling.
   virtual NGLayoutInputNode* NextSibling() = 0;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
new file mode 100644
index 0000000..5a45423
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.cc
@@ -0,0 +1,22 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/layout/ng/ng_layout_result.h"
+
+#include "core/layout/ng/ng_floating_object.h"
+
+namespace blink {
+
+NGLayoutResult::NGLayoutResult(
+    PassRefPtr<NGPhysicalFragment> physical_fragment,
+    PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
+        out_of_flow_descendants,
+    Vector<NGStaticPosition> out_of_flow_positions,
+    Vector<Persistent<NGFloatingObject>>& unpositioned_floats)
+    : physical_fragment_(physical_fragment),
+      out_of_flow_descendants_(out_of_flow_descendants),
+      out_of_flow_positions_(out_of_flow_positions),
+      unpositioned_floats_(unpositioned_floats) {}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
new file mode 100644
index 0000000..49d206a
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_layout_result.h
@@ -0,0 +1,73 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NGLayoutResult_h
+#define NGLayoutResult_h
+
+#include "core/CoreExport.h"
+#include "core/layout/ng/ng_physical_fragment.h"
+#include "core/layout/ng/ng_units.h"
+#include "platform/LayoutUnit.h"
+#include "platform/heap/Handle.h"
+#include "wtf/Vector.h"
+
+namespace blink {
+
+class LayoutObject;
+class NGPhysicalFragment;
+class NGBlockNode;
+struct NGFloatingObject;
+
+// The NGLayoutResult stores the resulting data from layout. This includes
+// geometry information in form of a NGPhysicalFragment, which is kept around
+// for painting, hit testing, etc., as well as additional data which is only
+// necessary during layout and stored on this object.
+// Layout code should access the NGPhysicalFragment through the wrappers in
+// NGFragment et al.
+class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
+ public:
+  RefPtr<NGPhysicalFragment> PhysicalFragment() const {
+    return physical_fragment_;
+  }
+
+  const HeapLinkedHashSet<WeakMember<NGBlockNode>>& OutOfFlowDescendants()
+      const {
+    return out_of_flow_descendants_;
+  }
+
+  const Vector<NGStaticPosition>& OutOfFlowPositions() const {
+    return out_of_flow_positions_;
+  }
+
+  // List of floats that need to be positioned by the next in-flow child that
+  // can determine its position in space.
+  // Use case example where it may be needed:
+  //    <div><float></div>
+  //    <div style="margin-top: 10px; height: 20px"></div>
+  // The float cannot be positioned right away inside of the 1st div because
+  // the vertical position is not known at that moment. It will be known only
+  // after the 2nd div collapses its margin with its parent.
+  const Vector<Persistent<NGFloatingObject>>& UnpositionedFloats() const {
+    return unpositioned_floats_;
+  }
+
+ private:
+  friend class NGFragmentBuilder;
+
+  NGLayoutResult(PassRefPtr<NGPhysicalFragment> physical_fragment,
+                 PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
+                     out_of_flow_descendants,
+                 Vector<NGStaticPosition> out_of_flow_positions,
+                 Vector<Persistent<NGFloatingObject>>& unpositioned_floats);
+
+  RefPtr<NGPhysicalFragment> physical_fragment_;
+  LayoutObject* layout_object_;
+  PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_descendants_;
+  Vector<NGStaticPosition> out_of_flow_positions_;
+  Vector<Persistent<NGFloatingObject>> unpositioned_floats_;
+};
+
+}  // namespace blink
+
+#endif  // NGLayoutResult_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
index edf7f11..da091be 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -78,10 +78,10 @@
       if (IsContainingBlockForAbsoluteDescendant(container_style_,
                                                  descendant->Style())) {
         NGLogicalOffset offset;
-        RefPtr<NGPhysicalFragment> physical_fragment =
+        RefPtr<NGLayoutResult> result =
             LayoutDescendant(*descendant, static_position, &offset);
         // TODO(atotic) Need to adjust size of overflow rect per spec.
-        container_builder_->AddChild(std::move(physical_fragment), offset);
+        container_builder_->AddChild(std::move(result), offset);
       } else {
         container_builder_->AddOutOfFlowDescendant(descendant, static_position);
       }
@@ -95,7 +95,7 @@
   }
 }
 
-RefPtr<NGPhysicalFragment> NGOutOfFlowLayoutPart::LayoutDescendant(
+RefPtr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
     NGBlockNode& descendant,
     NGStaticPosition static_position,
     NGLogicalOffset* offset) {
@@ -104,7 +104,7 @@
   // relative to the container's padding box.
   static_position.offset -= container_border_physical_offset_;
 
-  RefPtr<NGPhysicalFragment> physical_fragment = nullptr;
+  RefPtr<NGLayoutResult> layout_result = nullptr;
   Optional<MinAndMaxContentSizes> inline_estimate;
   Optional<LayoutUnit> block_estimate;
 
@@ -118,12 +118,12 @@
           inline_estimate);
 
   if (AbsoluteNeedsChildBlockSize(descendant.Style())) {
-    physical_fragment =
-        GenerateFragment(descendant, block_estimate, node_position);
+    layout_result = GenerateFragment(descendant, block_estimate, node_position);
 
     // TODO(ikilpatrick): the writing mode switching here looks wrong.
-    NGBoxFragment fragment(container_space_->WritingMode(),
-                           toNGPhysicalBoxFragment(physical_fragment.get()));
+    NGBoxFragment fragment(
+        container_space_->WritingMode(),
+        toNGPhysicalBoxFragment(layout_result->PhysicalFragment().get()));
 
     block_estimate = fragment.BlockSize();
   }
@@ -133,12 +133,11 @@
                                         &node_position);
 
   // Skip this step if we produced a fragment when estimating the block size.
-  if (!physical_fragment) {
+  if (!layout_result) {
     block_estimate =
         node_position.size.ConvertToLogical(container_space_->WritingMode())
             .block_size;
-    physical_fragment =
-        GenerateFragment(descendant, block_estimate, node_position);
+    layout_result = GenerateFragment(descendant, block_estimate, node_position);
   }
 
   // Compute logical offset, NGAbsolutePhysicalPosition is calculated relative
@@ -150,10 +149,10 @@
   offset->block_offset =
       inset.block_start + container_border_offset_.block_offset;
 
-  return physical_fragment;
+  return layout_result;
 }
 
-RefPtr<NGPhysicalFragment> NGOutOfFlowLayoutPart::GenerateFragment(
+RefPtr<NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
     NGBlockNode& descendant,
     const Optional<LayoutUnit>& block_estimate,
     const NGAbsolutePhysicalPosition node_position) {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
index daf91ef2..284f7b34 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -20,6 +20,7 @@
 class NGBlockNode;
 class NGFragmentBuilder;
 class NGConstraintSpace;
+class NGLayoutResult;
 
 // Helper class for positioning of out-of-flow blocks.
 // It should be used together with NGFragmentBuilder.
@@ -34,11 +35,11 @@
   void Run();
 
  private:
-  RefPtr<NGPhysicalFragment> LayoutDescendant(NGBlockNode& descendant,
-                                              NGStaticPosition static_position,
-                                              NGLogicalOffset* offset);
+  RefPtr<NGLayoutResult> LayoutDescendant(NGBlockNode& descendant,
+                                          NGStaticPosition static_position,
+                                          NGLogicalOffset* offset);
 
-  RefPtr<NGPhysicalFragment> GenerateFragment(
+  RefPtr<NGLayoutResult> GenerateFragment(
       NGBlockNode& node,
       const Optional<LayoutUnit>& block_estimate,
       const NGAbsolutePhysicalPosition node_position);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index 1af3ab533..d4a1a11 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -67,8 +67,8 @@
   NGConstraintSpace* space =
       NGConstraintSpace::CreateFromLayoutObject(*block_flow);
   NGBlockNode* node = new NGBlockNode(block_flow);
-  RefPtr<NGPhysicalFragment> fragment = node->Layout(space);
-  EXPECT_EQ(fragment->OutOfFlowDescendants().size(), (size_t)2);
+  RefPtr<NGLayoutResult> result = node->Layout(space);
+  EXPECT_EQ(result->OutOfFlowDescendants().size(), (size_t)2);
 
   // Test the final result.
   Element* fixed_1 = document().getElementById("fixed1");
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
index ad9d2fcd..04d247bf 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
@@ -4,6 +4,8 @@
 
 #include "core/layout/ng/ng_physical_box_fragment.h"
 
+#include "core/layout/ng/ng_floating_object.h"
+
 namespace blink {
 
 NGPhysicalBoxFragment::NGPhysicalBoxFragment(
@@ -11,10 +13,6 @@
     NGPhysicalSize size,
     NGPhysicalSize overflow,
     Vector<RefPtr<NGPhysicalFragment>>& children,
-    PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
-        out_of_flow_descendants,
-    Vector<NGStaticPosition>& out_of_flow_positions,
-    Vector<Persistent<NGFloatingObject>>& unpositioned_floats,
     Vector<Persistent<NGFloatingObject>>& positioned_floats,
     const WTF::Optional<NGLogicalOffset>& bfc_offset,
     const NGMarginStrut& end_margin_strut,
@@ -23,11 +21,8 @@
                          size,
                          overflow,
                          kFragmentBox,
-                         out_of_flow_descendants,
-                         out_of_flow_positions,
-                         unpositioned_floats,
-                         positioned_floats,
                          break_token),
+      positioned_floats_(positioned_floats),
       bfc_offset_(bfc_offset),
       end_margin_strut_(end_margin_strut) {
   children_.swap(children);
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
index 5326966..1a259c1a 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
@@ -13,7 +13,6 @@
 
 namespace blink {
 
-class NGBlockNode;
 struct NGFloatingObject;
 
 class CORE_EXPORT NGPhysicalBoxFragment final : public NGPhysicalFragment {
@@ -24,10 +23,6 @@
       NGPhysicalSize size,
       NGPhysicalSize overflow,
       Vector<RefPtr<NGPhysicalFragment>>& children,
-      PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
-          out_of_flow_descendants,
-      Vector<NGStaticPosition>& out_of_flow_positions,
-      Vector<Persistent<NGFloatingObject>>& unpositioned_floats,
       Vector<Persistent<NGFloatingObject>>& positioned_floats,
       const WTF::Optional<NGLogicalOffset>& bfc_offset,
       const NGMarginStrut& end_margin_strut,
@@ -37,6 +32,13 @@
     return children_;
   }
 
+  // List of positioned float that need to be copied to the old layout tree.
+  // TODO(layout-ng): remove this once we change painting code to handle floats
+  // differently.
+  const Vector<Persistent<NGFloatingObject>>& PositionedFloats() const {
+    return positioned_floats_;
+  }
+
   const WTF::Optional<NGLogicalOffset>& BfcOffset() const {
     return bfc_offset_;
   }
@@ -45,6 +47,7 @@
 
  private:
   Vector<RefPtr<NGPhysicalFragment>> children_;
+  Vector<Persistent<NGFloatingObject>> positioned_floats_;
   const WTF::Optional<NGLogicalOffset> bfc_offset_;
   const NGMarginStrut end_margin_strut_;
 };
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
index b0491072..291a8f7 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
@@ -10,28 +10,17 @@
 
 namespace blink {
 
-NGPhysicalFragment::NGPhysicalFragment(
-    LayoutObject* layout_object,
-    NGPhysicalSize size,
-    NGPhysicalSize overflow,
-    NGFragmentType type,
-    PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
-        out_of_flow_descendants,
-    Vector<NGStaticPosition> out_of_flow_positions,
-    Vector<Persistent<NGFloatingObject>>& unpositioned_floats,
-    Vector<Persistent<NGFloatingObject>>& positioned_floats,
-    NGBreakToken* break_token)
+NGPhysicalFragment::NGPhysicalFragment(LayoutObject* layout_object,
+                                       NGPhysicalSize size,
+                                       NGPhysicalSize overflow,
+                                       NGFragmentType type,
+                                       NGBreakToken* break_token)
     : layout_object_(layout_object),
       size_(size),
       overflow_(overflow),
       break_token_(break_token),
       type_(type),
-      is_placed_(false) {
-  out_of_flow_descendants_.swap(out_of_flow_descendants);
-  out_of_flow_positions_.swap(out_of_flow_positions);
-  unpositioned_floats_.swap(unpositioned_floats);
-  positioned_floats_.swap(positioned_floats);
-}
+      is_placed_(false) {}
 
 void NGPhysicalFragment::destroy() const {
   if (Type() == kFragmentText)
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
index 2ccd3e5..2d014c50 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
@@ -14,11 +14,9 @@
 namespace blink {
 
 class LayoutObject;
-class NGBlockNode;
 class NGBreakToken;
-struct NGFloatingObject;
 
-// The NGPhysicalFragment contains the output information from layout. The
+// The NGPhysicalFragment contains the output geometry from layout. The
 // fragment stores all of its information in the physical coordinate system for
 // use by paint, hit-testing etc.
 //
@@ -26,8 +24,8 @@
 // Once we have transitioned fully to LayoutNG it should be a const pointer
 // such that paint/hit-testing/etc don't modify it.
 //
-// Layout code should only access output layout information through the
-// NGFragmentBase classes which transforms information into the logical
+// Layout code should only access geometry information through the
+// NGFragment wrapper classes which transforms information into the logical
 // coordinate system.
 class CORE_EXPORT NGPhysicalFragment : public RefCounted<NGPhysicalFragment> {
  public:
@@ -82,46 +80,13 @@
 
   LayoutObject* GetLayoutObject() const { return layout_object_; }
 
-  const HeapLinkedHashSet<WeakMember<NGBlockNode>>& OutOfFlowDescendants()
-      const {
-    return out_of_flow_descendants_;
-  }
-
-  const Vector<NGStaticPosition>& OutOfFlowPositions() const {
-    return out_of_flow_positions_;
-  }
-
   bool IsPlaced() const { return is_placed_; }
 
-  // List of floats that need to be positioned by the next in-flow child that
-  // can determine its position in space.
-  // Use case example where it may be needed:
-  //    <div><float></div>
-  //    <div style="margin-top: 10px; height: 20px"></div>
-  // The float cannot be positioned right away inside of the 1st div because
-  // the vertical position is not known at that moment. It will be known only
-  // after the 2nd div collapses its margin with its parent.
-  const Vector<Persistent<NGFloatingObject>>& UnpositionedFloats() const {
-    return unpositioned_floats_;
-  }
-
-  // List of positioned float that need to be copied to the old layout tree.
-  // TODO(layout-ng): remove this once we change painting code to handle floats
-  // differently.
-  const Vector<Persistent<NGFloatingObject>>& PositionedFloats() const {
-    return positioned_floats_;
-  }
-
  protected:
   NGPhysicalFragment(LayoutObject* layout_object,
                      NGPhysicalSize size,
                      NGPhysicalSize overflow,
                      NGFragmentType type,
-                     PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
-                         out_of_flow_descendants,
-                     Vector<NGStaticPosition> out_of_flow_positions,
-                     Vector<Persistent<NGFloatingObject>>& unpositioned_floats,
-                     Vector<Persistent<NGFloatingObject>>& positioned_floats,
                      NGBreakToken* break_token = nullptr);
 
   LayoutObject* layout_object_;
@@ -129,10 +94,6 @@
   NGPhysicalSize overflow_;
   NGPhysicalOffset offset_;
   Persistent<NGBreakToken> break_token_;
-  PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>> out_of_flow_descendants_;
-  Vector<NGStaticPosition> out_of_flow_positions_;
-  Vector<Persistent<NGFloatingObject>> unpositioned_floats_;
-  Vector<Persistent<NGFloatingObject>> positioned_floats_;
 
   unsigned type_ : 1;
   unsigned is_placed_ : 1;
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_text_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_text_fragment.h
index bb33b0f1..ad9540e 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_text_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_text_fragment.h
@@ -16,27 +16,14 @@
 
 class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
  public:
-  NGPhysicalTextFragment(
-      LayoutObject* layout_object,
-      const NGInlineNode* node,
-      unsigned item_index,
-      unsigned start_offset,
-      unsigned end_offset,
-      NGPhysicalSize size,
-      NGPhysicalSize overflow,
-      PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>&
-          out_of_flow_descendants,
-      Vector<NGStaticPosition> out_of_flow_positions,
-      Vector<Persistent<NGFloatingObject>>& unpositioned_floats,
-      Vector<Persistent<NGFloatingObject>>& positioned_floats)
-      : NGPhysicalFragment(layout_object,
-                           size,
-                           overflow,
-                           kFragmentText,
-                           out_of_flow_descendants,
-                           out_of_flow_positions,
-                           unpositioned_floats,
-                           positioned_floats),
+  NGPhysicalTextFragment(LayoutObject* layout_object,
+                         const NGInlineNode* node,
+                         unsigned item_index,
+                         unsigned start_offset,
+                         unsigned end_offset,
+                         NGPhysicalSize size,
+                         NGPhysicalSize overflow)
+      : NGPhysicalFragment(layout_object, size, overflow, kFragmentText),
         node_(node),
         item_index_(item_index),
         start_offset_(start_offset),
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
index 1f1e593..ab37fec 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.cc
@@ -26,7 +26,7 @@
   DCHECK(inline_box_);
 }
 
-RefPtr<NGPhysicalFragment> NGTextLayoutAlgorithm::Layout() {
+RefPtr<NGLayoutResult> NGTextLayoutAlgorithm::Layout() {
   ASSERT_NOT_REACHED();
   return nullptr;
 }
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
index fec586d21..7107769 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_text_layout_algorithm.h
@@ -32,7 +32,7 @@
                         NGConstraintSpace* space,
                         NGBreakToken* break_token = nullptr);
 
-  RefPtr<NGPhysicalFragment> Layout() override;
+  RefPtr<NGLayoutResult> Layout() override;
   void LayoutInline(NGLineBuilder*);
 
  private:
diff --git a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
index 23d2efb..a7c502c1 100644
--- a/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxPaintInvalidator.cpp
@@ -117,8 +117,7 @@
   const ComputedStyle& style = m_box.styleRef();
 
   if ((style.backgroundLayers().thisOrNextLayersUseContentBox() ||
-       style.maskLayers().thisOrNextLayersUseContentBox() ||
-       style.boxSizing() == EBoxSizing::kBorderBox) &&
+       style.maskLayers().thisOrNextLayersUseContentBox()) &&
       previousContentBoxRect() != m_box.contentBoxRect())
     return PaintInvalidationContentBoxChange;
 
@@ -319,11 +318,6 @@
 
   const ComputedStyle& style = m_box.styleRef();
 
-  // If we use border-box sizing we need to track changes in the size of the
-  // content box.
-  if (style.boxSizing() == EBoxSizing::kBorderBox)
-    return true;
-
   // Background and mask layers can depend on other boxes than border box. See
   // crbug.com/490533
   if (style.backgroundLayers().thisOrNextLayersUseContentBox() ||
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index e4544c51..4318b01 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -640,6 +640,9 @@
         borderBottomWidth() != other.borderBottomWidth() ||
         borderRightWidth() != other.borderRightWidth())
       return true;
+
+    if (m_surround->padding != other.m_surround->padding)
+      return true;
   }
 
   if (m_rareNonInheritedData.get() != other.m_rareNonInheritedData.get()) {
@@ -884,11 +887,6 @@
       position() != other.position())
     return true;
 
-  if (m_surround.get() != other.m_surround.get()) {
-    if (m_surround->padding != other.m_surround->padding)
-      return true;
-  }
-
   if (m_rareNonInheritedData.get() != other.m_rareNonInheritedData.get()) {
     if (m_rareNonInheritedData->m_alignContent !=
             other.m_rareNonInheritedData->m_alignContent ||
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 20449ab..b1890ab 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -111,36 +111,8 @@
 void SVGElement::buildPendingResourcesIfNeeded() {
   if (!needsPendingResourceHandling() || !isConnected() || inUseShadowTree())
     return;
-
-  SVGTreeScopeResources& treeScopeResources =
-      treeScope().ensureSVGTreeScopedResources();
-  AtomicString resourceId = getIdAttribute();
-  if (!treeScopeResources.hasPendingResource(resourceId))
-    return;
-  // Guaranteed by hasPendingResource.
-  DCHECK(!resourceId.isEmpty());
-
-  // Get pending elements for this id.
-  SVGTreeScopeResources::SVGPendingElements* pendingElements =
-      treeScopeResources.removePendingResource(resourceId);
-  if (!pendingElements || pendingElements->isEmpty())
-    return;
-
-  // Rebuild pending resources for each client of a pending resource that is
-  // being removed.
-  for (Element* clientElement : *pendingElements) {
-    DCHECK(clientElement->hasPendingResources());
-    if (!clientElement->hasPendingResources())
-      continue;
-    // TODO(fs): Ideally we'd always resolve pending resources async instead of
-    // inside insertedInto and svgAttributeChanged. For now we only do it for
-    // <use> since that would stamp out DOM.
-    if (isSVGUseElement(clientElement))
-      toSVGUseElement(clientElement)->invalidateShadowTree();
-    else
-      clientElement->buildPendingResource();
-    treeScopeResources.clearHasPendingResourcesIfPossible(clientElement);
-  }
+  treeScope().ensureSVGTreeScopedResources().notifyResourceAvailable(
+      getIdAttribute());
 }
 
 SVGElementRareData* SVGElement::ensureSVGRareData() {
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
index 4cb6f3c..9617851 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.cpp
@@ -8,6 +8,7 @@
 #include "core/dom/TreeScope.h"
 #include "core/layout/svg/LayoutSVGResourceContainer.h"
 #include "core/layout/svg/SVGResourcesCache.h"
+#include "core/svg/SVGUseElement.h"
 #include "wtf/text/AtomicString.h"
 
 namespace blink {
@@ -152,6 +153,31 @@
   return m_pendingResources.take(id);
 }
 
+void SVGTreeScopeResources::notifyResourceAvailable(const AtomicString& id) {
+  if (id.isEmpty())
+    return;
+  // Get pending elements for this id.
+  SVGPendingElements* pendingElements = m_pendingResources.take(id);
+  if (!pendingElements)
+    return;
+  // Rebuild pending resources for each client of a pending resource that is
+  // being removed.
+  for (Element* clientElement : *pendingElements) {
+    DCHECK(clientElement->hasPendingResources());
+    if (!clientElement->hasPendingResources())
+      continue;
+    // TODO(fs): Ideally we'd always resolve pending resources async instead of
+    // inside insertedInto and svgAttributeChanged. For now we only do it for
+    // <use> since that would stamp out DOM.
+    if (isSVGUseElement(clientElement))
+      toSVGUseElement(clientElement)->invalidateShadowTree();
+    else
+      clientElement->buildPendingResource();
+
+    clearHasPendingResourcesIfPossible(clientElement);
+  }
+}
+
 DEFINE_TRACE(SVGTreeScopeResources) {
   visitor->trace(m_pendingResources);
 }
diff --git a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
index 9529a4ad..c5a54a22 100644
--- a/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
+++ b/third_party/WebKit/Source/core/svg/SVGTreeScopeResources.h
@@ -41,6 +41,7 @@
   bool hasPendingResource(const AtomicString& id) const;
   bool isElementPendingResources(Element*) const;
   bool isElementPendingResource(Element*, const AtomicString& id) const;
+  void notifyResourceAvailable(const AtomicString& id);
   void clearHasPendingResourcesIfPossible(Element*);
   void removeElementFromPendingResources(Element*);
   SVGPendingElements* removePendingResource(const AtomicString& id);
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 8f29630..c06c6405 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -122,6 +122,7 @@
   "front_end/components/DOMBreakpointsSidebarPane.js",
   "front_end/components/DOMPresentationUtils.js",
   "front_end/components/domUtils.css",
+  "front_end/components/imagePreview.css",
   "front_end/components/Linkifier.js",
   "front_end/components/module.json",
   "front_end/components/Reload.js",
@@ -306,6 +307,7 @@
   "front_end/network/networkPanel.css",
   "front_end/network/NetworkPanel.js",
   "front_end/network/NetworkTimeCalculator.js",
+  "front_end/network/networkTimingTable.css",
   "front_end/network/NetworkWaterfallColumn.js",
   "front_end/network/requestCookiesView.css",
   "front_end/network/RequestCookiesView.js",
@@ -331,6 +333,7 @@
   "front_end/object_ui/CustomPreviewComponent.js",
   "front_end/object_ui/JavaScriptAutocomplete.js",
   "front_end/object_ui/module.json",
+  "front_end/object_ui/objectPopover.css",
   "front_end/object_ui/ObjectPopoverHelper.js",
   "front_end/object_ui/objectPropertiesSection.css",
   "front_end/object_ui/ObjectPropertiesSection.js",
@@ -490,6 +493,7 @@
   "front_end/source_frame/FontView.js",
   "front_end/source_frame/imageView.css",
   "front_end/source_frame/ImageView.js",
+  "front_end/source_frame/messagesPopover.css",
   "front_end/source_frame/module.json",
   "front_end/source_frame/ResourceSourceFrame.js",
   "front_end/source_frame/SourceCodeDiff.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Settings.js b/third_party/WebKit/Source/devtools/front_end/common/Settings.js
index 0c5f8d8..28a3087 100644
--- a/third_party/WebKit/Source/devtools/front_end/common/Settings.js
+++ b/third_party/WebKit/Source/devtools/front_end/common/Settings.js
@@ -731,6 +731,13 @@
     // This update is no-op.
   }
 
+  _updateVersionFrom23To24() {
+    var oldSetting = Common.settings.createSetting('searchInContentScripts', false);
+    var newSetting = Common.settings.createSetting('searchInAnonymousAndContentScripts', false);
+    newSetting.set(oldSetting.get());
+    oldSetting.remove();
+  }
+
   _migrateSettingsFromLocalStorage() {
     // This step migrates all the settings except for the ones below into the browser profile.
     var localSettings = new Set([
@@ -763,7 +770,7 @@
 };
 
 Common.VersionController._currentVersionName = 'inspectorVersion';
-Common.VersionController.currentVersion = 23;
+Common.VersionController.currentVersion = 24;
 
 /**
  * @type {!Common.Settings}
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 7eec38f..9e8c620 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
@@ -189,6 +189,7 @@
 
   function buildContent() {
     var container = createElement('table');
+    UI.appendStyle(container, 'components/imagePreview.css');
     container.className = 'image-preview-container';
     var naturalWidth = precomputedFeatures ? precomputedFeatures.naturalWidth : imageElement.naturalWidth;
     var naturalHeight = precomputedFeatures ? precomputedFeatures.naturalHeight : imageElement.naturalHeight;
diff --git a/third_party/WebKit/Source/devtools/front_end/components/imagePreview.css b/third_party/WebKit/Source/devtools/front_end/components/imagePreview.css
new file mode 100644
index 0000000..08020e5b
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/components/imagePreview.css
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+.image-preview-container {
+    background: transparent;
+    text-align: center;
+    border-spacing: 0;
+}
+
+.image-preview-container img {
+    margin: 2px auto;
+    max-width: 100px;
+    max-height: 100px;
+    background-image: url(Images/checker.png);
+    -webkit-user-select: text;
+    -webkit-user-drag: auto;
+}
+
+.image-container {
+    padding: 0;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/components/module.json b/third_party/WebKit/Source/devtools/front_end/components/module.json
index 4167aa2..8a494f5 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/components/module.json
@@ -25,6 +25,7 @@
     ],
     "resources": [
         "breakpointsList.css",
-        "domUtils.css"
+        "domUtils.css",
+        "imagePreview.css"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
index f7a6eb5e..7d6a78c 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
@@ -379,20 +379,6 @@
     cursor: text;
 }
 
-.image-preview-container {
-    background: transparent;
-    text-align: center;
-}
-
-.image-preview-container img {
-    margin: 2px auto;
-    max-width: 100px;
-    max-height: 100px;
-    background-image: url(Images/checker.png);
-    -webkit-user-select: text;
-    -webkit-user-drag: auto;
-}
-
 .metrics {
     border-bottom: 1px solid #ccc;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
index f7e137f..fd29015 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestTimingView.js
@@ -180,6 +180,7 @@
    */
   static createTimingTable(request, calculator) {
     var tableElement = createElementWithClass('table', 'network-timing-table');
+    UI.appendStyle(tableElement, 'network/networkTimingTable.css');
     var colgroup = tableElement.createChild('colgroup');
     colgroup.createChild('col', 'labels');
     colgroup.createChild('col', 'bars');
@@ -212,10 +213,10 @@
       if (rangeName === Network.RequestTimeRangeNames.Push) {
         createHeader(Common.UIString('Server Push'));
       } else if (rangeName === Network.RequestTimeRangeNames.Queueing) {
-          queueingHeader = tableElement.createChild('tr', 'network-timing-table-header');
-          queueingHeader.createChild('td').createTextChild(Common.UIString('Resource Scheduling'));
-          queueingHeader.createChild('td').createTextChild('');
-          queueingHeader.createChild('td').createTextChild(Common.UIString('TIME'));
+        queueingHeader = tableElement.createChild('tr', 'network-timing-table-header');
+        queueingHeader.createChild('td').createTextChild(Common.UIString('Resource Scheduling'));
+        queueingHeader.createChild('td').createTextChild('');
+        queueingHeader.createChild('td').createTextChild(Common.UIString('TIME'));
       } else if (Network.RequestTimingView.ConnectionSetupRangeNames.has(rangeName)) {
         if (!connectionHeader)
           connectionHeader = createHeader(Common.UIString('Connection Start'));
@@ -339,6 +340,7 @@
       this._tableElement.remove();
 
     this._tableElement = Network.RequestTimingView.createTimingTable(this._request, this._calculator);
+    this._tableElement.classList.add('resource-timing-table');
     this.element.appendChild(this._tableElement);
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/network/module.json b/third_party/WebKit/Source/devtools/front_end/network/module.json
index f58c2d8..9aa74b46 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/network/module.json
@@ -144,6 +144,7 @@
         "networkLogView.css",
         "networkManageCustomHeadersView.css",
         "networkPanel.css",
+        "networkTimingTable.css",
         "networkWaterfallColumn.css",
         "requestCookiesView.css",
         "requestHeadersTree.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css b/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css
index 03a4cbe1..80f149b 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/network/networkPanel.css
@@ -56,144 +56,8 @@
     color: rgb(30%, 30%, 30%);
 }
 
-/* Network timing is shared between popover and network item view pane */
-
-.network-timing-table {
-    width: 380px;
-    border-spacing: 0;
-    padding-left: 10px;
-    padding-right: 10px;
-    line-height: initial;
-}
-
-.network-timing-start {
-    border-top: 5px solid transparent;
-}
-.network-timing-table-header td, .network-timing-footer td {
-    border-top: 10px solid transparent;
-}
-
-.network-timing-table-header td {
-    color: #bbb;
-}
-
-.network-timing-table-header td:last-child {
-    text-align: right;
-}
-
-.network-timing-table col.labels {
-    width: 156px;
-}
-
-.network-timing-table col.duration {
-    width: 80px;
-}
-
-.network-timing-table td {
-    padding: 2px 0;
-}
-
-.network-timing-table td.caution {
-    font-weight: bold;
-    color: rgb(255, 128, 0);
-    padding: 2px 0;
-}
-
-.network-timing-table hr.break {
-    border: 0;
-    height: 1px;
-    background-image: linear-gradient(to right, #eee, #bbb, #eee);
-}
-
-.network-timing-footer td:last-child {
-    font-weight: bold;
-    text-align: right;
-}
-
-.network-timing-row {
-    position: relative;
-    height: 15px;
-}
-
-.network-timing-bar {
-    position: absolute;
-    min-width: 1px;
-    top: 0;
-    bottom: 0;
-}
-
-.network-timing-bar-title {
-    color: #222;
-    white-space: nowrap;
-    text-align: right;
-}
-
-.network-timing-bar.queueing,
-.network-timing-bar.total {
-    border: 1px solid rgba(0, 0, 0, 0.1);
-}
-
-.network-timing-bar.blocking, -theme-preserve {
-    background-color: #AAAAAA;
-}
-
-.network-timing-bar.proxy, -theme-preserve {
-    background-color: #A1887F;
-}
-
-.network-timing-bar.dns, -theme-preserve {
-    background-color: #009688;
-}
-
-.network-timing-bar.connecting,
-.network-timing-bar.serviceworker,
-.network-timing-bar.serviceworker-preparation, -theme-preserve {
-    background-color: #FF9800;
-}
-
-.network-timing-bar.ssl, -theme-preserve {
-    background-color: #9C27B0;
-}
-
-.network-timing-bar.sending, -theme-preserve {
-    background-color: #B0BEC5;
-}
-
-.network-timing-bar.waiting, -theme-preserve {
-    background-color: #00C853;
-}
-
-.network-timing-bar.receiving, -theme-preserve,
-.network-timing-bar.receiving-push, -theme-preserve {
-    background-color: #03A9F4;
-}
-
-.network-timing-bar.push, -theme-preserve {
-    background-color: #8CDBff;
-}
-
-.network-timing-bar.server-timing, -theme-preserve {
-    background-color: #ddd;
-}
-
-.network-timing-table td.network-timing-metric {
-    white-space: nowrap;
-    max-width: 150px;
-    overflow-x: hidden;
-    text-overflow: ellipsis;
-}
-
-.network-timing-bar.proxy,
-.network-timing-bar.dns,
-.network-timing-bar.ssl,
-.network-timing-bar.connecting,
-.network-timing-bar.blocking {
-    height: 10px;
-    margin: auto;
-}
-
-.resource-timing-view .network-timing-table {
-    width: 100%;
+.resource-timing-table {
+    width: 100% !important;
 }
 
 #network-overview-panel {
diff --git a/third_party/WebKit/Source/devtools/front_end/network/networkTimingTable.css b/third_party/WebKit/Source/devtools/front_end/network/networkTimingTable.css
new file mode 100644
index 0000000..a0a4c22
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/network/networkTimingTable.css
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+.network-timing-table {
+    width: 380px;
+    border-spacing: 0;
+    padding-left: 10px;
+    padding-right: 10px;
+    line-height: initial;
+}
+
+.network-timing-start {
+    border-top: 5px solid transparent;
+}
+.network-timing-table-header td, .network-timing-footer td {
+    border-top: 10px solid transparent;
+}
+
+.network-timing-table-header td {
+    color: #bbb;
+}
+
+.network-timing-table-header td:last-child {
+    text-align: right;
+}
+
+.network-timing-table col.labels {
+    width: 156px;
+}
+
+.network-timing-table col.duration {
+    width: 80px;
+}
+
+.network-timing-table td {
+    padding: 2px 0;
+}
+
+.network-timing-table td.caution {
+    font-weight: bold;
+    color: rgb(255, 128, 0);
+    padding: 2px 0;
+}
+
+.network-timing-table hr.break {
+    border: 0;
+    height: 1px;
+    background-image: linear-gradient(to right, #eee, #bbb, #eee);
+}
+
+.network-timing-footer td:last-child {
+    font-weight: bold;
+    text-align: right;
+}
+
+.network-timing-row {
+    position: relative;
+    height: 15px;
+}
+
+.network-timing-bar {
+    position: absolute;
+    min-width: 1px;
+    top: 0;
+    bottom: 0;
+}
+
+.network-timing-bar-title {
+    color: #222;
+    white-space: nowrap;
+    text-align: right;
+}
+
+.network-timing-bar.queueing,
+.network-timing-bar.total {
+    border: 1px solid rgba(0, 0, 0, 0.1);
+}
+
+.network-timing-bar.blocking, -theme-preserve {
+    background-color: #AAAAAA;
+}
+
+.network-timing-bar.proxy, -theme-preserve {
+    background-color: #A1887F;
+}
+
+.network-timing-bar.dns, -theme-preserve {
+    background-color: #009688;
+}
+
+.network-timing-bar.connecting,
+.network-timing-bar.serviceworker,
+.network-timing-bar.serviceworker-preparation, -theme-preserve {
+    background-color: #FF9800;
+}
+
+.network-timing-bar.ssl, -theme-preserve {
+    background-color: #9C27B0;
+}
+
+.network-timing-bar.sending, -theme-preserve {
+    background-color: #B0BEC5;
+}
+
+.network-timing-bar.waiting, -theme-preserve {
+    background-color: #00C853;
+}
+
+.network-timing-bar.receiving, -theme-preserve,
+.network-timing-bar.receiving-push, -theme-preserve {
+    background-color: #03A9F4;
+}
+
+.network-timing-bar.push, -theme-preserve {
+    background-color: #8CDBff;
+}
+
+.network-timing-bar.server-timing, -theme-preserve {
+    background-color: #ddd;
+}
+
+.network-timing-table td.network-timing-metric {
+    white-space: nowrap;
+    max-width: 150px;
+    overflow-x: hidden;
+    text-overflow: ellipsis;
+}
+
+.network-timing-bar.proxy,
+.network-timing-bar.dns,
+.network-timing-bar.ssl,
+.network-timing-bar.connecting,
+.network-timing-bar.blocking {
+    height: 10px;
+    margin: auto;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/object_ui/ObjectPopoverHelper.js b/third_party/WebKit/Source/devtools/front_end/object_ui/ObjectPopoverHelper.js
index 29773797..7617975 100644
--- a/third_party/WebKit/Source/devtools/front_end/object_ui/ObjectPopoverHelper.js
+++ b/third_party/WebKit/Source/devtools/front_end/object_ui/ObjectPopoverHelper.js
@@ -128,6 +128,7 @@
       if (result.type !== 'object') {
         popoverContentElement = createElement('span');
         UI.appendStyle(popoverContentElement, 'object_ui/objectValue.css');
+        UI.appendStyle(popoverContentElement, 'object_ui/objectPopover.css');
         var valueElement = popoverContentElement.createChild('span', 'monospace object-value-' + result.type);
         valueElement.style.whiteSpace = 'pre';
 
@@ -155,10 +156,11 @@
           popoverContentElement = customPreviewComponent.element;
         } else {
           popoverContentElement = createElement('div');
+          UI.appendStyle(popoverContentElement, 'object_ui/objectPopover.css');
           this._titleElement = popoverContentElement.createChild('div', 'monospace');
-          this._titleElement.createChild('span', 'source-frame-popover-title').textContent = description;
+          this._titleElement.createChild('span', 'object-popover-title').textContent = description;
           var section = new ObjectUI.ObjectPropertiesSection(result, '', this._lazyLinkifier());
-          section.element.classList.add('source-frame-popover-tree');
+          section.element.classList.add('object-popover-tree');
           section.titleLessMode();
           popoverContentElement.appendChild(section.element);
         }
diff --git a/third_party/WebKit/Source/devtools/front_end/object_ui/module.json b/third_party/WebKit/Source/devtools/front_end/object_ui/module.json
index e8c50c1d..b47310c 100644
--- a/third_party/WebKit/Source/devtools/front_end/object_ui/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/object_ui/module.json
@@ -13,8 +13,8 @@
     ],
     "resources": [
         "customPreviewComponent.css",
-        "objectValue.css",
-        "objectValue.css",
-        "objectPropertiesSection.css"
+        "objectPopover.css",
+        "objectPropertiesSection.css",
+        "objectValue.css"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/object_ui/objectPopover.css b/third_party/WebKit/Source/devtools/front_end/object_ui/objectPopover.css
new file mode 100644
index 0000000..37f4c0e
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/object_ui/objectPopover.css
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+.object-popover-title {
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+    font-weight: bold;
+    padding-left: 18px;
+}
+
+.object-popover-tree {
+    border-top: 1px solid rgb(184, 184, 184);
+    overflow: auto;
+    position: absolute;
+    top: 21px;
+    bottom: 5px;
+    left: 5px;
+    right: 5px;
+    margin-top: 1px;
+}
+
+.object-popover-container {
+    display: inline-block;
+}
+
+.function-popover-title {
+    border-bottom: 1px solid #AAA;
+    margin-bottom: 3px;
+    padding-bottom: 2px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.function-popover-title .function-name {
+    font-weight: bold;
+}
+
+.function-title-link-container {
+    display: flex;
+    align-items: center;
+    position: relative;
+    margin-left: 10px;
+}
+
+.function-location-step-into {
+    position: relative;
+    height: 14px;
+    transform: rotate(-90deg);
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
index 8580781..b9aa382 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -260,8 +260,6 @@
   willHide() {
     this._currentSearchResultIndex = -1;
     this._popoverHelper.hidePopover();
-    if (this.helpPopover && this.helpPopover.isShowing())
-      this.helpPopover.hide();
   }
 
   /**
@@ -2000,7 +1998,7 @@
 Profiler.HeapSnapshotStatisticsView = class extends UI.VBox {
   constructor() {
     super();
-    this.setMinimumSize(50, 25);
+    this.element.classList.add('heap-snapshot-statistics-view');
     this._pieChart = new PerfUI.PieChart(150, Profiler.HeapSnapshotStatisticsView._valueFormatter, true);
     this._pieChart.element.classList.add('heap-snapshot-stats-pie-chart');
     this.element.appendChild(this._pieChart.element);
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/heapProfiler.css b/third_party/WebKit/Source/devtools/front_end/profiler/heapProfiler.css
index 2280acf..b60620d 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/heapProfiler.css
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/heapProfiler.css
@@ -138,12 +138,18 @@
     bottom: 0;
 }
 
+.heap-snapshot-statistics-view {
+    overflow: auto;
+}
+
 .heap-snapshot-stats-pie-chart {
     margin: 12px 30px;
+    flex-shrink: 0;
 }
 
 .heap-snapshot-stats-legend {
     margin-left: 24px;
+    flex-shrink: 0;
 }
 
 .heap-snapshot-stats-legend > div {
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js b/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
index 1046c64..c9f57c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
@@ -494,9 +494,10 @@
     this.element = createElementWithClass('div', 'text-editor-row-message');
     this._icon = this.element.createChild('label', '', 'dt-icon-label');
     this._icon.type = SourceFrame.UISourceCodeFrame._iconClassPerLevel[message.level()];
-    this._repeatCountElement = this.element.createChild('label', 'message-repeat-count hidden', 'dt-small-bubble');
+    this._repeatCountElement =
+        this.element.createChild('label', 'text-editor-row-message-repeat-count hidden', 'dt-small-bubble');
     this._repeatCountElement.type = SourceFrame.UISourceCodeFrame._bubbleTypePerLevel[message.level()];
-    var linesContainer = this.element.createChild('div', 'text-editor-row-message-lines');
+    var linesContainer = this.element.createChild('div');
     var lines = this._message.text().split('\n');
     for (var i = 0; i < lines.length; ++i) {
       var messageLine = linesContainer.createChild('div');
@@ -579,6 +580,7 @@
    */
   messagesDescription() {
     this._messagesDescriptionElement.removeChildren();
+    UI.appendStyle(this._messagesDescriptionElement, 'source_frame/messagesPopover.css');
     for (var i = 0; i < this._messages.length; ++i)
       this._messagesDescriptionElement.appendChild(this._messages[i].element);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/messagesPopover.css b/third_party/WebKit/Source/devtools/front_end/source_frame/messagesPopover.css
new file mode 100644
index 0000000..f083c46
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/messagesPopover.css
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+.text-editor-messages-description-container {
+    display: inline-block;
+}
+
+.text-editor-row-message:first-child {
+    border-top-width: 0;
+}
+
+.text-editor-row-message {
+    line-height: 1.2;
+    white-space: nowrap;
+    display: flex;
+    align-items: center;
+    justify-content: flex-start;
+    margin-top: 2px;
+}
+
+.text-editor-row-message-repeat-count {
+    margin-right: 0.5em;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/module.json b/third_party/WebKit/Source/devtools/front_end/source_frame/module.json
index ca4f0e5..9d5e607a 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/module.json
@@ -49,6 +49,7 @@
     ],
     "resources": [
         "fontView.css",
-        "imageView.css"
+        "imageView.css",
+        "messagesPopover.css"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
index bfc38df..513ca1c 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
@@ -154,7 +154,7 @@
     if (!searchResult.searchMatches.length)
       return;
     if (!this._searchResultsPane)
-      this._searchResultsPane = this._searchScope.createSearchResultsPane(this._searchConfig);
+      this._searchResultsPane = new Sources.FileBasedSearchResultsPane(this._searchConfig);
     this._resetResults();
     this._searchResultsElement.appendChild(this._searchResultsPane.element);
     this._searchResultsPane.addSearchResult(searchResult);
@@ -435,11 +435,5 @@
    */
   performIndexing(progress) {},
 
-  stopSearch() {},
-
-  /**
-   * @param {!Workspace.ProjectSearchConfig} searchConfig
-   * @return {!Sources.SearchResultsPane}
-   */
-  createSearchResultsPane(searchConfig) {}
+  stopSearch() {}
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index 0a517f82..fc433ab 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -317,10 +317,6 @@
   _projectRemoved(event) {
     var project = /** @type {!Workspace.Project} */ (event.data);
 
-    var frame = Bindings.NetworkProject.frameForProject(project);
-    if (frame)
-      this._discardFrame(frame);
-
     var uiSourceCodes = project.uiSourceCodes();
     for (var i = 0; i < uiSourceCodes.length; ++i)
       this._removeUISourceCode(uiSourceCodes[i]);
@@ -548,8 +544,10 @@
           break;
         if (!(node instanceof Sources.NavigatorGroupTreeNode || node instanceof Sources.NavigatorFolderTreeNode))
           break;
-        if (node._type === Sources.NavigatorView.Types.Frame)
+        if (node._type === Sources.NavigatorView.Types.Frame) {
+          this._discardFrame(/** @type {!SDK.ResourceTreeFrame} */ (frame));
           break;
+        }
 
         var folderId = this._folderNodeId(project, target, frame, uiSourceCode.origin(), node._folderPath);
         this._subfolderNodes.delete(folderId);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
index 641d357..42ea08e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesSearchScope.js
@@ -74,24 +74,17 @@
    * @return {!Array.<!Workspace.Project>}
    */
   _projects() {
-    /**
-     * @param {!Workspace.Project} project
-     * @return {boolean}
-     */
-    function filterOutServiceProjects(project) {
-      return project.type() !== Workspace.projectTypes.Service;
-    }
+    var searchInAnonymousAndContentScripts = Common.moduleSetting('searchInAnonymousAndContentScripts').get();
 
-    /**
-     * @param {!Workspace.Project} project
-     * @return {boolean}
-     */
-    function filterOutContentScriptsIfNeeded(project) {
-      return Common.moduleSetting('searchInContentScripts').get() ||
-          project.type() !== Workspace.projectTypes.ContentScripts;
-    }
-
-    return Workspace.workspace.projects().filter(filterOutServiceProjects).filter(filterOutContentScriptsIfNeeded);
+    return Workspace.workspace.projects().filter(project => {
+      if (project.type() === Workspace.projectTypes.Service)
+        return false;
+      if (!searchInAnonymousAndContentScripts && project.isServiceProject())
+        return false;
+      if (!searchInAnonymousAndContentScripts && project.type() === Workspace.projectTypes.ContentScripts)
+        return false;
+      return true;
+    });
   }
 
   /**
@@ -283,13 +276,4 @@
   stopSearch() {
     ++this._searchId;
   }
-
-  /**
-   * @override
-   * @param {!Workspace.ProjectSearchConfig} searchConfig
-   * @return {!Sources.FileBasedSearchResultsPane}
-   */
-  createSearchResultsPane(searchConfig) {
-    return new Sources.FileBasedSearchResultsPane(searchConfig);
-  }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/module.json b/third_party/WebKit/Source/devtools/front_end/sources/module.json
index 64fc1ab..134d954ac 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sources/module.json
@@ -375,8 +375,8 @@
         {
             "type": "setting",
             "category": "Sources",
-            "title": "Search in content scripts",
-            "settingName": "searchInContentScripts",
+            "title": "Search in anonymous and content scripts",
+            "settingName": "searchInAnonymousAndContentScripts",
             "settingType": "boolean",
             "defaultValue": false
         },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
index e22f46b..17fd3c63 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesPanel.css
@@ -55,41 +55,6 @@
     height: 28px;
 }
 
-.function-location-link {
-    float: right;
-    margin-left: 10px;
-}
-
-.function-location-step-into {
-    position: relative;
-    height: 14px;
-    transform: rotate(-90deg);
-}
-
-.object-popover-container {
-    display: inline-block;
-}
-
-.function-popover-title {
-    border-bottom: 1px solid #AAA;
-    margin-bottom: 3px;
-    padding-bottom: 2px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-}
-
-.function-title-link-container {
-    display: flex;
-    align-items: center;
-    position: relative;
-    margin-left: 10px;
-}
-
-.function-popover-title .function-name {
-    font-weight: bold;
-}
-
 .panel.sources .sidebar-pane-stack {
     overflow: auto;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
index 6d76f00..73c39ff 100644
--- a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
+++ b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
@@ -368,27 +368,6 @@
     opacity: 0.5;
 }
 
-.text-editor-messages-description-container {
-    display: inline-block;
-}
-
-.text-editor-row-message:first-child {
-    border-top-width: 0;
-}
-
-.text-editor-row-message {
-    border-top: 1px solid rgb(215, 215, 215);
-    line-height: 1.2;
-    white-space: nowrap;
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-}
-
-.text-editor-row-message .message-repeat-count {
-    margin-right: 0.5em;
-}
-
 .CodeMirror .text-editor-line-decoration-icon {
     position: absolute;
     cursor: pointer;
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 ee40700..c257246 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -1403,6 +1403,7 @@
         return;
       }
       var container = createElement('div');
+      UI.appendStyle(container, 'components/imagePreview.css');
       container.classList.add('image-preview-container', 'vbox', 'link');
       var img = container.createChild('img');
       img.src = imageURL;
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 5def207..8fbe22a 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/timelinePanel.css
@@ -284,25 +284,6 @@
     line-height: 18px;
 }
 
-.image-preview-container {
-    background: transparent;
-    text-align: left;
-    border-spacing: 0;
-    margin: 4px;
-}
-
-.image-preview-container img {
-    max-width: 100px;
-    max-height: 100px;
-    background-image: url(Images/checker.png);
-    -webkit-user-select: text;
-    -webkit-user-drag: auto;
-}
-
-.image-container {
-    padding: 0;
-}
-
 .timeline-filters-header {
     overflow: hidden;
     flex: none;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
index 05663d9b..b960a62 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineModel.js
@@ -122,15 +122,23 @@
 
   /**
    * @param {!SDK.TracingModel.Event} event
+   * @param {string} field
+   * @return {string}
+   */
+  static globalEventId(event, field) {
+    var data = event.args['data'] || event.args['beginData'];
+    var id = data && data[field];
+    if (!id)
+      return '';
+    return `${event.thread.process().id()}.${id}`;
+  }
+
+  /**
+   * @param {!SDK.TracingModel.Event} event
    * @return {string}
    */
   static eventFrameId(event) {
-    var data = event.args['data'] || event.args['beginData'];
-    var frame = data && data['frame'];
-    if (!frame)
-      return '';
-    var processId = event.thread.process().id();
-    return `${processId}.${frame}`;
+    return TimelineModel.TimelineModel.globalEventId(event, 'frame');
   }
 
   /**
@@ -1008,7 +1016,7 @@
       var e = events[i];
       if (!resourceTypes.has(e.name))
         continue;
-      var id = e.args['data']['requestId'];
+      var id = TimelineModel.TimelineModel.globalEventId(e, 'requestId');
       var request = requests.get(id);
       if (request) {
         request.addEvent(e);
@@ -1709,15 +1717,20 @@
     var initiatorInfo = TimelineModel.TimelineAsyncEventTracker._asyncEvents.get(initiatorType);
     if (!initiatorInfo)
       return;
-    var id = event.args['data'][initiatorInfo.joinBy];
+    var id = TimelineModel.TimelineModel.globalEventId(event, initiatorInfo.joinBy);
     if (!id)
       return;
     /** @type {!Map<string, !SDK.TracingModel.Event>|undefined} */
     var initiatorMap = this._initiatorByType.get(initiatorType);
-    if (isInitiator)
+    if (isInitiator) {
       initiatorMap.set(id, event);
-    else
-      TimelineModel.TimelineData.forEvent(event).setInitiator(initiatorMap.get(id) || null);
+      return;
+    }
+    var initiator = initiatorMap.get(id) || null;
+    var timelineData = TimelineModel.TimelineData.forEvent(event);
+    timelineData.setInitiator(initiator);
+    if (!timelineData.frameId && initiator)
+      timelineData.frameId = TimelineModel.TimelineModel.eventFrameId(initiator);
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/popover.css b/third_party/WebKit/Source/devtools/front_end/ui/popover.css
index 82c82046..b060c7a 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/popover.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/popover.css
@@ -67,22 +67,3 @@
     margin-bottom: -19px;
     background-position: 0 -19px;
 }
-
-.source-frame-popover-title {
-    text-overflow: ellipsis;
-    overflow: hidden;
-    white-space: nowrap;
-    font-weight: bold;
-    padding-left: 18px;
-}
-
-.source-frame-popover-tree {
-    border-top: 1px solid rgb(184, 184, 184);
-    overflow: auto;
-    position: absolute;
-    top: 21px;
-    bottom: 5px;
-    left: 5px;
-    right: 5px;
-    margin-top: 1px;
-}
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
index 919bc97..5ee91880 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2D.h
@@ -192,7 +192,7 @@
 
   void resetUsageTracking();
 
-  void incrementFrameCount() { m_usageCounters.numFramesSinceReset++; }
+  void finalizeFrame() override { m_usageCounters.numFramesSinceReset++; }
 
   bool isPaintable() const final { return hasImageBuffer(); }
 
diff --git a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
index f4abf45..ea8e2a2 100644
--- a/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
+++ b/third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DUsageTrackingTest.cpp
@@ -637,11 +637,11 @@
   createContext(NonOpaque);
   EXPECT_EQ(0, context2d()->getUsage().numFramesSinceReset);
 
-  context2d()->incrementFrameCount();
+  context2d()->finalizeFrame();
   EXPECT_EQ(1, context2d()->getUsage().numFramesSinceReset);
 
-  context2d()->incrementFrameCount();
-  context2d()->incrementFrameCount();
+  context2d()->finalizeFrame();
+  context2d()->finalizeFrame();
   EXPECT_EQ(3, context2d()->getUsage().numFramesSinceReset);
 }
 
@@ -649,8 +649,8 @@
   createContext(NonOpaque);
   EXPECT_EQ(0, context2d()->getUsage().numFramesSinceReset);
 
-  context2d()->incrementFrameCount();
-  context2d()->incrementFrameCount();
+  context2d()->finalizeFrame();
+  context2d()->finalizeFrame();
   EXPECT_EQ(2, context2d()->getUsage().numFramesSinceReset);
 
   const int numReps = 100;
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationReceiver.cpp b/third_party/WebKit/Source/modules/presentation/PresentationReceiver.cpp
index bbefd94..14aea21 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationReceiver.cpp
+++ b/third_party/WebKit/Source/modules/presentation/PresentationReceiver.cpp
@@ -49,14 +49,15 @@
 
   // receiver.connectionList property not accessed
   if (!m_connectionListProperty)
-    return nullptr;
+    return connection;
 
   if (m_connectionListProperty->getState() ==
-      ScriptPromisePropertyBase::Pending)
+      ScriptPromisePropertyBase::Pending) {
     m_connectionListProperty->resolve(m_connectionList);
-  else if (m_connectionListProperty->getState() ==
-           ScriptPromisePropertyBase::Resolved)
+  } else if (m_connectionListProperty->getState() ==
+             ScriptPromisePropertyBase::Resolved) {
     m_connectionList->dispatchConnectionAvailableEvent(connection);
+  }
 
   return connection;
 }
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
index a57a899b..94ef5791 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
+++ b/third_party/WebKit/Source/modules/presentation/PresentationReceiverTest.cpp
@@ -202,9 +202,12 @@
   WebPresentationSessionInfo sessionInfo(KURL(KURL(), "http://example.com"),
                                          "id");
   // Receive first connection.
-  receiver->onReceiverConnectionAvailable(sessionInfo);
+  auto* connection1 = receiver->onReceiverConnectionAvailable(sessionInfo);
+  EXPECT_TRUE(connection1);
+
   // Receive second connection.
-  receiver->onReceiverConnectionAvailable(sessionInfo);
+  auto* connection2 = receiver->onReceiverConnectionAvailable(sessionInfo);
+  EXPECT_TRUE(connection2);
 
   receiver->connectionList(scope.getScriptState());
   verifyConnectionListPropertyState(ScriptPromisePropertyBase::Resolved,
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 6158955..449c7e9 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1204,6 +1204,7 @@
   ASSERT(drawingBuffer());
 
   m_markedCanvasDirty = false;
+  m_animationFrameInProgress = false;
   m_activeTextureUnit = 0;
   m_packAlignment = 4;
   m_unpackAlignment = 4;
@@ -1419,17 +1420,23 @@
   if (!canvas())
     return;
 
-  LayoutBox* layoutBox = canvas()->layoutBox();
-  if (layoutBox && layoutBox->hasAcceleratedCompositing()) {
-    layoutBox->contentChanged(changeType);
-  }
-  if (!m_markedCanvasDirty) {
-    m_markedCanvasDirty = true;
+  m_markedCanvasDirty = true;
+
+  if (!m_animationFrameInProgress) {
+    m_animationFrameInProgress = true;
+    LayoutBox* layoutBox = canvas()->layoutBox();
+    if (layoutBox && layoutBox->hasAcceleratedCompositing()) {
+      layoutBox->contentChanged(changeType);
+    }
     IntSize canvasSize = clampedCanvasSize();
     didDraw(SkIRect::MakeXYWH(0, 0, canvasSize.width(), canvasSize.height()));
   }
 }
 
+void WebGLRenderingContextBase::finalizeFrame() {
+  m_animationFrameInProgress = false;
+}
+
 void WebGLRenderingContextBase::onErrorMessage(const char* message,
                                                int32_t id) {
   if (m_synthesizedErrorsToConsole)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 4853119..fbde1a8 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -625,6 +625,7 @@
   bool paintRenderingResultsToCanvas(SourceDrawingBuffer) override;
   WebLayer* platformLayer() const override;
   void stop() override;
+  void finalizeFrame() override;
 
   // DrawingBuffer::Client implementation.
   bool DrawingBufferClientIsBoundForDraw() override;
@@ -687,6 +688,7 @@
   TaskRunnerTimer<WebGLRenderingContextBase> m_restoreTimer;
 
   bool m_markedCanvasDirty;
+  bool m_animationFrameInProgress;
 
   // List of bound VBO's. Used to maintain info about sizes for ARRAY_BUFFER and
   // stored values for ELEMENT_ARRAY_BUFFER
diff --git a/third_party/WebKit/Source/modules/webusb/NavigatorUSB.idl b/third_party/WebKit/Source/modules/webusb/NavigatorUSB.idl
index 581358f..e9a8522 100644
--- a/third_party/WebKit/Source/modules/webusb/NavigatorUSB.idl
+++ b/third_party/WebKit/Source/modules/webusb/NavigatorUSB.idl
@@ -4,6 +4,9 @@
 
 // https://wicg.github.io/webusb/#enumeration
 
+// The [SecureContext] and [OriginTrialEnabled] extended attributes don't mix.
+// Once this is out of origin trial and the secure context logic is removed from
+// ConditionalFeaturesForModules.cpp add [SecureContext] here.
 partial interface Navigator {
     [OriginTrialEnabled=WebUSB] readonly attribute USB usb;
 };
diff --git a/third_party/WebKit/Source/modules/webusb/USB.cpp b/third_party/WebKit/Source/modules/webusb/USB.cpp
index 847a4aa..3100af6f8 100644
--- a/third_party/WebKit/Source/modules/webusb/USB.cpp
+++ b/third_party/WebKit/Source/modules/webusb/USB.cpp
@@ -80,16 +80,11 @@
   if (!m_deviceManager) {
     resolver->reject(DOMException::create(NotSupportedError));
   } else {
-    String errorMessage;
-    if (!scriptState->getExecutionContext()->isSecureContext(errorMessage)) {
-      resolver->reject(DOMException::create(SecurityError, errorMessage));
-    } else {
-      m_deviceManagerRequests.insert(resolver);
-      m_deviceManager->GetDevices(
-          nullptr, convertToBaseCallback(WTF::bind(&USB::onGetDevices,
-                                                   wrapPersistent(this),
-                                                   wrapPersistent(resolver))));
-    }
+    m_deviceManagerRequests.insert(resolver);
+    m_deviceManager->GetDevices(
+        nullptr, convertToBaseCallback(WTF::bind(&USB::onGetDevices,
+                                                 wrapPersistent(this),
+                                                 wrapPersistent(resolver))));
   }
   return promise;
 }
@@ -116,10 +111,7 @@
                                         wrapWeakPersistent(this))));
   }
 
-  String errorMessage;
-  if (!executionContext->isSecureContext(errorMessage)) {
-    resolver->reject(DOMException::create(SecurityError, errorMessage));
-  } else if (!UserGestureIndicator::consumeUserGesture()) {
+  if (!UserGestureIndicator::consumeUserGesture()) {
     resolver->reject(DOMException::create(
         SecurityError,
         "Must be handling a user gesture to show a permission request."));
diff --git a/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp b/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
index d3ba4637..33b0169 100644
--- a/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
+++ b/third_party/WebKit/Source/platform/network/mime/MIMETypeRegistry.cpp
@@ -140,7 +140,7 @@
     const String& codecs) {
   const std::string asciiMimeType = ToLowerASCIIOrEmpty(mimeType);
   std::vector<std::string> codecVector;
-  media::ParseCodecString(ToASCIIOrEmpty(codecs), &codecVector, false);
+  media::SplitCodecsToVector(ToASCIIOrEmpty(codecs), &codecVector, false);
   return static_cast<SupportsType>(
       media::IsSupportedMediaFormat(asciiMimeType, codecVector));
 }
@@ -151,7 +151,7 @@
   if (asciiMimeType.empty())
     return false;
   std::vector<std::string> parsedCodecIds;
-  media::ParseCodecString(ToASCIIOrEmpty(codecs), &parsedCodecIds, false);
+  media::SplitCodecsToVector(ToASCIIOrEmpty(codecs), &parsedCodecIds, false);
   return static_cast<MIMETypeRegistry::SupportsType>(
       media::StreamParserFactory::IsTypeSupported(asciiMimeType,
                                                   parsedCodecIds));
diff --git a/third_party/WebKit/Source/platform/scheduler/child/OWNERS b/third_party/WebKit/Source/platform/scheduler/child/OWNERS
index 6dc4cb4..9bf4416 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/OWNERS
+++ b/third_party/WebKit/Source/platform/scheduler/child/OWNERS
@@ -1,3 +1,6 @@
 alexclarke@chromium.org
 rmcilroy@chromium.org
 skyostil@chromium.org
+
+# TEAM: scheduler-dev@chromium.org
+# COMPONENT: Blink>Scheduling
diff --git a/third_party/WebKit/Source/web/WebFrameSerializer.cpp b/third_party/WebKit/Source/web/WebFrameSerializer.cpp
index 4434b29..6d2110f4 100644
--- a/third_party/WebKit/Source/web/WebFrameSerializer.cpp
+++ b/third_party/WebKit/Source/web/WebFrameSerializer.cpp
@@ -131,7 +131,7 @@
     return false;
   if (isHTMLHeadElement(element) || isHTMLMetaElement(element) ||
       isHTMLStyleElement(element) || isHTMLDataListElement(element) ||
-      isHTMLOptionElement(element)) {
+      isHTMLOptionElement(element) || isHTMLLinkElement(element)) {
     return false;
   }
   Element* parent = element.parentElement();
diff --git a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
index 8528b8b..8e6a9c3 100644
--- a/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
+++ b/third_party/WebKit/Source/web/tests/NGInlineLayoutTest.cpp
@@ -48,9 +48,9 @@
   NGConstraintSpace* constraintSpace = constraintSpaceForElement(blockFlow);
   NGBlockNode* node = new NGBlockNode(blockFlow);
 
-  RefPtr<NGPhysicalFragment> fragment =
+  RefPtr<NGLayoutResult> result =
       NGBlockLayoutAlgorithm(node, constraintSpace).Layout();
-  EXPECT_TRUE(fragment);
+  EXPECT_TRUE(result);
 
   String expectedText("Hello World!");
   EXPECT_EQ(expectedText, toNGInlineNode(node->FirstChild())->Text(0, 12));
@@ -72,9 +72,9 @@
   NGConstraintSpace* constraintSpace = constraintSpaceForElement(blockFlow);
   NGBlockNode* node = new NGBlockNode(blockFlow);
 
-  RefPtr<NGPhysicalFragment> fragment =
+  RefPtr<NGLayoutResult> result =
       NGBlockLayoutAlgorithm(node, constraintSpace).Layout();
-  EXPECT_TRUE(fragment);
+  EXPECT_TRUE(result);
 
   String expectedText("Hello ");
   expectedText.append(objectReplacementCharacter);
diff --git a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
index 9459bfc..84b9eff 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameSerializerTest.cpp
@@ -283,13 +283,14 @@
   EXPECT_NE(WTF::kNotFound, mhtml.find("<head"));
   EXPECT_NE(WTF::kNotFound, mhtml.find("<style"));
   EXPECT_NE(WTF::kNotFound, mhtml.find("<title"));
-  EXPECT_NE(WTF::kNotFound, mhtml.find("<link"));
   EXPECT_NE(WTF::kNotFound, mhtml.find("<datalist"));
   EXPECT_NE(WTF::kNotFound, mhtml.find("<option"));
   // One for meta in head and another for meta in body.
   EXPECT_EQ(2, matchSubstring(mhtml, "<meta", 5));
   // One for style in head and another for style in body.
   EXPECT_EQ(2, matchSubstring(mhtml, "<style", 6));
+  // One for link in head and another for link in body.
+  EXPECT_EQ(2, matchSubstring(mhtml, "<link", 5));
 
   // These hidden elements that affect layout should remain intact.
   EXPECT_NE(WTF::kNotFound, mhtml.find("<h2"));
diff --git a/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html b/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
index 465fc7a..a12892aec 100644
--- a/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
+++ b/third_party/WebKit/Source/web/tests/data/frameserialization/hidden_elements.html
@@ -27,5 +27,6 @@
   </style>
   <meta itemprop="name" content="value">
 </div>
+<link rel="next2" href="next2.html">
 </body>
 </html>
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
index f31ab9b..6ea84b6d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
@@ -27,10 +27,10 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 import cStringIO as StringIO
-import diff_parser
 import re
 import unittest
 
+from webkitpy.common.checkout import diff_parser
 from webkitpy.common.checkout.diff_test_data import DIFF_TEST_DATA
 
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/find_files_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/find_files_unittest.py
index a904b4d..15e1f4e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/find_files_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/find_files_unittest.py
@@ -29,8 +29,8 @@
 import sys
 import unittest
 
+from webkitpy.common import find_files
 from webkitpy.common.system.filesystem import FileSystem
-import find_files
 
 
 class MockWinFileSystem(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checker.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checker.py
index 212b0a8..f305755 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checker.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checker.py
@@ -35,21 +35,21 @@
 import re
 import sys
 
-from checkers.common import categories as CommonCategories
-from checkers.common import CarriageReturnChecker
-from checkers.cpp import CppChecker
-from checkers.jsonchecker import JSONChecker
-from checkers.png import PNGChecker
-from checkers.python import PythonChecker
-from checkers.test_expectations import TestExpectationsChecker
-from checkers.text import TextChecker
-from checkers.xcodeproj import XcodeProjectFileChecker
-from checkers.xml import XMLChecker
-from error_handlers import DefaultStyleErrorHandler
-from filter import FilterConfiguration
-from optparser import ArgumentParser
-from optparser import DefaultCommandOptionValues
 from webkitpy.common.system.log_utils import configure_logging as _configure_logging
+from webkitpy.style.checkers.common import CarriageReturnChecker
+from webkitpy.style.checkers.common import categories as CommonCategories
+from webkitpy.style.checkers.cpp import CppChecker
+from webkitpy.style.checkers.jsonchecker import JSONChecker
+from webkitpy.style.checkers.png import PNGChecker
+from webkitpy.style.checkers.python import PythonChecker
+from webkitpy.style.checkers.test_expectations import TestExpectationsChecker
+from webkitpy.style.checkers.text import TextChecker
+from webkitpy.style.checkers.xcodeproj import XcodeProjectFileChecker
+from webkitpy.style.checkers.xml import XMLChecker
+from webkitpy.style.error_handlers import DefaultStyleErrorHandler
+from webkitpy.style.filter import FilterConfiguration
+from webkitpy.style.optparser import ArgumentParser
+from webkitpy.style.optparser import DefaultCommandOptionValues
 
 
 _log = logging.getLogger(__name__)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/common_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/common_unittest.py
index 6200acc..bda749a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/common_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/common_unittest.py
@@ -24,8 +24,8 @@
 
 import unittest
 
-from common import CarriageReturnChecker
-from common import TabChecker
+from webkitpy.style.checkers.common import CarriageReturnChecker
+from webkitpy.style.checkers.common import TabChecker
 
 # FIXME: The unit tests for the cpp, text, and common checkers should
 #        share supporting test code. This can include, for example, the
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
index 51ce750..810bfbe2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -40,10 +40,10 @@
 import re
 import unittest
 
-import cpp as cpp_style
-from cpp import CppChecker
-from ..filter import FilterConfiguration
 from webkitpy.common.system.filesystem import FileSystem
+from webkitpy.style.checkers import cpp as cpp_style
+from webkitpy.style.checkers.cpp import CppChecker
+from webkitpy.style.filter import FilterConfiguration
 
 # This class works as an error collector and replaces cpp_style.Error
 # function for the unit tests.  We also verify each category we see
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/jsonchecker_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/jsonchecker_unittest.py
index 11b9d16..ac83a11 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/jsonchecker_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/jsonchecker_unittest.py
@@ -24,7 +24,7 @@
 
 import unittest
 
-import jsonchecker
+from webkitpy.style.checkers import jsonchecker
 
 
 class MockErrorHandler(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/png_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/png_unittest.py
index 636df7d7..c0aeb0c 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/png_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/png_unittest.py
@@ -25,7 +25,7 @@
 
 import unittest
 
-from png import PNGChecker
+from webkitpy.style.checkers.png import PNGChecker
 from webkitpy.common.system.filesystem_mock import MockFileSystem
 from webkitpy.common.system.system_host_mock import MockSystemHost
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
index d4c35d6e..abad796 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
@@ -25,7 +25,7 @@
 import os
 import unittest
 
-from python import PythonChecker
+from webkitpy.style.checkers.python import PythonChecker
 
 
 class PythonCheckerTest(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
index c8b8051..6ca9699 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
@@ -30,9 +30,9 @@
 
 import logging
 
-from common import TabChecker
 from webkitpy.common.host import Host
 from webkitpy.layout_tests.models.test_expectations import TestExpectationParser
+from webkitpy.style.checkers.common import TabChecker
 
 
 class TestExpectationsChecker(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
index c5ff9e5..c2d4e29 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
@@ -28,7 +28,7 @@
 
 import unittest
 
-from test_expectations import TestExpectationsChecker
+from webkitpy.style.checkers.test_expectations import TestExpectationsChecker
 from webkitpy.common.host_mock import MockHost
 
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text.py
index c85d9e61..9526f12 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text.py
@@ -29,11 +29,10 @@
 
 """Checks WebKit style for text files."""
 
-from common import TabChecker
+from webkitpy.style.checkers.common import TabChecker
 
 
 class TextChecker(object):
-
     """Processes text lines for checking style."""
 
     def __init__(self, file_path, handle_style_error):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text_unittest.py
index a9b9433..beeffb6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/text_unittest.py
@@ -26,12 +26,9 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-"""Unit test for text_style.py."""
-
 import unittest
 
-import text as text_style
-from text import TextChecker
+from webkitpy.style.checkers.text import process_file_data, TextChecker
 
 
 class TextStyleTestCase(unittest.TestCase):
@@ -45,7 +42,7 @@
             """Records if an error occurs."""
             self.had_error = True
 
-        text_style.process_file_data('', lines, error_for_test)
+        process_file_data('', lines, error_for_test)
         self.assertFalse(self.had_error, '%s should not have any errors.' % lines)
 
     def assertError(self, lines, expected_line_number):
@@ -58,7 +55,7 @@
             self.assertEqual('whitespace/tab', category)
             self.had_error = True
 
-        text_style.process_file_data('', lines, error_for_test)
+        process_file_data('', lines, error_for_test)
         self.assertTrue(self.had_error, '%s should have an error [whitespace/tab].' % lines)
 
     def test_no_error(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xcodeproj_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xcodeproj_unittest.py
index e36c93d..00de7f3 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xcodeproj_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xcodeproj_unittest.py
@@ -22,9 +22,10 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 """Unit test for xcodeproj.py."""
+
 import unittest
 
-import xcodeproj
+from webkitpy.style.checkers import xcodeproj
 
 
 class TestErrorHandler(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py
index 8d4505f..8127142 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py
@@ -23,7 +23,8 @@
 """Unit test for xml.py."""
 
 import unittest
-import xml
+
+from webkitpy.style.checkers import xml
 
 
 class MockErrorHandler(object):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/error_handlers_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/error_handlers_unittest.py
index e9b3b32..6c93eb2 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/error_handlers_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/error_handlers_unittest.py
@@ -24,9 +24,9 @@
 
 import unittest
 
-from checker import StyleProcessorConfiguration
-from error_handlers import DefaultStyleErrorHandler
-from filter import FilterConfiguration
+from webkitpy.style.checker import StyleProcessorConfiguration
+from webkitpy.style.error_handlers import DefaultStyleErrorHandler
+from webkitpy.style.filter import FilterConfiguration
 
 
 class DefaultStyleErrorHandlerTest(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/filter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/filter_unittest.py
index 0567c8d..a6a93bd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/filter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/filter_unittest.py
@@ -24,9 +24,9 @@
 
 import unittest
 
-from filter import _CategoryFilter as CategoryFilter
-from filter import validate_filter_rules
-from filter import FilterConfiguration
+from webkitpy.style.filter import _CategoryFilter as CategoryFilter
+from webkitpy.style.filter import validate_filter_rules
+from webkitpy.style.filter import FilterConfiguration
 
 # On Testing __eq__() and __ne__():
 #
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/optparser.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/optparser.py
index d2141eb8..12cd4ff 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/optparser.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/optparser.py
@@ -26,7 +26,7 @@
 from optparse import OptionParser
 import sys
 
-from filter import validate_filter_rules
+from webkitpy.style.filter import validate_filter_rules
 # This module should not import anything from checker.py.
 
 _log = logging.getLogger(__name__)
diff --git a/third_party/WebKit/public/platform/WebPointerProperties.h b/third_party/WebKit/public/platform/WebPointerProperties.h
index 49a142e..ad2704ae 100644
--- a/third_party/WebKit/public/platform/WebPointerProperties.h
+++ b/third_party/WebKit/public/platform/WebPointerProperties.h
@@ -80,7 +80,13 @@
   // degrees in the range [0,359]. Always 0 if the device does not support it.
   int twist;
 
+  // - For pointerup/down events, the button of pointing device that triggered
+  // the event.
+  // - For other events, the button that was depressed during the move event. If
+  // multiple buttons were depressed, one of the depressed buttons (platform
+  // dependent).
   Button button;
+
   PointerType pointerType;
 
   int movementX;
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
index f15a9f135..fa51de8 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListener.java
@@ -269,7 +269,11 @@
     Preconditions.checkNotNull(objectIds);
 
     Context context = getApplicationContext();
-    context.startService(createRegisterIntent(context, clientId, objectIds));
+    try {
+      context.startService(createRegisterIntent(context, clientId, objectIds));
+    } catch (IllegalStateException exception) {
+      logger.info("Unable to deliver `register` intent: %s", exception);
+    }
   }
 
   /**
@@ -318,7 +322,11 @@
     Preconditions.checkNotNull(objectIds);
 
     Context context = getApplicationContext();
-    context.startService(createUnregisterIntent(context, clientId, objectIds));
+    try {
+      context.startService(createUnregisterIntent(context, clientId, objectIds));
+    } catch (IllegalStateException exception) {
+      logger.info("Unable to deliver `unregister` intent: %s", exception);
+    }
   }
 
   /** See specs for {@link InvalidationClient#acknowledge}. */
@@ -334,7 +342,11 @@
     Preconditions.checkNotNull(ackHandle);
 
     Context context = getApplicationContext();
-    context.startService(createAcknowledgeIntent(context, ackHandle));
+    try {
+      context.startService(createAcknowledgeIntent(context, ackHandle));
+    } catch (IllegalStateException exception) {
+      logger.info("Unable to deliver `acknowledge` intent: %s", exception);
+    }
   }
 
   /**
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
index d734f6c..9f3433f 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/external/client/contrib/AndroidListenerIntents.java
@@ -46,7 +46,7 @@
   /** Key of Intent byte[] holding a {@link RegistrationCommand} protocol buffer. */
   static final String EXTRA_REGISTRATION =
       "com.google.ipc.invalidation.android_listener.REGISTRATION";
-  
+
   /** Key of Intent boolean indicating whether scheduled tasks should be flushed. */
   static final String EXTRA_SCHEDULED_TASK =
       "com.google.ipc.invalidation.android_listener.SCHEDULED_TASK";
@@ -67,8 +67,12 @@
    * Issues the given {@code intent} to the TICL service class registered in the {@code context}.
    */
   static void issueTiclIntent(Context context, Intent intent) {
-    context.startService(intent.setClassName(context,
-        new AndroidTiclManifest(context).getTiclServiceClass()));
+    try {
+      context.startService(intent.setClassName(context,
+          new AndroidTiclManifest(context).getTiclServiceClass()));
+    } catch (IllegalStateException exception) {
+      logger.info("Unable to deliver ticl intent: %s", exception);
+    }
   }
 
   /**
@@ -76,7 +80,11 @@
    * {@code context}.
    */
   static void issueAndroidListenerIntent(Context context, Intent intent) {
-    context.startService(setAndroidListenerClass(context, intent));
+    try {
+      context.startService(setAndroidListenerClass(context, intent));
+    } catch (IllegalStateException exception) {
+      logger.info("Unable to deliver listener intent: %s", exception);
+    }
   }
 
   /**
@@ -106,7 +114,7 @@
       return null;
     }
   }
-  
+
   /**
    * Returns {@link StartCommand} extra from the given intent or null if no valid start command
    * exists.
@@ -131,12 +139,12 @@
   static boolean isStopIntent(Intent intent) {
     return intent.hasExtra(EXTRA_STOP);
   }
-  
+
   /** Returns {@code true} if the intent has the 'scheduled-task' extra. */
   static boolean isScheduledTaskIntent(Intent intent) {
     return intent.hasExtra(EXTRA_SCHEDULED_TASK);
   }
-  
+
   /**
    * Uses {@link AlarmManager} to schedule an intent that will cause scheduled tasks to be executed.
    * Replaces any existing scheduled-task intent, so the provided execute time should be for the
@@ -144,11 +152,11 @@
    */
   static void issueScheduledTaskIntent(Context context, long executeMs) {
     Intent intent = createScheduledTaskintent(context);
-    
+
     // Create a pending intent that will cause the AlarmManager to fire the above intent.
     PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,
         PendingIntent.FLAG_UPDATE_CURRENT);
-    
+
     // Schedule the pending intent after the appropriate delay.
     AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
     try {
@@ -195,7 +203,7 @@
     intent.putExtra(EXTRA_REGISTRATION, command.toByteArray());
     return setAndroidListenerClass(context, intent);
   }
-  
+
   /** Constructs an intent indicating that scheduled tasks should run. */
   static Intent createScheduledTaskintent(Context context) {
     return new Intent()
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
index 8eb63d0..17d00c4a 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInternalScheduler.java
@@ -19,6 +19,7 @@
 import com.google.ipc.invalidation.external.client.SystemResources;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
 import com.google.ipc.invalidation.external.client.SystemResources.Scheduler;
+import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
 import com.google.ipc.invalidation.ticl.RecurringTask;
 import com.google.ipc.invalidation.ticl.proto.AndroidService.AndroidSchedulerEvent;
 import com.google.ipc.invalidation.ticl.proto.AndroidService.ScheduledTask;
@@ -57,6 +58,8 @@
 public final class AndroidInternalScheduler implements Scheduler {
   /** Class that receives AlarmManager broadcasts and reissues them as intents for this service. */
   public static final class AlarmReceiver extends BroadcastReceiver {
+    private static final Logger logger = AndroidLogger.forTag("AlarmReceiver");
+
     /*
      * This class needs to be public so that it can be instantiated by the Android runtime.
      * Additionally, it should be declared as a broadcast receiver in the application manifest:
@@ -69,7 +72,11 @@
       // Resend the intent to the service so that it's processed on the handler thread and with
       // the automatic shutdown logic provided by IntentService.
       intent.setClassName(context, new AndroidTiclManifest(context).getTiclServiceClass());
-      context.startService(intent);
+      try {
+        context.startService(intent);
+      } catch (IllegalStateException exception) {
+        logger.warning("Unable to handle alarm: %s", exception);
+      }
     }
   }
 
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
index a6cecb1..748394b 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientImpl.java
@@ -19,6 +19,7 @@
 import com.google.ipc.invalidation.external.client.InvalidationListener;
 import com.google.ipc.invalidation.external.client.SystemResources;
 import com.google.ipc.invalidation.external.client.SystemResources.Logger;
+import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
 import com.google.ipc.invalidation.external.client.types.AckHandle;
 import com.google.ipc.invalidation.external.client.types.ErrorInfo;
 import com.google.ipc.invalidation.external.client.types.Invalidation;
@@ -58,6 +59,9 @@
  *
  */
 class AndroidInvalidationClientImpl extends InvalidationClientCore {
+  /** Logger from Ticl resources. */
+  private static final Logger staticLogger = AndroidLogger.forTag("InvClientImpl");
+
   /** Class implementing the application listener stub (allows overriding default for tests). */
   static Class<? extends Service> listenerServiceClassForTest = null;
 
@@ -156,7 +160,11 @@
       intent.setClassName(context, (listenerServiceClassForTest != null) ?
           listenerServiceClassForTest.getName() :
               new AndroidTiclManifest(context).getListenerServiceClass());
-      context.startService(intent);
+      try {
+        context.startService(intent);
+      } catch (IllegalStateException exception) {
+        staticLogger.warning("Unable to deliver intent: %s", exception);
+      }
     }
 
     /**
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
index 6a54f9d1..66f5418 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/AndroidInvalidationClientStub.java
@@ -17,6 +17,8 @@
 package com.google.ipc.invalidation.ticl.android2;
 
 import com.google.ipc.invalidation.external.client.InvalidationClient;
+import com.google.ipc.invalidation.external.client.SystemResources.Logger;
+import com.google.ipc.invalidation.external.client.android.service.AndroidLogger;
 import com.google.ipc.invalidation.external.client.types.AckHandle;
 import com.google.ipc.invalidation.external.client.types.ObjectId;
 import com.google.ipc.invalidation.ticl.ProtoWrapperConverter;
@@ -36,6 +38,8 @@
  *
  */
 class AndroidInvalidationClientStub implements InvalidationClient {
+  private final Logger logger = AndroidLogger.forTag("InvClientStub");
+
   /** Android system context. */
   private final Context context;
 
@@ -98,6 +102,10 @@
   /** Sends {@code intent} to the service implemented by {@link #serviceClass}. */
   private void issueIntent(Intent intent) {
     intent.setClassName(context, serviceClass);
-    context.startService(intent);
+    try {
+      context.startService(intent);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to issue intent: %s", exception);
+    }
   }
 }
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
index 175a64d..b3bd1fb 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclService.java
@@ -329,6 +329,9 @@
         }
       } catch (ValidationException exception) {
         resources.getLogger().info("Failed to parse message: %s", exception.getMessage());
+      } catch (IllegalStateException exception) {
+        resources.getLogger().info(
+            "Unable to send background invalidation intent: %s", exception.getMessage());
       }
     }
   }
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
index 0789d6e..11db5fa 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/TiclStateManager.java
@@ -75,6 +75,9 @@
     AndroidInvalidationClientImpl ticl = new AndroidInvalidationClientImpl(context, resources,
         random, state);
     initScheduler(resources, ticl, state.getScheduledTask());
+    AndroidInternalScheduler scheduler =
+        (AndroidInternalScheduler) resources.getInternalScheduler();
+    scheduler.handleImplicitSchedulerEvent();
     return ticl;
   }
 
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java
index 3a224487..3149de9 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidGcmController.java
@@ -58,7 +58,7 @@
    * A getter method for AndroidGcmController singleton which also initializes it if it wasn't
    * already initialized.
    *
-   * @param context, the application context.
+   * @param context the application context.
    * @return a singleton instance of the AndroidGcmController
    */
   public static AndroidGcmController get(Context context) {
@@ -75,8 +75,8 @@
    * Override AndroidGcmController with a custom GcmNetworkManager in tests. This overrides the
    * existing instance of AndroidGcmController if any.
    *
-   * @param context, the application context.
-   * @param gcmNetworkManager, the custom GcmNetworkManager to use.
+   * @param context the application context.
+   * @param gcmNetworkManager the custom GcmNetworkManager to use.
    */
   public static void overrideAndroidGcmControllerForTests(
       Context context, GcmNetworkManager gcmNetworkManager) {
@@ -106,7 +106,7 @@
    * GCM channel. Sets the {@link AndroidChannelPreferences.GcmChannelType} and fetches the
    * registration token from GCM if no token is stored or if the application has been updated.
    *
-   * @param useGcmUpstream, if true, the upstream messages from the client to the data center are
+   * @param useGcmUpstream if true, the upstream messages from the client to the data center are
    * sent using GCM.
    */
   public void initializeGcm(boolean useGcmUpstream) {
@@ -170,7 +170,7 @@
   /**
    * Used by the client to forward downstream messages received from GCM.
    *
-   * @param data, the data bundle of the downstream message.
+   * @param data the data bundle of the downstream message.
    */
   public void onMessageReceived(Bundle data) {
     String content = data.getString(C2dmConstants.CONTENT_PARAM);
@@ -186,6 +186,8 @@
         context.startService(msgIntent);
       } catch (ValidationException exception) {
         logger.warning("Failed parsing inbound message: %s", exception);
+      } catch (IllegalStateException exception) {
+        logger.warning("Unable to handle inbound message: %s", exception);
       }
     } else {
       logger.warning("GCM Intent has no message content: %s", data);
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
index 54d0fb9..aa3938ce 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageReceiverService.java
@@ -75,6 +75,8 @@
         startService(msgIntent);
       } catch (ValidationException exception) {
         logger.warning("Failed parsing inbound message: %s", exception);
+      } catch (IllegalStateException exception) {
+        logger.warning("Unable to handle inbound message: %s", exception);
       }
     } else {
       logger.fine("GCM Intent has no message content: %s", intent);
@@ -96,13 +98,21 @@
     final String ignoredData = "";
     sendBuffered.putExtra(AndroidChannelConstants.MESSAGE_SENDER_SVC_GCM_REGID_CHANGE, ignoredData);
     sendBuffered.setClass(this, AndroidMessageSenderService.class);
-    startService(sendBuffered);
+    try {
+      startService(sendBuffered);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to send buffered message(s): %s", exception);
+    }
 
     // Inform the Ticl service that the registration id has changed. This will cause it to send
     // a message to the data center and update the GCM registration id stored at the data center.
     Intent updateServer = ProtocolIntents.InternalDowncalls.newNetworkAddrChangeIntent();
     updateServer.setClassName(this, new AndroidTiclManifest(this).getTiclServiceClass());
-    startService(updateServer);
+    try {
+      startService(updateServer);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to handle new registration id: %s", exception);
+    }
   }
 
   @Override
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
index 81882a7..22a168c7 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidMessageSenderService.java
@@ -171,7 +171,7 @@
     requestTokenIntent.setClassName(getApplicationContext(), simpleListenerClass);
     try {
       startService(requestTokenIntent);
-    } catch (SecurityException exception) {
+    } catch (SecurityException | IllegalStateException exception) {
       logger.warning("unable to request auth token: %s", exception);
     }
   }
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
index 4a3adefd..377ad73b9 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/AndroidNetworkChannel.java
@@ -58,7 +58,11 @@
     } else {
       intent.setClassName(context, AndroidMessageSenderService.class.getName());
     }
-    context.startService(intent);
+    try {
+      context.startService(intent);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to send message: %s", exception);
+    }
   }
 
   @Override
diff --git a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java
index e6f4b4214..06c9d2f 100644
--- a/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java
+++ b/third_party/cacheinvalidation/src/java/com/google/ipc/invalidation/ticl/android2/channel/GcmRegistrationTaskService.java
@@ -37,14 +37,14 @@
  * started by the {@link GcmNetworkManager} when a Task scheduled using the GcmNetworkManager is
  * ready to be executed. The task to start this service is scheduled in
  * {@link AndroidGcmController#fetchToken}.
- * 
+ *
  * <p>The service fetches a token from GCM, stores it and sends an update to the server. In case of
  * failure to fetch the token, the task is rescheduled using the GcmNetworkManager which uses
  * exponential back-offs to control when the task is executed.
  */
 public class GcmRegistrationTaskService extends GcmTaskService {
   private static final Logger logger = AndroidLogger.forTag("RegistrationTaskService");
-  
+
   public InstanceID getInstanceID(Context context) {
     return InstanceID.getInstance(context);
   }
@@ -52,7 +52,7 @@
   /**
    * Called when the task is ready to be executed. Registers with GCM using
    * {@link InstanceID#getToken} and stores the registration token.
-   * 
+   *
    * <p>Returns {@link GcmNetworkManager#RESULT_SUCCESS} when the token is successfully retrieved.
    * On failure {@link GcmNetworkManager#RESULT_RESCHEDULE} is used which reschedules the service
    * to be executed again using exponential back-off.
@@ -110,12 +110,20 @@
     } else {
       sendBuffered.setClass(this, AndroidMessageSenderService.class);
     }
-    startService(sendBuffered);
+    try {
+      startService(sendBuffered);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to send buffered message(s): %s", exception);
+    }
 
     // Inform the Ticl service that the registration id has changed. This will cause it to send
     // a message to the data center and update the GCM registration id stored at the data center.
     Intent updateServer = ProtocolIntents.InternalDowncalls.newNetworkAddrChangeIntent();
     updateServer.setClassName(this, new AndroidTiclManifest(this).getTiclServiceClass());
-    startService(updateServer);
+    try {
+      startService(updateServer);
+    } catch (IllegalStateException exception) {
+      logger.warning("Unable to inform server about new registration id: %s", exception);
+    }
   }
 }
diff --git a/third_party/libvpx/README.chromium b/third_party/libvpx/README.chromium
index 1b819f9f..3d82e58 100644
--- a/third_party/libvpx/README.chromium
+++ b/third_party/libvpx/README.chromium
@@ -5,9 +5,9 @@
 License File: source/libvpx/LICENSE
 Security Critical: yes
 
-Date: Saturday February 11 2017
+Date: Tuesday February 21 2017
 Branch: master
-Commit: 91f87e75135cc9722ee72daf5154424f628a906e
+Commit: 4d4231352c8cefdae2e76b7bad4286ec21747c89
 
 Description:
 Contains the sources used to compile libvpx binaries used by Google Chrome and
diff --git a/third_party/libvpx/libvpx_srcs.gni b/third_party/libvpx/libvpx_srcs.gni
index 1a7345b..8ff29f3 100644
--- a/third_party/libvpx/libvpx_srcs.gni
+++ b/third_party/libvpx/libvpx_srcs.gni
@@ -316,6 +316,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_dsp_common.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_dsp_rtcd.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_filter.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_avx2.h",
@@ -758,6 +759,7 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_dsp_common.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_dsp_rtcd.c",
   "//third_party/libvpx/source/libvpx/vpx_dsp/vpx_filter.h",
+  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_avx2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/bitdepth_conversion_sse2.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/convolve.h",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/fwd_dct32x32_impl_avx2.h",
@@ -828,7 +830,6 @@
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/highbd_variance_impl_sse2.asm",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/intrapred_sse2.asm",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/intrapred_ssse3.asm",
-  "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/inv_wht_sse2.asm",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/quantize_avx_x86_64.asm",
   "//third_party/libvpx/source/libvpx/vpx_dsp/x86/quantize_ssse3_x86_64.asm",
diff --git a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
index 18f79e2..3f920cc2a4 100644
--- a/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/generic/vpx_dsp_rtcd.h
@@ -910,6 +910,9 @@
 void vpx_highbd_idct16x16_256_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct16x16_256_add vpx_highbd_idct16x16_256_add_c
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+#define vpx_highbd_idct16x16_38_add vpx_highbd_idct16x16_38_add_c
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
diff --git a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
index 3770dd3..ac968a9 100644
--- a/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,7 +139,8 @@
 RTCD_EXTERN void (*vp9_iht8x8_64_add)(const tran_low_t *input, uint8_t *dest, int stride, int tx_type);
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 #define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
@@ -157,6 +159,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_block_error_fp = vp9_block_error_fp_c;
     if (flags & HAS_SSE2) vp9_block_error_fp = vp9_block_error_fp_sse2;
     vp9_denoiser_filter = vp9_denoiser_filter_c;
@@ -191,6 +195,8 @@
     if (flags & HAS_SSE2) vp9_iht4x4_16_add = vp9_iht4x4_16_add_sse2;
     vp9_iht8x8_64_add = vp9_iht8x8_64_add_c;
     if (flags & HAS_SSE2) vp9_iht8x8_64_add = vp9_iht8x8_64_add_sse2;
+    vp9_quantize_fp = vp9_quantize_fp_c;
+    if (flags & HAS_SSE2) vp9_quantize_fp = vp9_quantize_fp_sse2;
     vp9_temporal_filter_apply = vp9_temporal_filter_apply_c;
     if (flags & HAS_SSE2) vp9_temporal_filter_apply = vp9_temporal_filter_apply_sse2;
 }
diff --git a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
index 727a39e..20ab4d2 100644
--- a/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/ia32/vpx_dsp_rtcd.h
@@ -1095,6 +1095,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct16x16_256_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct16x16_38_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
@@ -2443,6 +2447,8 @@
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_10_add = vpx_highbd_idct16x16_10_add_sse2;
     vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_sse2;
+    vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_38_add_c;
+    if (flags & HAS_SSE2) vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_256_add_sse2;
     vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_sse2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_c;
diff --git a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
index f8c2110..b102039 100644
--- a/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,10 +139,13 @@
 #define vp9_iht8x8_64_add vp9_iht8x8_64_add_sse2
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+void vp9_quantize_fp_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
+void vp9_quantize_fp_32x32_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp_32x32)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_temporal_filter_apply_c(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
 void vp9_temporal_filter_apply_sse2(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
@@ -157,6 +161,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_diamond_search_sad = vp9_diamond_search_sad_c;
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
@@ -166,6 +172,10 @@
     if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_sse2;
     if (flags & HAS_AVX) vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_avx;
+    vp9_quantize_fp = vp9_quantize_fp_sse2;
+    if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
+    vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
+    if (flags & HAS_SSSE3) vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_ssse3;
 }
 #endif
 
diff --git a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
index 9fbfef8f..ac714cab 100644
--- a/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h
@@ -1102,6 +1102,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct16x16_256_add vpx_highbd_idct16x16_256_add_sse2
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+#define vpx_highbd_idct16x16_38_add vpx_highbd_idct16x16_256_add_sse2
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
diff --git a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
index 3770dd3..ac968a9 100644
--- a/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,7 +139,8 @@
 RTCD_EXTERN void (*vp9_iht8x8_64_add)(const tran_low_t *input, uint8_t *dest, int stride, int tx_type);
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 #define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
@@ -157,6 +159,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_block_error_fp = vp9_block_error_fp_c;
     if (flags & HAS_SSE2) vp9_block_error_fp = vp9_block_error_fp_sse2;
     vp9_denoiser_filter = vp9_denoiser_filter_c;
@@ -191,6 +195,8 @@
     if (flags & HAS_SSE2) vp9_iht4x4_16_add = vp9_iht4x4_16_add_sse2;
     vp9_iht8x8_64_add = vp9_iht8x8_64_add_c;
     if (flags & HAS_SSE2) vp9_iht8x8_64_add = vp9_iht8x8_64_add_sse2;
+    vp9_quantize_fp = vp9_quantize_fp_c;
+    if (flags & HAS_SSE2) vp9_quantize_fp = vp9_quantize_fp_sse2;
     vp9_temporal_filter_apply = vp9_temporal_filter_apply_c;
     if (flags & HAS_SSE2) vp9_temporal_filter_apply = vp9_temporal_filter_apply_sse2;
 }
diff --git a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
index 727a39e..20ab4d2 100644
--- a/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/ia32/vpx_dsp_rtcd.h
@@ -1095,6 +1095,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct16x16_256_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct16x16_38_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
@@ -2443,6 +2447,8 @@
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_10_add = vpx_highbd_idct16x16_10_add_sse2;
     vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_sse2;
+    vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_38_add_c;
+    if (flags & HAS_SSE2) vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_256_add_sse2;
     vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_sse2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_c;
diff --git a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
index f8c2110..b102039 100644
--- a/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,10 +139,13 @@
 #define vp9_iht8x8_64_add vp9_iht8x8_64_add_sse2
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+void vp9_quantize_fp_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
+void vp9_quantize_fp_32x32_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp_32x32)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_temporal_filter_apply_c(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
 void vp9_temporal_filter_apply_sse2(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
@@ -157,6 +161,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_diamond_search_sad = vp9_diamond_search_sad_c;
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
@@ -166,6 +172,10 @@
     if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_sse2;
     if (flags & HAS_AVX) vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_avx;
+    vp9_quantize_fp = vp9_quantize_fp_sse2;
+    if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
+    vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
+    if (flags & HAS_SSSE3) vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_ssse3;
 }
 #endif
 
diff --git a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
index 9fbfef8f..ac714cab 100644
--- a/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/mac/x64/vpx_dsp_rtcd.h
@@ -1102,6 +1102,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct16x16_256_add vpx_highbd_idct16x16_256_add_sse2
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+#define vpx_highbd_idct16x16_38_add vpx_highbd_idct16x16_256_add_sse2
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
diff --git a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
index 18f79e2..3f920cc2a4 100644
--- a/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h
@@ -910,6 +910,9 @@
 void vpx_highbd_idct16x16_256_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct16x16_256_add vpx_highbd_idct16x16_256_add_c
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+#define vpx_highbd_idct16x16_38_add vpx_highbd_idct16x16_38_add_c
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
diff --git a/third_party/libvpx/source/config/vpx_version.h b/third_party/libvpx/source/config/vpx_version.h
index 8b6f918b..d38bf2ad 100644
--- a/third_party/libvpx/source/config/vpx_version.h
+++ b/third_party/libvpx/source/config/vpx_version.h
@@ -1,7 +1,7 @@
 #define VERSION_MAJOR  1
 #define VERSION_MINOR  6
 #define VERSION_PATCH  1
-#define VERSION_EXTRA  "149-g91f87e751"
+#define VERSION_EXTRA  "235-g4d4231352"
 #define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
-#define VERSION_STRING_NOSP "v1.6.1-149-g91f87e751"
-#define VERSION_STRING      " v1.6.1-149-g91f87e751"
+#define VERSION_STRING_NOSP "v1.6.1-235-g4d4231352"
+#define VERSION_STRING      " v1.6.1-235-g4d4231352"
diff --git a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
index 3770dd3..ac968a9 100644
--- a/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,7 +139,8 @@
 RTCD_EXTERN void (*vp9_iht8x8_64_add)(const tran_low_t *input, uint8_t *dest, int stride, int tx_type);
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 #define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
@@ -157,6 +159,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_block_error_fp = vp9_block_error_fp_c;
     if (flags & HAS_SSE2) vp9_block_error_fp = vp9_block_error_fp_sse2;
     vp9_denoiser_filter = vp9_denoiser_filter_c;
@@ -191,6 +195,8 @@
     if (flags & HAS_SSE2) vp9_iht4x4_16_add = vp9_iht4x4_16_add_sse2;
     vp9_iht8x8_64_add = vp9_iht8x8_64_add_c;
     if (flags & HAS_SSE2) vp9_iht8x8_64_add = vp9_iht8x8_64_add_sse2;
+    vp9_quantize_fp = vp9_quantize_fp_c;
+    if (flags & HAS_SSE2) vp9_quantize_fp = vp9_quantize_fp_sse2;
     vp9_temporal_filter_apply = vp9_temporal_filter_apply_c;
     if (flags & HAS_SSE2) vp9_temporal_filter_apply = vp9_temporal_filter_apply_sse2;
 }
diff --git a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
index 727a39e..20ab4d2 100644
--- a/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/ia32/vpx_dsp_rtcd.h
@@ -1095,6 +1095,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 RTCD_EXTERN void (*vpx_highbd_idct16x16_256_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+RTCD_EXTERN void (*vpx_highbd_idct16x16_38_add)(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
@@ -2443,6 +2447,8 @@
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_10_add = vpx_highbd_idct16x16_10_add_sse2;
     vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct16x16_256_add = vpx_highbd_idct16x16_256_add_sse2;
+    vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_38_add_c;
+    if (flags & HAS_SSE2) vpx_highbd_idct16x16_38_add = vpx_highbd_idct16x16_256_add_sse2;
     vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_c;
     if (flags & HAS_SSE2) vpx_highbd_idct32x32_1_add = vpx_highbd_idct32x32_1_add_sse2;
     vpx_highbd_idct4x4_16_add = vpx_highbd_idct4x4_16_add_c;
diff --git a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
index f8c2110..b102039 100644
--- a/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vp9_rtcd.h
@@ -30,7 +30,8 @@
 #endif
 
 int64_t vp9_block_error_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
-#define vp9_block_error vp9_block_error_c
+int64_t vp9_block_error_avx2(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
+RTCD_EXTERN int64_t (*vp9_block_error)(const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz);
 
 int64_t vp9_block_error_fp_c(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
 int64_t vp9_block_error_fp_sse2(const tran_low_t *coeff, const tran_low_t *dqcoeff, int block_size);
@@ -138,10 +139,13 @@
 #define vp9_iht8x8_64_add vp9_iht8x8_64_add_sse2
 
 void vp9_quantize_fp_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp vp9_quantize_fp_c
+void vp9_quantize_fp_sse2(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+void vp9_quantize_fp_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_quantize_fp_32x32_c(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
-#define vp9_quantize_fp_32x32 vp9_quantize_fp_32x32_c
+void vp9_quantize_fp_32x32_ssse3(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
+RTCD_EXTERN void (*vp9_quantize_fp_32x32)(const tran_low_t *coeff_ptr, intptr_t n_coeffs, int skip_block, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan);
 
 void vp9_temporal_filter_apply_c(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
 void vp9_temporal_filter_apply_sse2(uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count);
@@ -157,6 +161,8 @@
 
     (void)flags;
 
+    vp9_block_error = vp9_block_error_c;
+    if (flags & HAS_AVX2) vp9_block_error = vp9_block_error_avx2;
     vp9_diamond_search_sad = vp9_diamond_search_sad_c;
     if (flags & HAS_AVX) vp9_diamond_search_sad = vp9_diamond_search_sad_avx;
     vp9_fdct8x8_quant = vp9_fdct8x8_quant_c;
@@ -166,6 +172,10 @@
     if (flags & HAS_SSE4_1) vp9_full_search_sad = vp9_full_search_sadx8;
     vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_sse2;
     if (flags & HAS_AVX) vp9_highbd_block_error_8bit = vp9_highbd_block_error_8bit_avx;
+    vp9_quantize_fp = vp9_quantize_fp_sse2;
+    if (flags & HAS_SSSE3) vp9_quantize_fp = vp9_quantize_fp_ssse3;
+    vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_c;
+    if (flags & HAS_SSSE3) vp9_quantize_fp_32x32 = vp9_quantize_fp_32x32_ssse3;
 }
 #endif
 
diff --git a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
index 9fbfef8f..ac714cab 100644
--- a/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
+++ b/third_party/libvpx/source/config/win/x64/vpx_dsp_rtcd.h
@@ -1102,6 +1102,10 @@
 void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct16x16_256_add vpx_highbd_idct16x16_256_add_sse2
 
+void vpx_highbd_idct16x16_38_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+void vpx_highbd_idct16x16_256_add_sse2(const tran_low_t *input, uint8_t *dest, int stride, int bd);
+#define vpx_highbd_idct16x16_38_add vpx_highbd_idct16x16_256_add_sse2
+
 void vpx_highbd_idct32x32_1024_add_c(const tran_low_t *input, uint8_t *dest, int stride, int bd);
 #define vpx_highbd_idct32x32_1024_add vpx_highbd_idct32x32_1024_add_c
 
diff --git a/tools/cr/OWNERS b/tools/cr/OWNERS
index fa6851a..852aadf 100644
--- a/tools/cr/OWNERS
+++ b/tools/cr/OWNERS
@@ -1,3 +1,5 @@
 miguelg@chromium.org
 petrcermak@chromium.org
 skyostil@chromium.org
+
+# COMPONENT: Tools
diff --git a/tools/gn/analyzer.cc b/tools/gn/analyzer.cc
index 06f9336..559287ef 100644
--- a/tools/gn/analyzer.cc
+++ b/tools/gn/analyzer.cc
@@ -51,13 +51,13 @@
 
 LabelSet LabelsFor(const TargetSet& targets) {
   LabelSet labels;
-  for (const auto& target : targets)
+  for (auto* target : targets)
     labels.insert(target->label());
   return labels;
 }
 
 bool AnyBuildFilesWereModified(const SourceFileSet& source_files) {
-  for (const auto& file : source_files) {
+  for (auto* file : source_files) {
     if (base::EndsWith(file->value(), ".gn", base::CompareCase::SENSITIVE) ||
         base::EndsWith(file->value(), ".gni", base::CompareCase::SENSITIVE))
       return true;
@@ -287,7 +287,7 @@
 
   TargetSet compile_targets = TargetsFor(inputs.compile_labels);
   if (inputs.compile_included_all) {
-    for (auto& root : roots_)
+    for (auto* root : roots_)
       compile_targets.insert(root);
   }
   TargetSet filtered_targets = Filter(compile_targets);
@@ -307,10 +307,10 @@
 TargetSet Analyzer::AllAffectedTargets(
     const SourceFileSet& source_files) const {
   TargetSet direct_matches;
-  for (const auto& source_file : source_files)
+  for (auto* source_file : source_files)
     AddTargetsDirectlyReferringToFileTo(source_file, &direct_matches);
   TargetSet all_matches;
-  for (const auto& match : direct_matches)
+  for (auto* match : direct_matches)
     AddAllRefsTo(match, &all_matches);
   return all_matches;
 }
@@ -392,7 +392,7 @@
 
 void Analyzer::AddTargetsDirectlyReferringToFileTo(const SourceFile* file,
                                                    TargetSet* matches) const {
-  for (const auto& target : all_targets_) {
+  for (auto* target : all_targets_) {
     // Only handles targets in the default toolchain.
     if ((target->label().GetToolchainLabel() == default_toolchain_) &&
         TargetRefersToFile(target, file))
diff --git a/tools/gn/import_manager.cc b/tools/gn/import_manager.cc
index 0213c33..c9a44d4 100644
--- a/tools/gn/import_manager.cc
+++ b/tools/gn/import_manager.cc
@@ -111,7 +111,7 @@
           base::TimeDelta::FromMilliseconds(20);
       if (TracingEnabled() &&
           import_block_end - import_block_begin > kImportBlockTraceThreshold) {
-        auto import_block_trace =
+        auto* import_block_trace =
             new TraceItem(TraceItem::TRACE_IMPORT_BLOCK, file.value(),
                           base::PlatformThread::CurrentId());
         import_block_trace->set_begin(import_block_begin);
diff --git a/tools/grit/grit/format/html_inline.py b/tools/grit/grit/format/html_inline.py
index 9e5ec6a8..3c8e21b 100755
--- a/tools/grit/grit/format/html_inline.py
+++ b/tools/grit/grit/format/html_inline.py
@@ -48,7 +48,23 @@
     '(\s*</include>)?',
     re.DOTALL)
 _SRC_RE = lazy_re.compile(
-    r'<(?!script)(?:[^>]+?\s)src=(?P<quote>")(?!\[\[|{{)(?P<filename>[^"\']*)\1',
+    r'<(?!script)(?:[^>]+?\s)src="(?!\[\[|{{)(?P<filename>[^"\']*)"',
+    re.MULTILINE)
+# This re matches '<img srcset="..."'
+_SRCSET_RE = lazy_re.compile(
+    r'<img\b(?:[^>]*?\s)srcset="(?!\[\[|{{)(?P<srcset>[^"\']*)"',
+    re.MULTILINE)
+# This re is for splitting srcset value string into "image candidate strings".
+# Notes:
+# - HTML 5.2 states that URL cannot start with comma.
+# - the "descriptor" is either "width descriptor" or "pixel density descriptor".
+#   The first one consists of "valid non-negative integer + letter 'x'",
+#   the second one is formed of "positive valid floating-point number +
+#   letter 'w'". As a reasonable compromise, we match a list of characters
+#   that form both of them.
+# Matches for example "img2.png 2x" or "img9.png 11E-2w".
+_SRCSET_ENTRY_RE = lazy_re.compile(
+    r'\s*(?P<url>[^,]\S+)\s+(?P<descriptor>[\deE.-]+[wx])\s*',
     re.MULTILINE)
 _ICON_RE = lazy_re.compile(
     r'<link rel="icon"\s(?:[^>]+?\s)?'
@@ -69,20 +85,17 @@
       distribution = distribution[1:].lower()
   return distribution
 
+def ConvertFileToDataURL(filename, base_path, distribution, inlined_files,
+    names_only):
+  """Convert filename to inlined data URI.
 
-def SrcInlineAsDataURL(
-    src_match, base_path, distribution, inlined_files, names_only=False,
-    filename_expansion_function=None):
-  """regex replace function.
-
-  Takes a regex match for src="filename", attempts to read the file
-  at 'filename' and returns the src attribute with the file inlined
-  as a data URI. If it finds DIST_SUBSTR string in file name, replaces
-  it with distribution.
+  Takes a filename from ether "src" or "srcset", and attempts to read the file
+  at 'filename'. Returns data URI as string with given file inlined.
+  If it finds DIST_SUBSTR string in file name, replaces it with distribution.
+  If filename contains ':', it is considered URL and not translated.
 
   Args:
-    src_match: regex match object with 'filename' and 'quote' named capturing
-               groups
+    filename: filename string from ether src or srcset attributes.
     base_path: path that to look for files in
     distribution: string that should replace DIST_SUBSTR
     inlined_files: The name of the opened file is appended to this list.
@@ -92,14 +105,9 @@
   Returns:
     string
   """
-  filename = src_match.group('filename')
-  if filename_expansion_function:
-    filename = filename_expansion_function(filename)
-  quote = src_match.group('quote')
-
   if filename.find(':') != -1:
     # filename is probably a URL, which we don't want to bother inlining
-    return src_match.group(0)
+    return filename
 
   filename = filename.replace(DIST_SUBSTR , distribution)
   filepath = os.path.normpath(os.path.join(base_path, filename))
@@ -113,11 +121,122 @@
     raise Exception('%s is of an an unknown type and '
                     'cannot be stored in a data url.' % filename)
   inline_data = base64.standard_b64encode(util.ReadFile(filepath, util.BINARY))
+  return 'data:%s;base64,%s' % (mimetype, inline_data)
+
+
+def SrcInlineAsDataURL(
+    src_match, base_path, distribution, inlined_files, names_only=False,
+    filename_expansion_function=None):
+  """regex replace function.
+
+  Takes a regex match for src="filename", attempts to read the file
+  at 'filename' and returns the src attribute with the file inlined
+  as a data URI. If it finds DIST_SUBSTR string in file name, replaces
+  it with distribution.
+
+  Args:
+    src_match: regex match object with 'filename' named capturing group
+    base_path: path that to look for files in
+    distribution: string that should replace DIST_SUBSTR
+    inlined_files: The name of the opened file is appended to this list.
+    names_only: If true, the function will not read the file but just return "".
+                It will still add the filename to |inlined_files|.
+
+  Returns:
+    string
+  """
+  filename = src_match.group('filename')
+  if filename_expansion_function:
+    filename = filename_expansion_function(filename)
+
+  data_url = ConvertFileToDataURL(filename, base_path, distribution,
+                                  inlined_files, names_only)
+
+  if not data_url:
+    return data_url
 
   prefix = src_match.string[src_match.start():src_match.start('filename')]
   suffix = src_match.string[src_match.end('filename'):src_match.end()]
-  return '%sdata:%s;base64,%s%s' % (prefix, mimetype, inline_data, suffix)
+  return prefix + data_url + suffix
 
+def SrcsetInlineAsDataURL(
+    srcset_match, base_path, distribution, inlined_files, names_only=False,
+    filename_expansion_function=None):
+  """regex replace function to inline files in srcset="..." attributes
+
+  Takes a regex match for srcset="filename 1x, filename 2x, ...", attempts to
+  read the files referenced by filenames and returns the srcset attribute with
+  the files inlined as a data URI. If it finds DIST_SUBSTR string in file name,
+  replaces it with distribution.
+
+  Args:
+    srcset_match: regex match object with 'srcset' named capturing group
+    base_path: path that to look for files in
+    distribution: string that should replace DIST_SUBSTR
+    inlined_files: The name of the opened file is appended to this list.
+    names_only: If true, the function will not read the file but just return "".
+                It will still add the filename to |inlined_files|.
+
+  Returns:
+    string
+  """
+  srcset = srcset_match.group('srcset')
+
+  if not srcset:
+    return srcset_match.group(0)
+
+  # HTML 5.2 defines srcset as a list of "image candidate strings".
+  # Each of them consists of URL and descriptor.
+  # _SRCSET_ENTRY_RE splits srcset into a list of URLs, descriptors and
+  # commas.
+  parts = _SRCSET_ENTRY_RE.split(srcset)
+
+  if not parts:
+    return srcset_match.group(0)
+
+  # List of image candidate strings that will form new srcset="..."
+  new_candidates = []
+
+  # When iterating over split srcset we fill this parts of a single image
+  # candidate string: [url, descriptor]
+  candidate = [];
+
+  for part in parts:
+    if not part:
+      continue
+
+    if part == ',':
+      # There must be no URL without a descriptor.
+      assert not candidate, "Bad srcset format in '%s'" % srcset_match.group(0)
+      continue
+
+    if candidate:
+      # descriptor found
+      if candidate[0]:
+        # This is not "names_only" mode.
+        candidate.append(part)
+        new_candidates.append(" ".join(candidate))
+
+      candidate = []
+      continue
+
+    if filename_expansion_function:
+      filename = filename_expansion_function(part)
+    else:
+      filename = part
+
+    data_url = ConvertFileToDataURL(filename, base_path, distribution,
+                                    inlined_files, names_only)
+
+    candidate.append(data_url)
+
+  # There must be no URL without a descriptor
+  assert not candidate, "Bad srcset ending in '%s' " % srcset_match.group(0)
+
+  prefix = srcset_match.string[srcset_match.start():
+      srcset_match.start('srcset')]
+  suffix = srcset_match.string[srcset_match.end('srcset'):srcset_match.end()]
+  return prefix + ','.join(new_candidates) + suffix
 
 class InlinedData:
   """Helper class holding the results from DoInline().
@@ -168,6 +287,16 @@
         src_match, filepath, distribution, inlined_files, names_only=names_only,
         filename_expansion_function=filename_expansion_function)
 
+  def SrcsetReplace(srcset_match, filepath=input_filepath,
+                 inlined_files=inlined_files):
+    """Helper function to provide SrcsetInlineAsDataURL with the base file
+    path.
+    """
+    return SrcsetInlineAsDataURL(
+        srcset_match, filepath, distribution, inlined_files,
+        names_only=names_only,
+        filename_expansion_function=filename_expansion_function)
+
   def GetFilepath(src_match, base_path = input_filepath):
     matches = src_match.groupdict().iteritems()
     filename = [v for k, v in matches if k.startswith('file') and v][0]
@@ -369,6 +498,7 @@
     if rewrite_function:
       flat_text = rewrite_function(input_filepath, flat_text, distribution)
     flat_text = _SRC_RE.sub(SrcReplace, flat_text)
+    flat_text = _SRCSET_RE.sub(SrcsetReplace, flat_text)
 
     # TODO(arv): Only do this inside <style> tags.
     flat_text = InlineCSSImages(flat_text)
diff --git a/tools/grit/grit/format/html_inline_unittest.py b/tools/grit/grit/format/html_inline_unittest.py
index d049b1ef..062296c 100755
--- a/tools/grit/grit/format/html_inline_unittest.py
+++ b/tools/grit/grit/format/html_inline_unittest.py
@@ -506,6 +506,60 @@
     self.failUnlessEqual(expected_inlined,
                          util.FixLineEnd(result.inlined_data, '\n'))
 
+  def testImgSrcset(self):
+    '''Tests that img srcset="" attributes are converted.'''
+
+    # Note that there is no space before "img10.png"
+    files = {
+      'index.html': '''
+      <html>
+      <img src="img1.png" srcset="img2.png 1x, img3.png 2x">
+      <img src="img4.png" srcset=" img5.png   1x , img6.png 2x ">
+      <img src="chrome://theme/img11.png" srcset="img7.png 1x, '''\
+          '''chrome://theme/img13.png 2x">
+      <img srcset="img8.png 300w, img9.png 11E-2w,img10.png -1e2w">
+      </html>
+      ''',
+      'img1.png': '''a1''',
+      'img2.png': '''a2''',
+      'img3.png': '''a3''',
+      'img4.png': '''a4''',
+      'img5.png': '''a5''',
+      'img6.png': '''a6''',
+      'img7.png': '''a7''',
+      'img8.png': '''a8''',
+      'img9.png': '''a9''',
+      'img10.png': '''a10''',
+    }
+
+    expected_inlined = '''
+      <html>
+      <img src="data:image/png;base64,YTE=" srcset="data:image/png;base64,'''\
+          '''YTI= 1x,data:image/png;base64,YTM= 2x">
+      <img src="data:image/png;base64,YTQ=" srcset="data:image/png;base64,'''\
+          '''YTU= 1x,data:image/png;base64,YTY= 2x">
+      <img src="chrome://theme/img11.png" srcset="data:image/png;base64,'''\
+          '''YTc= 1x,chrome://theme/img13.png 2x">
+      <img srcset="data:image/png;base64,YTg= 300w,data:image/png;base64,'''\
+          '''YTk= 11E-2w,data:image/png;base64,YTEw -1e2w">
+      </html>
+      '''
+
+    source_resources = set()
+    tmp_dir = util.TempDir(files)
+    for filename in files:
+      source_resources.add(tmp_dir.GetPath(filename))
+
+    # Test normal inlining.
+    result = html_inline.DoInline(
+        tmp_dir.GetPath('index.html'),
+        None)
+    resources = result.inlined_files
+    resources.add(tmp_dir.GetPath('index.html'))
+    self.failUnlessEqual(resources, source_resources)
+    self.failUnlessEqual(expected_inlined,
+                         util.FixLineEnd(result.inlined_data, '\n'))
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/ipc_fuzzer/message_replay/replay_process.cc b/tools/ipc_fuzzer/message_replay/replay_process.cc
index d69f9c1..f812995 100644
--- a/tools/ipc_fuzzer/message_replay/replay_process.cc
+++ b/tools/ipc_fuzzer/message_replay/replay_process.cc
@@ -11,7 +11,6 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
-#include "base/posix/global_descriptors.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
@@ -24,6 +23,7 @@
 #include "mojo/edk/embedder/scoped_ipc_support.h"
 
 #if defined(OS_POSIX)
+#include "base/posix/global_descriptors.h"
 #include "content/public/common/content_descriptors.h"
 #endif
 
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 10a462f..6ffdf566 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -58641,6 +58641,17 @@
   </summary>
 </histogram>
 
+<histogram name="SBDownloadFeedback.UploadRequestedByServer"
+    enum="DownloadUploadRequestedByServer">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    For each non-SAFE file, records whether the server requested that that file
+    be uploaded.
+
+    Logged before checking the file size, so it may be dropped there.
+  </summary>
+</histogram>
+
 <histogram name="SBDownloadFeedback.UploadResult"
     enum="SBDownloadFeedbackUploadResult">
   <owner>mattm@chromium.org</owner>
@@ -85997,6 +86008,11 @@
   <int value="6" label="Initiated by Automatic Resumption"/>
 </enum>
 
+<enum name="DownloadUploadRequestedByServer" type="int">
+  <int value="0" label="No Upload"/>
+  <int value="1" label="Upload Requested"/>
+</enum>
+
 <enum name="DragDropEventSource" type="int">
   <int value="0" label="Mouse"/>
   <int value="1" label="Touch"/>
diff --git a/tools/perf/OWNERS b/tools/perf/OWNERS
index ac6816ed..596f984 100644
--- a/tools/perf/OWNERS
+++ b/tools/perf/OWNERS
@@ -23,3 +23,6 @@
 # petrcermak@chromium.org
 # qyearsley@chromium.org
 # tonyg@chromium.org
+
+# TEAM: benchmarking-dev@chromium.org
+# COMPONENT: Speed>Benchmarking
diff --git a/ui/android/BUILD.gn b/ui/android/BUILD.gn
index bc9223a5..243e57f 100644
--- a/ui/android/BUILD.gn
+++ b/ui/android/BUILD.gn
@@ -42,10 +42,6 @@
     "ui_android_jni_registrar.h",
     "view_android.cc",
     "view_android.h",
-    "view_client.cc",
-    "view_client.h",
-    "view_root.cc",
-    "view_root.h",
     "window_android.cc",
     "window_android.h",
     "window_android_compositor.h",
@@ -85,7 +81,6 @@
   sources = [
     "java/src/org/chromium/ui/OverscrollRefreshHandler.java",
     "java/src/org/chromium/ui/base/ViewAndroidDelegate.java",
-    "java/src/org/chromium/ui/base/ViewRoot.java",
     "java/src/org/chromium/ui/base/WindowAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroidManager.java",
     "java/src/org/chromium/ui/resources/ResourceManager.java",
@@ -181,7 +176,6 @@
     "java/src/org/chromium/ui/base/SelectFileDialog.java",
     "java/src/org/chromium/ui/base/TouchDevice.java",
     "java/src/org/chromium/ui/base/ViewAndroidDelegate.java",
-    "java/src/org/chromium/ui/base/ViewRoot.java",
     "java/src/org/chromium/ui/base/WindowAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroid.java",
     "java/src/org/chromium/ui/display/DisplayAndroidManager.java",
@@ -252,7 +246,6 @@
     "overscroll_refresh_unittest.cc",
     "resources/resource_manager_impl_unittest.cc",
     "run_all_unittests.cc",
-    "view_android_unittest.cc",
   ]
   deps = [
     ":android",
diff --git a/ui/android/java/src/org/chromium/ui/base/ViewRoot.java b/ui/android/java/src/org/chromium/ui/base/ViewRoot.java
deleted file mode 100644
index 291c3af..0000000
--- a/ui/android/java/src/org/chromium/ui/base/ViewRoot.java
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.ui.base;
-
-import android.view.MotionEvent;
-
-import org.chromium.base.annotations.JNINamespace;
-
-/**
- * Class used to forward view, input events down to native.
- * TODO(jinsukkim): Hook this up to UI event forwarding flow and substitute WindowAndroid.
- */
-@JNINamespace("ui")
-public class ViewRoot {
-
-    private final WindowAndroid mWindowAndroid;
-
-    // The corresponding native instance. This class can only be used while
-    // the native instance is alive.
-    // This is initialized lazily. Use {@link getNativePtr()} rather than
-    // accessing it directly.
-    private long mNativeView;
-
-    public static ViewRoot create(WindowAndroid window) {
-        if (window == null) throw new IllegalArgumentException("WindowAndroid should not be null");
-        return new ViewRoot(window);
-    }
-
-    private ViewRoot(WindowAndroid window) {
-        mWindowAndroid = window;
-    }
-
-    public WindowAndroid getWindowAndroid() {
-        return mWindowAndroid;
-    }
-
-    public boolean onTouchEvent(MotionEvent event, boolean isTouchHandleEvent) {
-        final int pointerCount = event.getPointerCount();
-
-        float[] touchMajor = {event.getTouchMajor(),
-                              pointerCount > 1 ? event.getTouchMajor(1) : 0};
-        float[] touchMinor = {event.getTouchMinor(),
-                              pointerCount > 1 ? event.getTouchMinor(1) : 0};
-
-        for (int i = 0; i < 2; i++) {
-            if (touchMajor[i] < touchMinor[i]) {
-                float tmp = touchMajor[i];
-                touchMajor[i] = touchMinor[i];
-                touchMinor[i] = tmp;
-            }
-        }
-
-        return nativeOnTouchEvent(getNativePtr(), event,
-                event.getEventTime(), event.getActionMasked(),
-                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,
-                touchMajor[0], touchMajor[1],
-                touchMinor[0], touchMinor[1],
-                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(),
-                isTouchHandleEvent);
-    }
-
-    public long getNativePtr() {
-        if (mNativeView == 0) mNativeView = nativeInit(mWindowAndroid.getNativePointer());
-        return mNativeView;
-    }
-
-    public void destroy() {
-        if (mNativeView != 0) {
-            nativeDestroy(mNativeView);
-            mNativeView = 0;
-        }
-    }
-
-    private native long nativeInit(long windowNativePointer);
-    private native void nativeDestroy(long nativeViewRoot);
-
-    // All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
-    private native boolean nativeOnTouchEvent(
-            long nativeViewRoot, 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,
-            boolean isTouchHandleEvent);
-}
diff --git a/ui/android/ui_android_jni_registrar.cc b/ui/android/ui_android_jni_registrar.cc
index 1534cd5..3c02c50 100644
--- a/ui/android/ui_android_jni_registrar.cc
+++ b/ui/android/ui_android_jni_registrar.cc
@@ -10,7 +10,6 @@
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/android/screen_android.h"
 #include "ui/android/view_android.h"
-#include "ui/android/view_root.h"
 #include "ui/android/window_android.h"
 
 namespace ui {
@@ -18,7 +17,6 @@
 static base::android::RegistrationMethod kAndroidRegisteredMethods[] = {
     {"DisplayAndroidManager", ui::RegisterScreenAndroid},
     {"ResourceManager", ui::ResourceManagerImpl::RegisterResourceManager},
-    {"ViewRoot", ui::RegisterViewRoot},
     {"WindowAndroid", WindowAndroid::RegisterWindowAndroid},
 };
 
diff --git a/ui/android/view_android.cc b/ui/android/view_android.cc
index 43f084f..251c165 100644
--- a/ui/android/view_android.cc
+++ b/ui/android/view_android.cc
@@ -18,7 +18,6 @@
 using base::android::JavaRef;
 using base::android::ScopedJavaLocalRef;
 
-// ViewAndroid::ScopedAndroidView
 ViewAndroid::ScopedAnchorView::ScopedAnchorView(
     JNIEnv* env,
     const JavaRef<jobject>& jview,
@@ -69,65 +68,43 @@
   return view_.get(env);
 }
 
-// ViewAndroid
-ViewAndroid::ViewAndroid(ViewClient* client) : parent_(nullptr),
-                                               client_(client) {}
-ViewAndroid::ViewAndroid() : ViewAndroid(nullptr) {}
+ViewAndroid::ViewAndroid(const JavaRef<jobject>& delegate)
+    : parent_(nullptr),
+      delegate_(base::android::AttachCurrentThread(), delegate.obj()) {}
+
+ViewAndroid::ViewAndroid() : parent_(nullptr) {}
 
 ViewAndroid::~ViewAndroid() {
   RemoveFromParent();
 
-  auto children_copy = std::list<ViewAndroid*>(children_);
-  for (auto& child : children_copy)
-    RemoveChild(child);
+  for (std::list<ViewAndroid*>::iterator it = children_.begin();
+       it != children_.end(); it++) {
+    DCHECK_EQ((*it)->parent_, this);
+    (*it)->parent_ = nullptr;
+  }
 }
 
 void ViewAndroid::SetDelegate(const JavaRef<jobject>& delegate) {
-  // A ViewAndroid may have its own delegate or otherwise will
-  // use the next available parent's delegate.
   JNIEnv* env = base::android::AttachCurrentThread();
   delegate_ = JavaObjectWeakGlobalRef(env, delegate);
 }
 
 void ViewAndroid::AddChild(ViewAndroid* child) {
   DCHECK(child);
-  DCHECK(!child->IsViewRoot());  // ViewRoot cannot be a child.
   DCHECK(std::find(children_.begin(), children_.end(), child) ==
          children_.end());
 
-  // The new child goes to the top, which is the end of the list.
   children_.push_back(child);
   if (child->parent_)
     child->RemoveFromParent();
   child->parent_ = this;
 }
 
-void ViewAndroid::MoveToTop(ViewAndroid* child) {
-  DCHECK(child);
-  auto it = std::find(children_.begin(), children_.end(), child);
-  DCHECK(it != children_.end());
-
-  // Top element is placed at the end of the list.
-  if (*it != children_.back())
-    children_.splice(children_.rbegin().base(), children_, it);
-}
-
 void ViewAndroid::RemoveFromParent() {
   if (parent_)
     parent_->RemoveChild(this);
 }
 
-void ViewAndroid::SetLayout(int x,
-                            int y,
-                            int width,
-                            int height,
-                            bool match_parent) {
-  DCHECK(!match_parent || (x == 0 && y == 0 && width == 0 && height == 0));
-  origin_.SetPoint(x, y);
-  size_.SetSize(width, height);
-  match_parent_ = match_parent;
-}
-
 ViewAndroid::ScopedAnchorView ViewAndroid::AcquireAnchorView() {
   ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
   if (delegate.is_null())
@@ -138,19 +115,15 @@
       env, Java_ViewAndroidDelegate_acquireView(env, delegate), delegate);
 }
 
-float ViewAndroid::GetDipScale() {
-  return display::Screen::GetScreen()
-      ->GetDisplayNearestWindow(this)
-      .device_scale_factor();
-}
-
 void ViewAndroid::SetAnchorRect(const JavaRef<jobject>& anchor,
                                 const gfx::RectF& bounds) {
   ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
   if (delegate.is_null())
     return;
 
-  float scale = GetDipScale();
+  float scale = display::Screen::GetScreen()
+                    ->GetDisplayNearestWindow(this)
+                    .device_scale_factor();
   int left_margin = std::round(bounds.x() * scale);
   int top_margin = std::round((content_offset().y() + bounds.y()) * scale);
   JNIEnv* env = base::android::AttachCurrentThread();
@@ -201,14 +174,6 @@
   layer_ = layer;
 }
 
-ViewAndroid* ViewAndroid::GetViewRoot() {
-  return parent_ ? parent_->GetViewRoot() : nullptr;
-}
-
-bool ViewAndroid::IsViewRoot() {
-  return GetViewRoot() == this;
-}
-
 bool ViewAndroid::StartDragAndDrop(const JavaRef<jstring>& jtext,
                                    const JavaRef<jobject>& jimage) {
   ScopedJavaLocalRef<jobject> delegate(GetViewAndroidDelegate());
@@ -219,26 +184,4 @@
                                                    jimage);
 }
 
-bool ViewAndroid::OnTouchEventInternal(const MotionEventData& event) {
-  if (!children_.empty()) {
-    const MotionEventData& e =
-      origin_.IsOrigin() ? event : event.Offset(-origin_.x(), -origin_.y());
-
-    for (auto it = children_.rbegin(); it != children_.rend(); ++it) {
-      bool matched = (*it)->match_parent_;
-      if (!matched) {
-        gfx::Rect bound((*it)->origin_, (*it)->size_);
-        matched = bound.Contains(e.GetX(), e.GetY());
-      }
-      if (matched && (*it)->OnTouchEventInternal(e))
-        return true;
-    }
-  }
-
-  if (client_ && client_->OnTouchEvent(event))
-    return true;
-
-  return false;
-}
-
 }  // namespace ui
diff --git a/ui/android/view_android.h b/ui/android/view_android.h
index e446048..68adf34 100644
--- a/ui/android/view_android.h
+++ b/ui/android/view_android.h
@@ -10,7 +10,6 @@
 #include "base/android/jni_weak_ref.h"
 #include "base/memory/ref_counted.h"
 #include "ui/android/ui_android_export.h"
-#include "ui/android/view_client.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace cc {
@@ -23,8 +22,6 @@
 
 // A simple container for a UI layer.
 // At the root of the hierarchy is a WindowAndroid, when attached.
-// TODO(jinsukkim): Replace WindowAndroid with ViewRoot for the root of the
-//     view hierarchy. See https://crbug.com/671401
 class UI_ANDROID_EXPORT ViewAndroid {
  public:
   // Stores an anchored view to delete itself at the end of its lifetime
@@ -57,7 +54,9 @@
     // Default copy/assign disabled by move constructor.
   };
 
-  explicit ViewAndroid(ViewClient* client);
+  // A ViewAndroid may have its own delegate or otherwise will
+  // use the next available parent's delegate.
+  ViewAndroid(const base::android::JavaRef<jobject>& delegate);
 
   ViewAndroid();
   virtual ~ViewAndroid();
@@ -76,29 +75,18 @@
   // if disconnected.
   virtual WindowAndroid* GetWindowAndroid() const;
 
-  // Returns |ViewRoot| of this hierarchy. |null| if the hierarchy isn't
-  // attached to a |ViewRoot|.
-  virtual ViewAndroid* GetViewRoot();
-
   // Used to return and set the layer for this view. May be |null|.
   cc::Layer* GetLayer() const;
   void SetLayer(scoped_refptr<cc::Layer> layer);
 
   void SetDelegate(const base::android::JavaRef<jobject>& delegate);
 
-  // Adds a child to this view.
+  // Adds this view as a child of another view.
   void AddChild(ViewAndroid* child);
 
-  // Move the give child ViewAndroid to the top of the list
-  // so that it can be the first responder of events.
-  void MoveToTop(ViewAndroid* child);
-
   // Detaches this view from its parent.
   void RemoveFromParent();
 
-  // Set the layout relative to parent. Used to do hit testing against events.
-  void SetLayout(int x, int y, int width, int height, bool match_parent);
-
   bool StartDragAndDrop(const base::android::JavaRef<jstring>& jtext,
                         const base::android::JavaRef<jobject>& jimage);
 
@@ -110,18 +98,9 @@
   base::android::ScopedJavaLocalRef<jobject> GetContainerView();
 
  protected:
-  // Internal implementation of ViewClient forwarding calls to the interface.
-  bool OnTouchEventInternal(const MotionEventData& event);
-
-  // Virtual for testing.
-  virtual float GetDipScale();
-
   ViewAndroid* parent_;
 
  private:
-  // Returns true only if this is of type |ViewRoot|.
-  bool IsViewRoot();
-
   void RemoveChild(ViewAndroid* child);
 
   // Returns the Java delegate for this view. This is used to delegate work
@@ -130,19 +109,10 @@
   const base::android::ScopedJavaLocalRef<jobject>
       GetViewAndroidDelegate() const;
 
-  // The child view at the back of the list receives event first.
   std::list<ViewAndroid*> children_;
   scoped_refptr<cc::Layer> layer_;
   JavaObjectWeakGlobalRef delegate_;
-  ViewClient* const client_;
-
-  // Basic view layout information. Used to do hit testing deciding whether
-  // the passed events should be processed by the view.
-  gfx::Point origin_;  // In parent's coordinate space.
-  gfx::Size size_;
-  bool match_parent_;  // Bounds matches that of the parent if true.
-
-  gfx::Vector2dF content_offset_;  // In CSS pixel.
+  gfx::Vector2dF content_offset_;  // in CSS pixel
 
   DISALLOW_COPY_AND_ASSIGN(ViewAndroid);
 };
diff --git a/ui/android/view_android_unittest.cc b/ui/android/view_android_unittest.cc
deleted file mode 100644
index e4500b5..0000000
--- a/ui/android/view_android_unittest.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/android/view_root.h"
-
-namespace ui {
-
-using base::android::JavaParamRef;
-
-class TestViewRoot : public ViewRoot {
- public:
-  TestViewRoot() : ViewRoot(0L) {}
-  float GetDipScale() override { return 1.f; }
-};
-
-class TestViewClient : public ViewClient {
- public:
-  TestViewClient() : handle_event_(true),
-                     called_(false) {}
-
-  void SetHandleEvent(bool handle_event) { handle_event_ = handle_event; }
-  bool OnTouchEvent(const MotionEventData& event) override {
-    called_ = true;
-    return handle_event_;
-  }
-
-  bool EventHandled() { return called_ && handle_event_; }
-  void Reset() { called_ = false; }
-
- private:
-  bool handle_event_;  // Marks as event was consumed. True by default.
-  bool called_;
-};
-
-class ViewAndroidBoundsTest : public testing::Test {
- public:
-  ViewAndroidBoundsTest() : view1_(&client1_),
-                            view2_(&client2_),
-                            view3_(&client3_) {}
-  void Reset() {
-    client1_.Reset();
-    client2_.Reset();
-    client3_.Reset();
-  }
-
-  void GenerateTouchEventAt(float x, float y) {
-    root_.OnTouchEvent(nullptr,
-                       JavaParamRef<jobject>(nullptr),
-                       JavaParamRef<jobject>(nullptr),
-                       0L, // time
-                       0, 1, 0, 0,
-                       x, y, 0.f, 0.f, // pos
-                       0, 0,  // pointer_id
-                       0.f, 0.f, 0.f, 0.f,  // touch
-                       0.f, 0.f, 0.f, 0.f,
-                       0.f, 0.f,
-                       0, 0, 0, 0,
-                       false);
-  }
-
-  void ExpectHit(const TestViewClient& hitClient) {
-    TestViewClient* clients[3] = { &client1_, &client2_, &client3_ };
-    for (auto& client : clients) {
-      if (&hitClient == client)
-        EXPECT_TRUE(client->EventHandled());
-      else
-        EXPECT_FALSE(client->EventHandled());
-    }
-    Reset();
-  }
-
-  TestViewRoot root_;
-  TestViewClient client1_;
-  TestViewClient client2_;
-  TestViewClient client3_;
-  ViewAndroid view1_;
-  ViewAndroid view2_;
-  ViewAndroid view3_;
-};
-
-TEST_F(ViewAndroidBoundsTest, MatchesViewInFront) {
-  view1_.SetLayout(50, 50, 400, 600, false);
-  view2_.SetLayout(50, 50, 400, 600, false);
-  root_.AddChild(&view2_);
-  root_.AddChild(&view1_);
-
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client1_);
-
-  // View 2 moves up to the top, and events should hit it from now.
-  root_.MoveToTop(&view2_);
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client2_);
-}
-
-TEST_F(ViewAndroidBoundsTest, MatchesViewArea) {
-  view1_.SetLayout(50, 50, 200, 200, false);
-  view2_.SetLayout(20, 20, 400, 600, false);
-
-  root_.AddChild(&view2_);
-  root_.AddChild(&view1_);
-
-  // Falls within |view1_|'s bounds
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client1_);
-
-  // Falls within |view2_|'s bounds
-  GenerateTouchEventAt(300.f, 400.f);
-  ExpectHit(client2_);
-}
-
-TEST_F(ViewAndroidBoundsTest, MatchesViewAfterMove) {
-  view1_.SetLayout(50, 50, 200, 200, false);
-  view2_.SetLayout(20, 20, 400, 600, false);
-  root_.AddChild(&view2_);
-  root_.AddChild(&view1_);
-
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client1_);
-
-  view1_.SetLayout(150, 150, 200, 200, false);
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client2_);
-}
-
-TEST_F(ViewAndroidBoundsTest, MatchesViewSizeOfkMatchParent) {
-  view1_.SetLayout(20, 20, 400, 600, false);
-  view3_.SetLayout(0, 0, 0, 0, true);  // match parent
-  view2_.SetLayout(50, 50, 200, 200, false);
-
-  root_.AddChild(&view1_);
-  root_.AddChild(&view2_);
-  view1_.AddChild(&view3_);
-
-  GenerateTouchEventAt(100.f, 100.f);
-  ExpectHit(client2_);
-
-  GenerateTouchEventAt(300.f, 400.f);
-  ExpectHit(client3_);
-
-  client3_.SetHandleEvent(false);
-  GenerateTouchEventAt(300.f, 400.f);
-  ExpectHit(client1_);
-}
-
-TEST_F(ViewAndroidBoundsTest, MatchesViewsWithOffset) {
-  view1_.SetLayout(10, 20, 150, 100, false);
-  view2_.SetLayout(20, 30, 40, 30, false);
-  view3_.SetLayout(70, 30, 40, 30, false);
-
-  root_.AddChild(&view1_);
-  view1_.AddChild(&view2_);
-  view1_.AddChild(&view3_);
-
-  GenerateTouchEventAt(70, 30);
-  ExpectHit(client1_);
-
-  GenerateTouchEventAt(40, 60);
-  ExpectHit(client2_);
-
-  GenerateTouchEventAt(100, 70);
-  ExpectHit(client3_);
-}
-
-}  // namespace ui
diff --git a/ui/android/view_client.cc b/ui/android/view_client.cc
deleted file mode 100644
index b2442b1..0000000
--- a/ui/android/view_client.cc
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/android/view_client.h"
-
-namespace ui {
-
-MotionEventData::MotionEventData(float dip_scale,
-                                 jobject jevent,
-                                 long time,
-                                 int action,
-                                 int pointer_count,
-                                 int history_size,
-                                 int action_index,
-                                 float pos_x0,
-                                 float pos_y0,
-                                 float pos_x1,
-                                 float pos_y1,
-                                 int pointer_id_0,
-                                 int pointer_id_1,
-                                 float touch_major_0,
-                                 float touch_major_1,
-                                 float touch_minor_0,
-                                 float touch_minor_1,
-                                 float orientation_0,
-                                 float orientation_1,
-                                 float tilt_0,
-                                 float tilt_1,
-                                 float raw_pos_x,
-                                 float raw_pos_y,
-                                 int tool_type_0,
-                                 int tool_type_1,
-                                 int button_state,
-                                 int meta_state,
-                                 bool is_touch_handle_event) :
-    dip_scale_(dip_scale),
-    jevent_(jevent),
-    time_(time),
-    action_(action),
-    pointer_count_(pointer_count),
-    history_size_(history_size),
-    action_index_(action_index),
-    pos_x0_(pos_x0),
-    pos_y0_(pos_y0),
-    pos_x1_(pos_x1),
-    pos_y1_(pos_y1),
-    pointer_id_0_(pointer_id_0),
-    pointer_id_1_(pointer_id_1),
-    touch_major_0_(touch_major_0),
-    touch_major_1_(touch_major_1),
-    touch_minor_0_(touch_minor_0),
-    touch_minor_1_(touch_minor_1),
-    orientation_0_(orientation_0),
-    orientation_1_(orientation_1),
-    tilt_0_(tilt_0),
-    tilt_1_(tilt_1),
-    raw_pos_x_(raw_pos_x),
-    raw_pos_y_(raw_pos_y),
-    tool_type_0_(tool_type_0),
-    tool_type_1_(tool_type_1),
-    button_state_(button_state),
-    meta_state_(meta_state),
-    is_touch_handle_event_(is_touch_handle_event) {}
-
-MotionEventData::MotionEventData(const MotionEventData& other) :
-    dip_scale_(other.dip_scale_),
-    jevent_(other.jevent_),
-    time_(other.time_),
-    action_(other.action_),
-    pointer_count_(other.pointer_count_),
-    history_size_(other.history_size_),
-    action_index_(other.action_index_),
-    pos_x0_(other.pos_x0_),
-    pos_y0_(other.pos_y0_),
-    pos_x1_(other.pos_x1_),
-    pos_y1_(other.pos_y1_),
-    pointer_id_0_(other.pointer_id_0_),
-    pointer_id_1_(other.pointer_id_1_),
-    touch_major_0_(other.touch_major_0_),
-    touch_major_1_(other.touch_major_1_),
-    touch_minor_0_(other.touch_minor_0_),
-    touch_minor_1_(other.touch_minor_1_),
-    orientation_0_(other.orientation_0_),
-    orientation_1_(other.orientation_1_),
-    tilt_0_(other.tilt_0_),
-    tilt_1_(other.tilt_1_),
-    raw_pos_x_(other.raw_pos_x_),
-    raw_pos_y_(other.raw_pos_y_),
-    tool_type_0_(other.tool_type_0_),
-    tool_type_1_(other.tool_type_1_),
-    button_state_(other.button_state_),
-    meta_state_(other.meta_state_),
-    is_touch_handle_event_(other.is_touch_handle_event_) {}
-
-MotionEventData MotionEventData::Offset(float delta_x, float delta_y) const {
-  return MotionEventData(dip_scale_,
-                         jevent_,
-                         time_,
-                         action_,
-                         pointer_count_,
-                         history_size_,
-                         action_index_,
-                         pos_x0_ + delta_x,
-                         pos_y0_ + delta_y,
-                         pos_x1_ + delta_x,
-                         pos_y1_ + delta_y,
-                         pointer_id_0_,
-                         pointer_id_1_,
-                         touch_major_0_,
-                         touch_major_1_,
-                         touch_minor_0_,
-                         touch_minor_1_,
-                         orientation_0_,
-                         orientation_1_,
-                         tilt_0_,
-                         tilt_1_,
-                         raw_pos_x_,
-                         raw_pos_y_,
-                         tool_type_0_,
-                         tool_type_1_,
-                         button_state_,
-                         meta_state_,
-                         is_touch_handle_event_);
-}
-
-bool ViewClient::OnTouchEvent(const MotionEventData& event) { return false; }
-
-}  // namespace ui
diff --git a/ui/android/view_client.h b/ui/android/view_client.h
deleted file mode 100644
index fb7f79c..0000000
--- a/ui/android/view_client.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ANDROID_VIEW_CLIENT_H_
-#define UI_ANDROID_VIEW_CLIENT_H_
-
-#include <jni.h>
-
-#include "ui/android/ui_android_export.h"
-
-namespace ui {
-
-// Container of motion event data. Used when traversing views along their
-// hierarchy. Actual motion event object will be constructed right before
-// it is used in the |ViewClient| implementation to avoid creating multiple
-// |MotionEventAndroid| instances.
-struct MotionEventData {
-  MotionEventData(float dip_scale,
-                  jobject jevent,
-                  long time,
-                  int action,
-                  int pointer_count,
-                  int history_size,
-                  int action_index,
-                  float pos_x0,
-                  float pos_y0,
-                  float pos_x1,
-                  float pos_y1,
-                  int pointer_id_0,
-                  int pointer_id_1,
-                  float touch_major_0,
-                  float touch_major_1,
-                  float touch_minor_0,
-                  float touch_minor_1,
-                  float orientation_0,
-                  float orientation_1,
-                  float tilt_0,
-                  float tilt_1,
-                  float raw_pos_x,
-                  float raw_pos_y,
-                  int tool_type_0,
-                  int tool_type_1,
-                  int button_state,
-                  int meta_state,
-                  bool is_touch_handle_event);
-
-  MotionEventData(const MotionEventData& other);
-
-  // Returns a new |MotionEventData| object whose position is offset
-  // by a given delta.
-  MotionEventData Offset(float delta_x, float delta_y) const;
-
-  float GetX() const { return pos_x0_ / dip_scale_; }
-  float GetY() const { return pos_y0_ / dip_scale_; }
-
-  const float dip_scale_;
-  const jobject jevent_;
-  const long time_; // ms
-  const int action_;
-  const int pointer_count_;
-  const int history_size_;
-  const int action_index_;
-
-  const float pos_x0_;  // in pixel unit
-  const float pos_y0_;
-  const float pos_x1_;
-  const float pos_y1_;
-
-  const int pointer_id_0_;
-  const int pointer_id_1_;
-  const float touch_major_0_;
-  const float touch_major_1_;
-  const float touch_minor_0_;
-  const float touch_minor_1_;
-  const float orientation_0_;
-  const float orientation_1_;
-  const float tilt_0_;
-  const float tilt_1_;
-  const float raw_pos_x_;
-  const float raw_pos_y_;
-  const int tool_type_0_;
-  const int tool_type_1_;
-  const int button_state_;
-  const int meta_state_;
-  const bool is_touch_handle_event_;
-};
-
-// Client interface used to forward events from Java to native views.
-// Calls are dispatched to its children along the hierarchy of ViewAndroid.
-// Use bool return type to stop propagating the call i.e. overriden method
-// should return true to indicate that the event was handled and stop
-// the processing.
-// Note: Not in use yet. Will be hooked up together with ViewRoot.
-//       See https://crbug.com/671401.
-class UI_ANDROID_EXPORT ViewClient {
- public:
-  virtual bool OnTouchEvent(const MotionEventData& event);
-};
-
-}  // namespace ui
-
-#endif  // UI_ANDROID_VIEW_CLIENT_H_
diff --git a/ui/android/view_root.cc b/ui/android/view_root.cc
deleted file mode 100644
index 1a1f977..0000000
--- a/ui/android/view_root.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/android/view_root.h"
-
-#include "jni/ViewRoot_jni.h"
-
-namespace ui {
-
-using base::android::JavaParamRef;
-
-ViewRoot::ViewRoot(jlong window_android_ptr) {
-  WindowAndroid* window_android =
-          reinterpret_cast<WindowAndroid*>(window_android_ptr);
-  window_ = window_android;
-
-  // ViewRoot simply accepts all events and lets the hit testing
-  // start from its children.
-  SetLayout(0, 0, 0, 0, true);
-}
-
-ViewAndroid* ViewRoot::GetViewRoot() {
-  return this;
-}
-
-WindowAndroid* ViewRoot::GetWindowAndroid() const {
-  return window_;
-}
-
-void ViewRoot::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  delete this;
-}
-
-jboolean ViewRoot::OnTouchEvent(JNIEnv* env,
-                                const JavaParamRef<jobject>& obj,
-                                const JavaParamRef<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,
-                                jboolean is_touch_handle_event) {
-  MotionEventData event(GetDipScale(),
-                        motion_event.obj(),
-                        time_ms,
-                        android_action,
-                        pointer_count,
-                        history_size,
-                        action_index,
-                        pos_x_0,
-                        pos_y_0,
-                        pos_x_1,
-                        pos_y_1,
-                        pointer_id_0,
-                        pointer_id_1,
-                        touch_major_0,
-                        touch_major_1,
-                        touch_minor_0,
-                        touch_minor_1,
-                        orientation_0,
-                        orientation_1,
-                        tilt_0,
-                        tilt_1,
-                        raw_pos_x,
-                        raw_pos_y,
-                        android_tool_type_0,
-                        android_tool_type_1,
-                        android_button_state,
-                        android_meta_state,
-                        is_touch_handle_event);
-  return OnTouchEventInternal(event);
-}
-
-// static
-jlong Init(JNIEnv* env,
-           const JavaParamRef<jobject>& obj,
-           jlong window_android_ptr) {
-  return reinterpret_cast<intptr_t>(new ViewRoot(window_android_ptr));
-}
-
-bool RegisterViewRoot(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-}  // namespace ui
diff --git a/ui/android/view_root.h b/ui/android/view_root.h
deleted file mode 100644
index 49007fa4..0000000
--- a/ui/android/view_root.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_ANDROID_VIEW_ROOT_H_
-#define UI_ANDROID_VIEW_ROOT_H_
-
-#include <jni.h>
-
-#include "base/android/scoped_java_ref.h"
-#include "ui/android/ui_android_export.h"
-#include "ui/android/view_android.h"
-
-namespace ui {
-
-// ViewRoot is the root of a ViewAndroid tree.
-// TODO(jinsukkim): Hook this up to UI event forwarding flow and
-//     substitute WindowAndroid. See https://crbug.com/671401
-class UI_ANDROID_EXPORT ViewRoot : public ViewAndroid {
- public:
-  explicit ViewRoot(jlong window_android_ptr);
-
-  // ViewAndroid overrides.
-  WindowAndroid* GetWindowAndroid() const override;
-  ViewAndroid* GetViewRoot() override;
-
-  void Destroy(JNIEnv* env,
-               const base::android::JavaParamRef<jobject>& obj);
-
-  jboolean OnTouchEvent(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<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,
-      jboolean is_touch_handle_event);
-
- private:
-  WindowAndroid* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(ViewRoot);
-};
-
-bool RegisterViewRoot(JNIEnv* env);
-
-}  // namespace ui
-
-#endif  // UI_ANDROID_VIEW_ROOT_H_
diff --git a/ui/arc/notification/arc_notification_item.cc b/ui/arc/notification/arc_notification_item.cc
index f67f33a..88cda841 100644
--- a/ui/arc/notification/arc_notification_item.cc
+++ b/ui/arc/notification/arc_notification_item.cc
@@ -271,6 +271,10 @@
       notification_key_, button_index);
 }
 
+void ArcNotificationItem::OpenSettings() {
+  manager_->OpenNotificationSettings(notification_key_);
+}
+
 // Converts from Android notification priority to Chrome notification priority.
 // On Android, PRIORITY_DEFAULT does not pop up, so this maps PRIORITY_DEFAULT
 // to Chrome's -1 to adapt that behavior. Also, this maps PRIORITY_LOW and _HIGH
diff --git a/ui/arc/notification/arc_notification_item.h b/ui/arc/notification/arc_notification_item.h
index b98632f..3df5e6a 100644
--- a/ui/arc/notification/arc_notification_item.h
+++ b/ui/arc/notification/arc_notification_item.h
@@ -38,6 +38,7 @@
   void Close(bool by_user);
   void Click();
   void ButtonClick(int button_index);
+  void OpenSettings();
 
   const std::string& notification_key() const { return notification_key_; }
 
diff --git a/ui/arc/notification/arc_notification_manager.cc b/ui/arc/notification/arc_notification_manager.cc
index 2d368ff..b4619203 100644
--- a/ui/arc/notification/arc_notification_manager.cc
+++ b/ui/arc/notification/arc_notification_manager.cc
@@ -115,7 +115,7 @@
   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service()->notifications(), SendNotificationEventToAndroid);
 
-  // On shutdown, the ARC channel may quit earlier then notifications.
+  // On shutdown, the ARC channel may quit earlier than notifications.
   if (!notifications_instance) {
     VLOG(2) << "ARC Notification (key: " << key
             << ") is closed, but the ARC channel has already gone.";
@@ -137,7 +137,7 @@
   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service()->notifications(), SendNotificationEventToAndroid);
 
-  // On shutdown, the ARC channel may quit earlier then notifications.
+  // On shutdown, the ARC channel may quit earlier than notifications.
   if (!notifications_instance) {
     VLOG(2) << "ARC Notification (key: " << key
             << ") is clicked, but the ARC channel has already gone.";
@@ -160,7 +160,7 @@
   auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
       arc_bridge_service()->notifications(), SendNotificationEventToAndroid);
 
-  // On shutdown, the ARC channel may quit earlier then notifications.
+  // On shutdown, the ARC channel may quit earlier than notifications.
   if (!notifications_instance) {
     VLOG(2) << "ARC Notification (key: " << key
             << ")'s button is clicked, but the ARC channel has already gone.";
@@ -223,6 +223,23 @@
   notifications_instance->CloseNotificationWindow(key);
 }
 
+void ArcNotificationManager::OpenNotificationSettings(const std::string& key) {
+  if (items_.find(key) == items_.end()) {
+    DVLOG(3) << "Chrome requests to fire a click event on the notification "
+             << "settings button (key: " << key << "), but it is gone.";
+    return;
+  }
+
+  auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc_bridge_service()->notifications(), OpenNotificationSettings);
+
+  // On shutdown, the ARC channel may quit earlier than notifications.
+  if (!notifications_instance)
+    return;
+
+  notifications_instance->OpenNotificationSettings(key);
+}
+
 void ArcNotificationManager::OnToastPosted(mojom::ArcToastDataPtr data) {
   const base::string16 text16(
       base::UTF8ToUTF16(data->text.has_value() ? *data->text : std::string()));
diff --git a/ui/arc/notification/arc_notification_manager.h b/ui/arc/notification/arc_notification_manager.h
index c05ce10..c0a886ab 100644
--- a/ui/arc/notification/arc_notification_manager.h
+++ b/ui/arc/notification/arc_notification_manager.h
@@ -52,6 +52,7 @@
                                              int button_index);
   void CreateNotificationWindow(const std::string& key);
   void CloseNotificationWindow(const std::string& key);
+  void OpenNotificationSettings(const std::string& key);
 
  private:
   const AccountId main_profile_id_;
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index b8e7cf7b..52f9cdfc 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -35,6 +35,7 @@
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kAppIdKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(int, kAppType, 0);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kConstrainedWindowKey, false);
+DEFINE_UI_CLASS_PROPERTY_KEY(bool, kCreatedByUserGesture, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImmersiveFullscreenKey, false);
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index 3c02cdd..664de048 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -49,6 +49,9 @@
 // A property key to store if a window is a constrained window or not.
 AURA_EXPORT extern const WindowProperty<bool>* const kConstrainedWindowKey;
 
+// A property key to store if a window was created by a user gesture.
+AURA_EXPORT extern const WindowProperty<bool>* const kCreatedByUserGesture;
+
 // A property key to indicate that a window should show that it deserves
 // attention.
 AURA_EXPORT extern const aura::WindowProperty<bool>* const kDrawAttentionKey;
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc
index 7a452e5..9787d57 100644
--- a/ui/aura/mus/property_converter.cc
+++ b/ui/aura/mus/property_converter.cc
@@ -70,7 +70,7 @@
   if (transport_name->empty())
     return false;
 
-  auto image_key = static_cast<const WindowProperty<gfx::ImageSkia*>*>(key);
+  auto* image_key = static_cast<const WindowProperty<gfx::ImageSkia*>*>(key);
   if (image_properties_.count(image_key) > 0) {
     const gfx::ImageSkia* value = window->GetProperty(image_key);
     if (value) {
@@ -84,25 +84,25 @@
     return true;
   }
 
-  auto rect_key = static_cast<const WindowProperty<gfx::Rect*>*>(key);
+  auto* rect_key = static_cast<const WindowProperty<gfx::Rect*>*>(key);
   if (rect_properties_.count(rect_key) > 0) {
     *transport_value = GetArray(window, rect_key);
     return true;
   }
 
-  auto size_key = static_cast<const WindowProperty<gfx::Size*>*>(key);
+  auto* size_key = static_cast<const WindowProperty<gfx::Size*>*>(key);
   if (size_properties_.count(size_key) > 0) {
     *transport_value = GetArray(window, size_key);
     return true;
   }
 
-  auto string_key = static_cast<const WindowProperty<std::string*>*>(key);
+  auto* string_key = static_cast<const WindowProperty<std::string*>*>(key);
   if (string_properties_.count(string_key) > 0) {
     *transport_value = GetArray(window, string_key);
     return true;
   }
 
-  auto string16_key = static_cast<const WindowProperty<base::string16*>*>(key);
+  auto* string16_key = static_cast<const WindowProperty<base::string16*>*>(key);
   if (string16_properties_.count(string16_key) > 0) {
     *transport_value = GetArray(window, string16_key);
     return true;
@@ -122,23 +122,23 @@
   if (primitive_properties_.count(key) > 0)
     return primitive_properties_[key].transport_name;
 
-  auto image_key = static_cast<const WindowProperty<gfx::ImageSkia*>*>(key);
+  auto* image_key = static_cast<const WindowProperty<gfx::ImageSkia*>*>(key);
   if (image_properties_.count(image_key) > 0)
     return image_properties_[image_key];
 
-  auto rect_key = static_cast<const WindowProperty<gfx::Rect*>*>(key);
+  auto* rect_key = static_cast<const WindowProperty<gfx::Rect*>*>(key);
   if (rect_properties_.count(rect_key) > 0)
     return rect_properties_[rect_key];
 
-  auto size_key = static_cast<const WindowProperty<gfx::Size*>*>(key);
+  auto* size_key = static_cast<const WindowProperty<gfx::Size*>*>(key);
   if (size_properties_.count(size_key) > 0)
     return size_properties_[size_key];
 
-  auto string_key = static_cast<const WindowProperty<std::string*>*>(key);
+  auto* string_key = static_cast<const WindowProperty<std::string*>*>(key);
   if (string_properties_.count(string_key) > 0)
     return string_properties_[string_key];
 
-  auto string16_key = static_cast<const WindowProperty<base::string16*>*>(key);
+  auto* string16_key = static_cast<const WindowProperty<base::string16*>*>(key);
   if (string16_properties_.count(string16_key) > 0)
     return string16_properties_[string16_key];
 
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index b1870ecb..f52ae02 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -1895,8 +1895,8 @@
   l1->SetAnimator(LayerAnimator::CreateImplicitAnimator());
   l2->SetAnimator(LayerAnimator::CreateImplicitAnimator());
 
-  auto player1 = l1->GetAnimator()->GetAnimationPlayerForTesting();
-  auto player2 = l2->GetAnimator()->GetAnimationPlayerForTesting();
+  auto* player1 = l1->GetAnimator()->GetAnimationPlayerForTesting();
+  auto* player2 = l2->GetAnimator()->GetAnimationPlayerForTesting();
 
   EXPECT_FALSE(player1->has_any_animation());
 
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index 4f0faf9..12ae29dc 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -82,11 +82,11 @@
   }
   void SwapBuffers(cc::OutputSurfaceFrame frame) override {
     DCHECK(context_provider_.get());
-    if (frame.sub_buffer_rect == gfx::Rect(frame.size)) {
-      context_provider_->ContextSupport()->Swap();
-    } else {
+    if (frame.sub_buffer_rect) {
       context_provider_->ContextSupport()->PartialSwapBuffers(
-          frame.sub_buffer_rect);
+          *frame.sub_buffer_rect);
+    } else {
+      context_provider_->ContextSupport()->Swap();
     }
     gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
     const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM();
diff --git a/ui/events/gestures/gesture_recognizer_impl.cc b/ui/events/gestures/gesture_recognizer_impl.cc
index 9f708fc..9be2e418 100644
--- a/ui/events/gestures/gesture_recognizer_impl.cc
+++ b/ui/events/gestures/gesture_recognizer_impl.cc
@@ -114,7 +114,7 @@
     consumers.push_back(entry.first);
   }
 
-  for (auto consumer : consumers)
+  for (auto* consumer : consumers)
     CancelActiveTouches(consumer);
 }
 
diff --git a/ui/gfx/android/OWNERS b/ui/gfx/android/OWNERS
index 1849050..0fc82371 100644
--- a/ui/gfx/android/OWNERS
+++ b/ui/gfx/android/OWNERS
@@ -1,2 +1,4 @@
 aelias@chromium.org
 skyostil@chromium.org
+
+# COMPONENT: UI>GFX
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index 1ccfe75..09d5dce0 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -259,6 +259,51 @@
   EXPECT_GT(tmp.z(), tmp.y());
 }
 
+TEST(SimpleColorSpace, ToUndefined) {
+  ColorSpace null;
+  ColorSpace nonnull = gfx::ColorSpace::CreateSRGB();
+  // Video should have 1 step: YUV to RGB.
+  // Anything else should have 0 steps.
+  ColorSpace video = gfx::ColorSpace::CreateREC709();
+  std::unique_ptr<ColorTransform> video_to_null(
+      ColorTransform::NewColorTransform(
+          video, null, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_EQ(video_to_null->NumberOfStepsForTesting(), 1u);
+
+  // Test with an ICC profile that can't be represented as matrix+transfer.
+  ColorSpace luttrcicc = ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
+  std::unique_ptr<ColorTransform> luttrcicc_to_null(
+      ColorTransform::NewColorTransform(
+          luttrcicc, null, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_EQ(luttrcicc_to_null->NumberOfStepsForTesting(), 0u);
+  std::unique_ptr<ColorTransform> luttrcicc_to_nonnull(
+      ColorTransform::NewColorTransform(
+          luttrcicc, nonnull, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_GT(luttrcicc_to_nonnull->NumberOfStepsForTesting(), 0u);
+
+  // Test with an ICC profile that can.
+  ColorSpace adobeicc = ICCProfileForTestingAdobeRGB().GetColorSpace();
+  std::unique_ptr<ColorTransform> adobeicc_to_null(
+      ColorTransform::NewColorTransform(
+          adobeicc, null, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_EQ(adobeicc_to_null->NumberOfStepsForTesting(), 0u);
+  std::unique_ptr<ColorTransform> adobeicc_to_nonnull(
+      ColorTransform::NewColorTransform(
+          adobeicc, nonnull, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_GT(adobeicc_to_nonnull->NumberOfStepsForTesting(), 0u);
+
+  // And with something analytic.
+  ColorSpace srgb = gfx::ColorSpace::CreateXYZD50();
+  std::unique_ptr<ColorTransform> srgb_to_null(
+      ColorTransform::NewColorTransform(
+          srgb, null, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_EQ(srgb_to_null->NumberOfStepsForTesting(), 0u);
+  std::unique_ptr<ColorTransform> srgb_to_nonnull(
+      ColorTransform::NewColorTransform(
+          srgb, nonnull, ColorTransform::Intent::INTENT_PERCEPTUAL));
+  EXPECT_GT(srgb_to_nonnull->NumberOfStepsForTesting(), 0u);
+}
+
 TEST(SimpleColorSpace, DefaultToSRGB) {
   // The default value should do no transformation, regardless of destination.
   ColorSpace unknown;
diff --git a/ui/gfx/icc_profile.cc b/ui/gfx/icc_profile.cc
index 9f04bd8..9390da6 100644
--- a/ui/gfx/icc_profile.cc
+++ b/ui/gfx/icc_profile.cc
@@ -18,6 +18,7 @@
 const uint64_t ICCProfile::test_id_color_spin_ = 2;
 const uint64_t ICCProfile::test_id_generic_rgb_ = 3;
 const uint64_t ICCProfile::test_id_srgb_ = 4;
+const uint64_t ICCProfile::test_id_no_analytic_tr_fn_ = 5;
 
 namespace {
 const size_t kMinProfileLength = 128;
@@ -33,7 +34,7 @@
   ~Cache() {}
 
   // Start from-ICC-data IDs at the end of the hard-coded test id list above.
-  uint64_t next_unused_id = 5;
+  uint64_t next_unused_id = 10;
   base::MRUCache<uint64_t, ICCProfile> id_to_icc_profile_mru;
   base::Lock lock;
 };
diff --git a/ui/gfx/icc_profile.h b/ui/gfx/icc_profile.h
index a07edf6..95ae024 100644
--- a/ui/gfx/icc_profile.h
+++ b/ui/gfx/icc_profile.h
@@ -75,10 +75,12 @@
   friend ICCProfile ICCProfileForTestingColorSpin();
   friend ICCProfile ICCProfileForTestingGenericRGB();
   friend ICCProfile ICCProfileForTestingSRGB();
+  friend ICCProfile ICCProfileForTestingNoAnalyticTrFn();
   static const uint64_t test_id_adobe_rgb_;
   static const uint64_t test_id_color_spin_;
   static const uint64_t test_id_generic_rgb_;
   static const uint64_t test_id_srgb_;
+  static const uint64_t test_id_no_analytic_tr_fn_;
 
   // Populate |icc_profile| with the ICCProfile corresponding to id |id|. Return
   // false if |id| is not in the cache. If |only_if_needed| is true, then return
diff --git a/ui/gfx/image/image_skia_operations.cc b/ui/gfx/image/image_skia_operations.cc
index 4f23d5601..f469b3c8 100644
--- a/ui/gfx/image/image_skia_operations.cc
+++ b/ui/gfx/image/image_skia_operations.cc
@@ -594,7 +594,7 @@
 ImageSkia ImageSkiaOperations::CreateHorizontalShadow(
     const std::vector<ShadowValue>& shadows,
     bool fades_down) {
-  auto source = new HorizontalShadowSource(shadows, fades_down);
+  auto* source = new HorizontalShadowSource(shadows, fades_down);
   return ImageSkia(source, source->size());
 }
 
diff --git a/ui/gfx/shadow_util.cc b/ui/gfx/shadow_util.cc
index 88b19fae0..04360f9 100644
--- a/ui/gfx/shadow_util.cc
+++ b/ui/gfx/shadow_util.cc
@@ -106,7 +106,7 @@
   // To see what this looks like for elevation 24, try this CSS:
   //   box-shadow: 0 24px 48px rgba(0, 0, 0, .24),
   //               0 0 24px rgba(0, 0, 0, .12);
-  auto source = new ShadowNineboxSource(shadow->values, corner_radius);
+  auto* source = new ShadowNineboxSource(shadow->values, corner_radius);
   shadow->ninebox_image = ImageSkia(source, source->size());
   return *shadow;
 }
diff --git a/ui/gfx/test/icc_profiles.cc b/ui/gfx/test/icc_profiles.cc
index 459ad54..ee7130f 100644
--- a/ui/gfx/test/icc_profiles.cc
+++ b/ui/gfx/test/icc_profiles.cc
@@ -535,6 +535,175 @@
     0x00, 0x00, 0x10, 0x2f, 0x00, 0x00, 0xbe, 0x9c};
 }
 
+unsigned char no_analytic_tr_fn_profile_data[] = {
+    0x00, 0x00, 0x07, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00,
+    0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, 0x20, 0x58, 0x59, 0x5a, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x61, 0x63, 0x73, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xf6, 0xd6,
+    0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
+    0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x34,
+    0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x14,
+    0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x38, 0x00, 0x00, 0x00, 0x14,
+    0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, 0x4c, 0x00, 0x00, 0x00, 0x14,
+    0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x02, 0x0c,
+    0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x03, 0x6c, 0x00, 0x00, 0x02, 0x0c,
+    0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x05, 0x78, 0x00, 0x00, 0x02, 0x0c,
+    0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x07, 0x84, 0x00, 0x00, 0x00, 0x14,
+    0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x07, 0x98, 0x00, 0x00, 0x00, 0x3c,
+    0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x18,
+    0x00, 0x00, 0x00, 0x1c, 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x53, 0x00, 0x6b, 0x00, 0x69,
+    0x00, 0x61, 0x00, 0x20, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x73, 0x04, 0x00, 0x00, 0x39, 0x77, 0x00, 0x00, 0x00, 0x4a,
+    0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xf1,
+    0x00, 0x00, 0xb8, 0xec, 0x00, 0x00, 0x0d, 0xb6, 0x58, 0x59, 0x5a, 0x20,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0xe1, 0x00, 0x00, 0x0d, 0x9d,
+    0x00, 0x00, 0xc5, 0x2d, 0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06, 0x00, 0x09,
+    0x00, 0x0c, 0x00, 0x0f, 0x00, 0x12, 0x00, 0x15, 0x00, 0x18, 0x00, 0x1b,
+    0x00, 0x1f, 0x00, 0x24, 0x00, 0x2b, 0x00, 0x34, 0x00, 0x3e, 0x00, 0x4a,
+    0x00, 0x58, 0x00, 0x68, 0x00, 0x79, 0x00, 0x8c, 0x00, 0xa1, 0x00, 0xb8,
+    0x00, 0xd1, 0x00, 0xeb, 0x01, 0x08, 0x01, 0x27, 0x01, 0x47, 0x01, 0x69,
+    0x01, 0x8e, 0x01, 0xb4, 0x01, 0xdd, 0x02, 0x07, 0x02, 0x33, 0x02, 0x62,
+    0x02, 0x92, 0x02, 0xc4, 0x02, 0xf9, 0x03, 0x2f, 0x03, 0x68, 0x03, 0xa2,
+    0x03, 0xdf, 0x04, 0x1d, 0x04, 0x5e, 0x04, 0xa0, 0x04, 0xe5, 0x05, 0x2c,
+    0x05, 0x75, 0x05, 0xbf, 0x06, 0x0c, 0x06, 0x5a, 0x06, 0xab, 0x06, 0xfd,
+    0x07, 0x51, 0x07, 0xa8, 0x08, 0x00, 0x08, 0x5a, 0x08, 0xb6, 0x09, 0x14,
+    0x09, 0x74, 0x09, 0xd5, 0x0a, 0x39, 0x0a, 0x9e, 0x0b, 0x05, 0x0b, 0x6e,
+    0x0b, 0xd9, 0x0c, 0x46, 0x0c, 0xb4, 0x0d, 0x24, 0x0d, 0x96, 0x0e, 0x0a,
+    0x0e, 0x7f, 0x0e, 0xf7, 0x0f, 0x6f, 0x0f, 0xea, 0x10, 0x65, 0x10, 0xe3,
+    0x11, 0x62, 0x11, 0xe2, 0x12, 0x65, 0x12, 0xe8, 0x13, 0x6d, 0x13, 0xf4,
+    0x14, 0x7c, 0x15, 0x05, 0x15, 0x90, 0x16, 0x1c, 0x16, 0xaa, 0x17, 0x39,
+    0x17, 0xca, 0x18, 0x5c, 0x18, 0xf1, 0x19, 0x86, 0x1a, 0x1d, 0x1a, 0xb7,
+    0x1b, 0x52, 0x1b, 0xf0, 0x1c, 0x8f, 0x1d, 0x31, 0x1d, 0xd6, 0x1e, 0x7d,
+    0x1f, 0x26, 0x1f, 0xd2, 0x20, 0x80, 0x21, 0x31, 0x21, 0xe4, 0x22, 0x9a,
+    0x23, 0x52, 0x24, 0x0d, 0x24, 0xca, 0x25, 0x8b, 0x26, 0x4e, 0x27, 0x14,
+    0x27, 0xde, 0x28, 0xaa, 0x29, 0x7a, 0x2a, 0x4c, 0x2b, 0x22, 0x2b, 0xfc,
+    0x2c, 0xd9, 0x2d, 0xb8, 0x2e, 0x9b, 0x2f, 0x81, 0x30, 0x69, 0x31, 0x54,
+    0x32, 0x42, 0x33, 0x32, 0x34, 0x25, 0x35, 0x1a, 0x36, 0x12, 0x37, 0x0d,
+    0x38, 0x09, 0x39, 0x07, 0x3a, 0x07, 0x3b, 0x09, 0x3c, 0x0d, 0x3d, 0x12,
+    0x3e, 0x19, 0x3f, 0x22, 0x40, 0x2e, 0x41, 0x3a, 0x42, 0x47, 0x43, 0x56,
+    0x44, 0x67, 0x45, 0x79, 0x46, 0x8d, 0x47, 0xa3, 0x48, 0xbb, 0x49, 0xd7,
+    0x4a, 0xf5, 0x4c, 0x13, 0x4d, 0x34, 0x4e, 0x58, 0x4f, 0x80, 0x50, 0xab,
+    0x51, 0xda, 0x53, 0x0c, 0x54, 0x44, 0x55, 0x7f, 0x56, 0xbe, 0x58, 0x02,
+    0x59, 0x4b, 0x5a, 0x99, 0x5b, 0xec, 0x5d, 0x45, 0x5e, 0xa2, 0x60, 0x03,
+    0x61, 0x67, 0x62, 0xcf, 0x64, 0x3b, 0x65, 0xab, 0x67, 0x1e, 0x68, 0x93,
+    0x6a, 0x05, 0x6b, 0x77, 0x6c, 0xe7, 0x6e, 0x57, 0x6f, 0xc7, 0x71, 0x38,
+    0x72, 0xaa, 0x74, 0x1b, 0x75, 0x8c, 0x76, 0xfe, 0x78, 0x71, 0x79, 0xe6,
+    0x7b, 0x5d, 0x7c, 0xd4, 0x7e, 0x4c, 0x7f, 0xc6, 0x81, 0x42, 0x82, 0xc2,
+    0x84, 0x48, 0x85, 0xd2, 0x87, 0x61, 0x88, 0xf4, 0x8a, 0x8c, 0x8c, 0x28,
+    0x8d, 0xc8, 0x8f, 0x6c, 0x91, 0x12, 0x92, 0xbd, 0x94, 0x6a, 0x96, 0x19,
+    0x97, 0xcb, 0x99, 0x80, 0x9b, 0x36, 0x9c, 0xee, 0x9e, 0xa7, 0xa0, 0x61,
+    0xa2, 0x1c, 0xa3, 0xda, 0xa5, 0x9a, 0xa7, 0x5f, 0xa9, 0x28, 0xaa, 0xf5,
+    0xac, 0xc5, 0xae, 0x95, 0xb0, 0x66, 0xb2, 0x38, 0xb4, 0x0c, 0xb5, 0xe5,
+    0xb7, 0xc5, 0xb9, 0xac, 0xbb, 0x9b, 0xbd, 0x90, 0xbf, 0x8a, 0xc1, 0x8a,
+    0xc3, 0x8f, 0xc5, 0x98, 0xc7, 0xa8, 0xc9, 0xbe, 0xcb, 0xdd, 0xce, 0x01,
+    0xd0, 0x23, 0xd2, 0x42, 0xd4, 0x63, 0xd6, 0x84, 0xd8, 0xa5, 0xda, 0xc7,
+    0xdc, 0xe9, 0xdf, 0x09, 0xe1, 0x26, 0xe3, 0x40, 0xe5, 0x58, 0xe7, 0x6c,
+    0xe9, 0x81, 0xeb, 0x94, 0xed, 0xa5, 0xef, 0xb5, 0xf1, 0xc4, 0xf3, 0xd1,
+    0xf5, 0xdd, 0xf7, 0xe6, 0xf9, 0xef, 0xfb, 0xf6, 0xfd, 0xfb, 0xff, 0xff,
+    0x63, 0x75, 0x72, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+    0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x07, 0x00, 0x09, 0x00, 0x0c,
+    0x00, 0x0f, 0x00, 0x13, 0x00, 0x18, 0x00, 0x1f, 0x00, 0x26, 0x00, 0x30,
+    0x00, 0x3a, 0x00, 0x46, 0x00, 0x54, 0x00, 0x63, 0x00, 0x73, 0x00, 0x85,
+    0x00, 0x99, 0x00, 0xae, 0x00, 0xc5, 0x00, 0xdd, 0x00, 0xf7, 0x01, 0x12,
+    0x01, 0x30, 0x01, 0x4e, 0x01, 0x6f, 0x01, 0x91, 0x01, 0xb5, 0x01, 0xdb,
+    0x02, 0x02, 0x02, 0x2b, 0x02, 0x56, 0x02, 0x83, 0x02, 0xb2, 0x02, 0xe2,
+    0x03, 0x14, 0x03, 0x48, 0x03, 0x7e, 0x03, 0xb6, 0x03, 0xef, 0x04, 0x2a,
+    0x04, 0x68, 0x04, 0xa7, 0x04, 0xe8, 0x05, 0x2b, 0x05, 0x70, 0x05, 0xb7,
+    0x06, 0x00, 0x06, 0x4b, 0x06, 0x98, 0x06, 0xe6, 0x07, 0x37, 0x07, 0x8a,
+    0x07, 0xdf, 0x08, 0x36, 0x08, 0x90, 0x08, 0xeb, 0x09, 0x48, 0x09, 0xa7,
+    0x0a, 0x08, 0x0a, 0x6c, 0x0a, 0xd1, 0x0b, 0x39, 0x0b, 0xa3, 0x0c, 0x0e,
+    0x0c, 0x7c, 0x0c, 0xed, 0x0d, 0x5f, 0x0d, 0xd4, 0x0e, 0x4a, 0x0e, 0xc3,
+    0x0f, 0x3e, 0x0f, 0xbc, 0x10, 0x3c, 0x10, 0xbd, 0x11, 0x42, 0x11, 0xc8,
+    0x12, 0x51, 0x12, 0xdc, 0x13, 0x69, 0x13, 0xf9, 0x14, 0x8b, 0x15, 0x20,
+    0x15, 0xb6, 0x16, 0x50, 0x16, 0xeb, 0x17, 0x88, 0x18, 0x28, 0x18, 0xca,
+    0x19, 0x6e, 0x1a, 0x16, 0x1a, 0xbe, 0x1b, 0x69, 0x1c, 0x16, 0x1c, 0xc6,
+    0x1d, 0x77, 0x1e, 0x2a, 0x1e, 0xdf, 0x1f, 0x96, 0x20, 0x4e, 0x21, 0x08,
+    0x21, 0xc4, 0x22, 0x81, 0x23, 0x3f, 0x23, 0xff, 0x24, 0xc0, 0x25, 0x82,
+    0x26, 0x47, 0x27, 0x0e, 0x27, 0xd6, 0x28, 0xa1, 0x29, 0x6d, 0x2a, 0x3b,
+    0x2b, 0x0d, 0x2b, 0xdf, 0x2c, 0xb2, 0x2d, 0x87, 0x2e, 0x5e, 0x2f, 0x37,
+    0x30, 0x11, 0x30, 0xed, 0x31, 0xcb, 0x32, 0xaa, 0x33, 0x8c, 0x34, 0x6f,
+    0x35, 0x56, 0x36, 0x3f, 0x37, 0x2a, 0x38, 0x18, 0x39, 0x09, 0x39, 0xfd,
+    0x3a, 0xf4, 0x3b, 0xf0, 0x3c, 0xef, 0x3d, 0xf1, 0x3e, 0xf7, 0x40, 0x00,
+    0x41, 0x0d, 0x42, 0x1d, 0x43, 0x31, 0x44, 0x49, 0x45, 0x64, 0x46, 0x82,
+    0x47, 0xa4, 0x48, 0xc9, 0x49, 0xf1, 0x4b, 0x1a, 0x4c, 0x46, 0x4d, 0x75,
+    0x4e, 0xa4, 0x4f, 0xd6, 0x51, 0x0a, 0x52, 0x40, 0x53, 0x78, 0x54, 0xb2,
+    0x55, 0xee, 0x57, 0x2d, 0x58, 0x6f, 0x59, 0xb3, 0x5a, 0xfa, 0x5c, 0x44,
+    0x5d, 0x91, 0x5e, 0xe2, 0x60, 0x35, 0x61, 0x8b, 0x62, 0xe4, 0x64, 0x3e,
+    0x65, 0x9c, 0x66, 0xfb, 0x68, 0x5b, 0x69, 0xbb, 0x6b, 0x1b, 0x6c, 0x7b,
+    0x6d, 0xda, 0x6f, 0x3a, 0x70, 0x9b, 0x71, 0xfd, 0x73, 0x61, 0x74, 0xc8,
+    0x76, 0x32, 0x77, 0x9f, 0x79, 0x0e, 0x7a, 0x7f, 0x7b, 0xf3, 0x7d, 0x6a,
+    0x7e, 0xe3, 0x80, 0x5f, 0x81, 0xdd, 0x83, 0x61, 0x84, 0xe9, 0x86, 0x75,
+    0x88, 0x06, 0x89, 0x9d, 0x8b, 0x37, 0x8c, 0xd8, 0x8e, 0x7d, 0x90, 0x28,
+    0x91, 0xd6, 0x93, 0x87, 0x95, 0x38, 0x96, 0xe9, 0x98, 0x9a, 0x9a, 0x4b,
+    0x9b, 0xfd, 0x9d, 0xb2, 0x9f, 0x69, 0xa1, 0x22, 0xa2, 0xde, 0xa4, 0x98,
+    0xa6, 0x53, 0xa8, 0x0d, 0xa9, 0xc7, 0xab, 0x80, 0xad, 0x3d, 0xae, 0xfe,
+    0xb0, 0xc3, 0xb2, 0x8d, 0xb4, 0x5d, 0xb6, 0x30, 0xb8, 0x0a, 0xb9, 0xec,
+    0xbb, 0xd8, 0xbd, 0xce, 0xbf, 0xcf, 0xc1, 0xd9, 0xc3, 0xed, 0xc6, 0x0d,
+    0xc8, 0x36, 0xca, 0x66, 0xcc, 0x9c, 0xce, 0xd6, 0xd1, 0x11, 0xd3, 0x4d,
+    0xd5, 0x89, 0xd7, 0xc2, 0xd9, 0xf9, 0xdc, 0x2d, 0xde, 0x5b, 0xe0, 0x83,
+    0xe2, 0xa1, 0xe4, 0xb6, 0xe6, 0xc7, 0xe8, 0xd1, 0xea, 0xd8, 0xec, 0xda,
+    0xee, 0xd8, 0xf0, 0xd1, 0xf2, 0xc6, 0xf4, 0xb6, 0xf6, 0xa2, 0xf8, 0x8b,
+    0xfa, 0x6e, 0xfc, 0x4e, 0xfe, 0x28, 0xff, 0xff, 0x63, 0x75, 0x72, 0x76,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
+    0x00, 0x03, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x13,
+    0x00, 0x19, 0x00, 0x20, 0x00, 0x28, 0x00, 0x31, 0x00, 0x3c, 0x00, 0x47,
+    0x00, 0x54, 0x00, 0x63, 0x00, 0x72, 0x00, 0x83, 0x00, 0x95, 0x00, 0xa9,
+    0x00, 0xbe, 0x00, 0xd4, 0x00, 0xec, 0x01, 0x06, 0x01, 0x21, 0x01, 0x3d,
+    0x01, 0x5b, 0x01, 0x7a, 0x01, 0x9b, 0x01, 0xbe, 0x01, 0xe2, 0x02, 0x08,
+    0x02, 0x2f, 0x02, 0x58, 0x02, 0x83, 0x02, 0xb0, 0x02, 0xde, 0x03, 0x0e,
+    0x03, 0x3f, 0x03, 0x72, 0x03, 0xa8, 0x03, 0xde, 0x04, 0x17, 0x04, 0x52,
+    0x04, 0x8e, 0x04, 0xcc, 0x05, 0x0c, 0x05, 0x4e, 0x05, 0x92, 0x05, 0xd8,
+    0x06, 0x1f, 0x06, 0x69, 0x06, 0xb5, 0x07, 0x02, 0x07, 0x52, 0x07, 0xa3,
+    0x07, 0xf7, 0x08, 0x4d, 0x08, 0xa5, 0x08, 0xff, 0x09, 0x5b, 0x09, 0xb9,
+    0x0a, 0x19, 0x0a, 0x7c, 0x0a, 0xe0, 0x0b, 0x47, 0x0b, 0xb0, 0x0c, 0x1c,
+    0x0c, 0x8a, 0x0c, 0xfa, 0x0d, 0x6c, 0x0d, 0xe1, 0x0e, 0x58, 0x0e, 0xd1,
+    0x0f, 0x4d, 0x0f, 0xcb, 0x10, 0x4c, 0x10, 0xcf, 0x11, 0x55, 0x11, 0xdd,
+    0x12, 0x68, 0x12, 0xf5, 0x13, 0x85, 0x14, 0x17, 0x14, 0xac, 0x15, 0x44,
+    0x15, 0xe0, 0x16, 0x7c, 0x17, 0x1a, 0x17, 0xba, 0x18, 0x5c, 0x19, 0x00,
+    0x19, 0xa6, 0x1a, 0x4d, 0x1a, 0xf7, 0x1b, 0xa2, 0x1c, 0x50, 0x1d, 0x00,
+    0x1d, 0xb1, 0x1e, 0x65, 0x1f, 0x1a, 0x1f, 0xd1, 0x20, 0x89, 0x21, 0x43,
+    0x21, 0xfe, 0x22, 0xba, 0x23, 0x78, 0x24, 0x37, 0x24, 0xf6, 0x25, 0xb7,
+    0x26, 0x7a, 0x27, 0x3d, 0x28, 0x02, 0x28, 0xc8, 0x29, 0x8f, 0x2a, 0x58,
+    0x2b, 0x22, 0x2b, 0xee, 0x2c, 0xbc, 0x2d, 0x8e, 0x2e, 0x62, 0x2f, 0x38,
+    0x30, 0x12, 0x30, 0xee, 0x31, 0xce, 0x32, 0xb0, 0x33, 0x95, 0x34, 0x7d,
+    0x35, 0x67, 0x36, 0x54, 0x37, 0x44, 0x38, 0x37, 0x39, 0x2c, 0x3a, 0x25,
+    0x3b, 0x21, 0x3c, 0x20, 0x3d, 0x23, 0x3e, 0x2a, 0x3f, 0x34, 0x40, 0x42,
+    0x41, 0x52, 0x42, 0x64, 0x43, 0x78, 0x44, 0x8e, 0x45, 0xa6, 0x46, 0xc0,
+    0x47, 0xdb, 0x48, 0xf9, 0x4a, 0x17, 0x4b, 0x37, 0x4c, 0x58, 0x4d, 0x7b,
+    0x4e, 0x9f, 0x4f, 0xc5, 0x50, 0xee, 0x52, 0x18, 0x53, 0x45, 0x54, 0x74,
+    0x55, 0xa4, 0x56, 0xd9, 0x58, 0x12, 0x59, 0x50, 0x5a, 0x93, 0x5b, 0xdb,
+    0x5d, 0x28, 0x5e, 0x7b, 0x5f, 0xd3, 0x61, 0x31, 0x62, 0x93, 0x63, 0xf9,
+    0x65, 0x64, 0x66, 0xd3, 0x68, 0x46, 0x69, 0xbb, 0x6b, 0x34, 0x6c, 0xab,
+    0x6e, 0x21, 0x6f, 0x95, 0x71, 0x08, 0x72, 0x7a, 0x73, 0xeb, 0x75, 0x5d,
+    0x76, 0xce, 0x78, 0x3e, 0x79, 0xae, 0x7b, 0x1e, 0x7c, 0x8c, 0x7d, 0xfa,
+    0x7f, 0x67, 0x80, 0xd5, 0x82, 0x4a, 0x83, 0xc6, 0x85, 0x4a, 0x86, 0xd6,
+    0x88, 0x6a, 0x8a, 0x07, 0x8b, 0xac, 0x8d, 0x5c, 0x8f, 0x14, 0x90, 0xd6,
+    0x92, 0xa0, 0x94, 0x73, 0x96, 0x4e, 0x98, 0x2b, 0x9a, 0x09, 0x9b, 0xe7,
+    0x9d, 0xc6, 0x9f, 0xa4, 0xa1, 0x82, 0xa3, 0x5e, 0xa5, 0x35, 0xa7, 0x09,
+    0xa8, 0xd9, 0xaa, 0xa5, 0xac, 0x71, 0xae, 0x40, 0xb0, 0x12, 0xb1, 0xe8,
+    0xb3, 0xc1, 0xb5, 0x9f, 0xb7, 0x83, 0xb9, 0x6f, 0xbb, 0x61, 0xbd, 0x5c,
+    0xbf, 0x60, 0xc1, 0x6c, 0xc3, 0x7b, 0xc5, 0x8c, 0xc7, 0xa1, 0xc9, 0xb7,
+    0xcb, 0xcd, 0xcd, 0xe4, 0xcf, 0xf7, 0xd2, 0x07, 0xd4, 0x12, 0xd6, 0x18,
+    0xd8, 0x21, 0xda, 0x2f, 0xdc, 0x41, 0xde, 0x57, 0xe0, 0x6f, 0xe2, 0x88,
+    0xe4, 0xa1, 0xe6, 0xbd, 0xe8, 0xdc, 0xeb, 0x03, 0xed, 0x29, 0xef, 0x4c,
+    0xf1, 0x6c, 0xf3, 0x89, 0xf5, 0xa4, 0xf7, 0xbc, 0xf9, 0xd1, 0xfb, 0xe3,
+    0xfd, 0xf2, 0xff, 0xff, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d,
+    0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x20,
+    0x00, 0x00, 0x00, 0x1c, 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67,
+    0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63,
+    0x00, 0x2e, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x36};
+
 ICCProfile ICCProfileForTestingAdobeRGB() {
   return ICCProfile::FromDataWithId(
       reinterpret_cast<const char*>(adobe_rgb_profile_data),
@@ -559,4 +728,11 @@
       arraysize(colorspin_profile_data), ICCProfile::test_id_color_spin_);
 }
 
+ICCProfile ICCProfileForTestingNoAnalyticTrFn() {
+  return ICCProfile::FromDataWithId(
+      reinterpret_cast<const char*>(no_analytic_tr_fn_profile_data),
+      arraysize(no_analytic_tr_fn_profile_data),
+      ICCProfile::test_id_no_analytic_tr_fn_);
+}
+
 }  // namespace gfx
diff --git a/ui/gfx/test/icc_profiles.h b/ui/gfx/test/icc_profiles.h
index 5eb9bd3..464f107 100644
--- a/ui/gfx/test/icc_profiles.h
+++ b/ui/gfx/test/icc_profiles.h
@@ -11,4 +11,7 @@
 ICCProfile ICCProfileForTestingGenericRGB();
 ICCProfile ICCProfileForTestingSRGB();
 
+// A profile that does not have an analytic transfer function.
+ICCProfile ICCProfileForTestingNoAnalyticTrFn();
+
 }  // namespace gfx
diff --git a/ui/gl/gl_switches.cc b/ui/gl/gl_switches.cc
index 8171048..2eccfc3 100644
--- a/ui/gl/gl_switches.cc
+++ b/ui/gl/gl_switches.cc
@@ -135,3 +135,13 @@
     arraysize(kGLSwitchesCopiedFromGpuProcessHost);
 
 }  // namespace switches
+
+namespace features {
+
+#if defined(OS_WIN)
+// Wait for D3D VSync signals in GPU process (as opposed to delay based VSync
+// generated in Browser process based on VSync parameters).
+const base::Feature kD3DVsync{"D3DVsync", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif  // defined(OS_WIN)
+
+}  // namespace features
diff --git a/ui/gl/gl_switches.h b/ui/gl/gl_switches.h
index 270b3fc..945783b7 100644
--- a/ui/gl/gl_switches.h
+++ b/ui/gl/gl_switches.h
@@ -7,6 +7,7 @@
 
 // Defines all the command-line switches used by ui/gl.
 
+#include "base/feature_list.h"
 #include "ui/gl/gl_export.h"
 
 namespace gl {
@@ -64,4 +65,12 @@
 
 }  // namespace switches
 
+namespace features {
+
+#if defined(OS_WIN)
+GL_EXPORT extern const base::Feature kD3DVsync;
+#endif  // defined(OS_WIN)
+
+}  // namespace features
+
 #endif  // UI_GL_GL_SWITCHES_H_
diff --git a/ui/message_center/notification_list.cc b/ui/message_center/notification_list.cc
index 3bac9c1b..9a9ed0f 100644
--- a/ui/message_center/notification_list.cc
+++ b/ui/message_center/notification_list.cc
@@ -24,7 +24,7 @@
 bool ShouldShowNotificationAsPopup(
     const Notification& notification,
     const NotificationBlockers& blockers) {
-  for (const auto& blocker : blockers) {
+  for (auto* blocker : blockers) {
     if (!blocker->ShouldShowNotificationAsPopup(notification))
       return false;
   }
diff --git a/ui/message_center/views/message_list_view.cc b/ui/message_center/views/message_list_view.cc
index 51158fd..92d5d7f 100644
--- a/ui/message_center/views/message_list_view.cc
+++ b/ui/message_center/views/message_list_view.cc
@@ -188,7 +188,7 @@
     has_deferred_task_ = false;
     // cancel cause OnBoundsAnimatorDone which deletes |deleted_when_done_|.
     animator_.Cancel();
-    for (auto view : deleting_views_)
+    for (auto* view : deleting_views_)
       delete view;
     deleting_views_.clear();
     adding_views_.clear();
@@ -230,7 +230,7 @@
 void MessageListView::OnBoundsAnimatorProgressed(
     views::BoundsAnimator* animator) {
   DCHECK_EQ(&animator_, animator);
-  for (auto view : deleted_when_done_) {
+  for (auto* view : deleted_when_done_) {
     const gfx::SlideAnimation* animation = animator->GetAnimationForView(view);
     if (animation)
       view->layer()->SetOpacity(animation->CurrentValueBetween(1.0, 0.0));
@@ -238,7 +238,7 @@
 }
 
 void MessageListView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) {
-  for (auto view : deleted_when_done_)
+  for (auto* view : deleted_when_done_)
     delete view;
   deleted_when_done_.clear();
 
diff --git a/ui/message_center/views/message_list_view_unittest.cc b/ui/message_center/views/message_list_view_unittest.cc
index 96c54cd..dd534b2 100644
--- a/ui/message_center/views/message_list_view_unittest.cc
+++ b/ui/message_center/views/message_list_view_unittest.cc
@@ -187,7 +187,7 @@
 
 TEST_F(MessageListViewTest, AddNotification) {
   // Create a dummy notification.
-  auto notification_view = CreateNotificationView(
+  auto* notification_view = CreateNotificationView(
       Notification(NOTIFICATION_TYPE_SIMPLE, std::string(kNotificationId1),
                    base::UTF8ToUTF16("title"), base::UTF8ToUTF16("message1"),
                    gfx::Image(), base::UTF8ToUTF16("display source"), GURL(),
diff --git a/ui/message_center/views/notification_view.cc b/ui/message_center/views/notification_view.cc
index c7bdce4..7d880e7 100644
--- a/ui/message_center/views/notification_view.cc
+++ b/ui/message_center/views/notification_view.cc
@@ -542,7 +542,7 @@
 
 void NotificationView::CreateOrUpdateListItemViews(
     const Notification& notification) {
-  for (auto item_view : item_views_)
+  for (auto* item_view : item_views_)
     delete item_view;
   item_views_.clear();
 
@@ -623,10 +623,10 @@
   bool new_buttons = action_buttons_.size() != buttons.size();
 
   if (new_buttons || buttons.size() == 0) {
-    for (auto item : separators_)
+    for (auto* item : separators_)
       delete item;
     separators_.clear();
-    for (auto item : action_buttons_)
+    for (auto* item : action_buttons_)
       delete item;
     action_buttons_.clear();
   }
diff --git a/ui/views/border.cc b/ui/views/border.cc
index 14e6d302..61b3b4a 100644
--- a/ui/views/border.cc
+++ b/ui/views/border.cc
@@ -10,8 +10,10 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "cc/paint/paint_flags.h"
+#include "ui/compositor/dip_util.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/views/painter.h"
 #include "ui/views/view.h"
 
@@ -42,18 +44,26 @@
 }
 
 void SolidSidedBorder::Paint(const View& view, gfx::Canvas* canvas) {
-  // Top border.
-  canvas->FillRect(gfx::Rect(0, 0, view.width(), insets_.top()), color_);
-  // Left border.
-  canvas->FillRect(gfx::Rect(0, insets_.top(), insets_.left(),
-                             view.height() - insets_.height()), color_);
-  // Bottom border.
-  canvas->FillRect(gfx::Rect(0, view.height() - insets_.bottom(), view.width(),
-                             insets_.bottom()), color_);
-  // Right border.
-  canvas->FillRect(gfx::Rect(view.width() - insets_.right(), insets_.top(),
-                             insets_.right(), view.height() - insets_.height()),
-                   color_);
+  // Undo DSF so that we can be sure to draw an integral number of pixels for
+  // the border. Integral scale factors should be unaffected by this, but for
+  // fractional scale factors this ensures sharp lines.
+  gfx::ScopedCanvas scoped(canvas);
+  float dsf = canvas->UndoDeviceScaleFactor();
+
+  gfx::RectF scaled_bounds;
+  if (view.layer()) {
+    scaled_bounds =
+        gfx::RectF(ui::ConvertRectToPixel(view.layer(), view.GetLocalBounds()));
+  } else {
+    scaled_bounds = gfx::RectF(view.GetLocalBounds());
+    scaled_bounds.Scale(dsf);
+  }
+
+  // This scaling operation floors the inset values.
+  scaled_bounds.Inset(insets_.Scale(dsf));
+  canvas->sk_canvas()->clipRect(gfx::RectFToSkRect(scaled_bounds),
+                                SkClipOp::kDifference, true);
+  canvas->DrawColor(color_);
 }
 
 gfx::Insets SolidSidedBorder::GetInsets() const {
diff --git a/ui/views/border_unittest.cc b/ui/views/border_unittest.cc
index ab428df..09d2b4e 100644
--- a/ui/views/border_unittest.cc
+++ b/ui/views/border_unittest.cc
@@ -72,6 +72,12 @@
                                       draw_rrect_calls_.end());
   }
 
+  const std::vector<SkPaint>& draw_paint_calls() const {
+    return draw_paint_calls_;
+  }
+
+  const SkRect& last_clip_bounds() const { return last_clip_bounds_; }
+
   // SkCanvas overrides:
   void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
     draw_rect_calls_.insert(DrawRectCall(rect, paint));
@@ -81,11 +87,25 @@
     draw_rrect_calls_.insert(DrawRRectCall(rrect, paint));
   }
 
+  void onDrawPaint(const SkPaint& paint) override {
+    draw_paint_calls_.push_back(paint);
+  }
+
+  void onClipRect(const SkRect& rect,
+                  SkClipOp op,
+                  ClipEdgeStyle edge_style) override {
+    last_clip_bounds_ = rect;
+  }
+
  private:
   // Stores all the calls for querying by the test, in sorted order.
   std::set<DrawRectCall> draw_rect_calls_;
   std::set<DrawRRectCall> draw_rrect_calls_;
 
+  // Stores the onDrawPaint calls in chronological order.
+  std::vector<SkPaint> draw_paint_calls_;
+  SkRect last_clip_bounds_;
+
   DISALLOW_COPY_AND_ASSIGN(MockCanvas);
 };
 
@@ -155,24 +175,19 @@
 }
 
 TEST_F(BorderTest, SolidBorder) {
-  std::unique_ptr<Border> border(CreateSolidBorder(3, SK_ColorBLUE));
+  const SkColor kBorderColor = SK_ColorMAGENTA;
+  std::unique_ptr<Border> border(CreateSolidBorder(3, kBorderColor));
   EXPECT_EQ(gfx::Size(6, 6), border->GetMinimumSize());
   EXPECT_EQ(gfx::Insets(3, 3, 3, 3), border->GetInsets());
   border->Paint(*view_, canvas_.get());
 
-  std::vector<MockCanvas::DrawRectCall> draw_rect_calls =
-      sk_canvas_->draw_rect_calls();
-  ASSERT_EQ(4u, draw_rect_calls.size());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 3), draw_rect_calls[0].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[0].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 3, 3, 47), draw_rect_calls[1].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[1].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 47, 100, 50), draw_rect_calls[2].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[2].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(97, 3, 100, 47), draw_rect_calls[3].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[3].paint.getColor());
+  gfx::Rect bounds = view_->GetLocalBounds();
+  bounds.Inset(border->GetInsets());
 
-  EXPECT_TRUE(sk_canvas_->draw_rrect_calls().empty());
+  ASSERT_EQ(1u, sk_canvas_->draw_paint_calls().size());
+  EXPECT_EQ(kBorderColor, sk_canvas_->draw_paint_calls()[0].getColor());
+  EXPECT_EQ(gfx::RectF(bounds),
+            gfx::SkRectToRectF(sk_canvas_->last_clip_bounds()));
 }
 
 TEST_F(BorderTest, RoundedRectBorder) {
@@ -210,28 +225,23 @@
 }
 
 TEST_F(BorderTest, SolidSidedBorder) {
+  const SkColor kBorderColor = SK_ColorMAGENTA;
   const gfx::Insets kInsets(1, 2, 3, 4);
 
   std::unique_ptr<Border> border(
       CreateSolidSidedBorder(kInsets.top(), kInsets.left(), kInsets.bottom(),
-                             kInsets.right(), SK_ColorBLUE));
+                             kInsets.right(), kBorderColor));
   EXPECT_EQ(gfx::Size(6, 4), border->GetMinimumSize());
   EXPECT_EQ(kInsets, border->GetInsets());
   border->Paint(*view_, canvas_.get());
 
-  std::vector<MockCanvas::DrawRectCall> draw_rect_calls =
-      sk_canvas_->draw_rect_calls();
-  ASSERT_EQ(4u, draw_rect_calls.size());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 1), draw_rect_calls[0].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[0].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 1, 2, 47), draw_rect_calls[1].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[1].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(0, 47, 100, 50), draw_rect_calls[2].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[2].paint.getColor());
-  EXPECT_EQ(SkRect::MakeLTRB(96, 1, 100, 47), draw_rect_calls[3].rect);
-  EXPECT_EQ(SK_ColorBLUE, draw_rect_calls[3].paint.getColor());
+  gfx::Rect bounds = view_->GetLocalBounds();
+  bounds.Inset(border->GetInsets());
 
-  EXPECT_TRUE(sk_canvas_->draw_rrect_calls().empty());
+  ASSERT_EQ(1u, sk_canvas_->draw_paint_calls().size());
+  EXPECT_EQ(kBorderColor, sk_canvas_->draw_paint_calls()[0].getColor());
+  EXPECT_EQ(gfx::RectF(bounds),
+            gfx::SkRectToRectF(sk_canvas_->last_clip_bounds()));
 }
 
 TEST_F(BorderTest, BorderPainter) {
diff --git a/ui/views/controls/menu/menu_item_view.cc b/ui/views/controls/menu/menu_item_view.cc
index def3514..450cf5ac 100644
--- a/ui/views/controls/menu/menu_item_view.cc
+++ b/ui/views/controls/menu/menu_item_view.cc
@@ -524,7 +524,7 @@
     }
   }
 
-  for (auto item : removed_items_)
+  for (auto* item : removed_items_)
     delete item;
   removed_items_.clear();
 }
@@ -599,7 +599,7 @@
 
 MenuItemView::~MenuItemView() {
   delete submenu_;
-  for (auto item : removed_items_)
+  for (auto* item : removed_items_)
     delete item;
 }
 
diff --git a/ui/views/controls/scrollbar/overlay_scroll_bar.cc b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
index 4c0a6d5..83d7a58 100644
--- a/ui/views/controls/scrollbar/overlay_scroll_bar.cc
+++ b/ui/views/controls/scrollbar/overlay_scroll_bar.cc
@@ -110,7 +110,7 @@
 
 OverlayScrollBar::OverlayScrollBar(bool horizontal)
     : BaseScrollBar(horizontal), hide_timer_(false, false) {
-  auto thumb = new Thumb(this);
+  auto* thumb = new Thumb(this);
   SetThumb(thumb);
   thumb->Init();
   set_notify_enter_exit_on_child(true);
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn
index ef70dd3..3f27518f 100644
--- a/ui/views/examples/BUILD.gn
+++ b/ui/views/examples/BUILD.gn
@@ -18,6 +18,8 @@
     "checkbox_example.h",
     "combobox_example.cc",
     "combobox_example.h",
+    "dialog_example.cc",
+    "dialog_example.h",
     "example_base.cc",
     "example_base.h",
     "example_combobox_model.cc",
diff --git a/ui/views/examples/button_sticker_sheet.cc b/ui/views/examples/button_sticker_sheet.cc
index dc98a83..9b32de4f 100644
--- a/ui/views/examples/button_sticker_sheet.cc
+++ b/ui/views/examples/button_sticker_sheet.cc
@@ -56,7 +56,7 @@
   const int kPaddingRowHeight = 8;
   layout->StartRow(kRowDoesNotResizeVertically, kStretchyGridColumnSetId);
   layout->AddView(MakePlainLabel(label_text));
-  for (const auto& view : views)
+  for (auto* view : views)
     layout->AddView(view);
   // This gets added extraneously after the last row, but it doesn't hurt and
   // means there's no need to keep track of whether to add it or not.
diff --git a/ui/views/examples/dialog_example.cc b/ui/views/examples/dialog_example.cc
new file mode 100644
index 0000000..637c6da
--- /dev/null
+++ b/ui/views/examples/dialog_example.cc
@@ -0,0 +1,329 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/views/examples/dialog_example.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/views/bubble/bubble_dialog_delegate.h"
+#include "ui/views/controls/button/checkbox.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/controls/combobox/combobox.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/views_delegate.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
+
+using base::ASCIIToUTF16;
+
+namespace views {
+namespace examples {
+namespace {
+
+constexpr int kFieldsColumnId = 0;
+constexpr int kButtonsColumnId = 1;
+constexpr int kFakeModeless = ui::MODAL_TYPE_SYSTEM + 1;
+
+}  // namespace
+
+template <class DialogType>
+class DialogExample::Delegate : public virtual DialogType {
+ public:
+  explicit Delegate(DialogExample* parent) : parent_(parent) {}
+
+  void InitDelegate() {
+    LayoutManager* fill_layout = new FillLayout();
+    this->SetLayoutManager(fill_layout);
+    Label* body = new Label(parent_->body_->text());
+    body->SetMultiLine(true);
+    body->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+    body->set_background(Background::CreateSolidBackground(0, 255, 255));
+    this->AddChildView(body);
+
+    // Give the example code a way to change the body text.
+    parent_->last_body_label_ = body;
+  }
+
+ protected:
+  // WidgetDelegate:
+  ui::ModalType GetModalType() const override {
+    return parent_->GetModalType();
+  }
+
+  base::string16 GetWindowTitle() const override {
+    return parent_->title_->text();
+  }
+
+  // DialogDelegate:
+  View* CreateExtraView() {
+    if (!parent_->has_extra_button_->checked())
+      return nullptr;
+    return MdTextButton::CreateSecondaryUiButton(
+        nullptr, parent_->extra_button_label_->text());
+  }
+
+  bool Cancel() override { return parent_->AllowDialogClose(false); }
+  bool Accept() override { return parent_->AllowDialogClose(true); }
+  int GetDialogButtons() const override { return parent_->GetDialogButtons(); }
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override {
+    if (button == ui::DIALOG_BUTTON_OK)
+      return parent_->ok_button_label_->text();
+    if (button == ui::DIALOG_BUTTON_CANCEL)
+      return parent_->cancel_button_label_->text();
+    return base::string16();
+  }
+
+ private:
+  DialogExample* parent_;
+
+  DISALLOW_COPY_AND_ASSIGN(Delegate);
+};
+
+class DialogExample::Bubble : public Delegate<BubbleDialogDelegateView> {
+ public:
+  Bubble(DialogExample* parent, View* anchor)
+      : BubbleDialogDelegateView(anchor, BubbleBorder::TOP_LEFT),
+        Delegate(parent) {
+    set_close_on_deactivate(!parent->persistent_bubble_->checked());
+  }
+
+  // BubbleDialogDelegateView:
+  void Init() override { InitDelegate(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Bubble);
+};
+
+class DialogExample::Dialog : public Delegate<DialogDelegateView> {
+ public:
+  explicit Dialog(DialogExample* parent) : Delegate(parent) {}
+
+  // WidgetDelegate:
+  bool CanResize() const override {
+    // Mac supports resizing of modal dialogs (parent or window-modal). On other
+    // platforms this will be weird unless the modal type is "none", but helps
+    // test layout.
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Dialog);
+};
+
+DialogExample::DialogExample()
+    : ExampleBase("Dialog"),
+      mode_model_({
+          base::ASCIIToUTF16("Modeless"), base::ASCIIToUTF16("Window Modal"),
+          base::ASCIIToUTF16("Child Modal"), base::ASCIIToUTF16("System Modal"),
+          base::ASCIIToUTF16("Fake Modeless (non-bubbles)"),
+      }) {}
+
+DialogExample::~DialogExample() {}
+
+void DialogExample::CreateExampleView(View* container) {
+  // GridLayout |resize_percent| constants.
+  const float kFixed = 0.f;
+  const float kStretchy = 1.f;
+
+  const int horizontal_spacing =
+      ViewsDelegate::GetInstance()->GetDialogRelatedButtonHorizontalSpacing();
+  GridLayout* layout = GridLayout::CreatePanel(container);
+  container->SetLayoutManager(layout);
+  ColumnSet* column_set = layout->AddColumnSet(kFieldsColumnId);
+  column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, kFixed,
+                        GridLayout::USE_PREF, 0, 0);
+  column_set->AddPaddingColumn(kFixed, horizontal_spacing);
+  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kStretchy,
+                        GridLayout::USE_PREF, 0, 0);
+  column_set->AddPaddingColumn(kFixed, horizontal_spacing);
+  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, kFixed,
+                        GridLayout::USE_PREF, 0, 0);
+  StartTextfieldRow(layout, &title_, "Dialog Title", "Title");
+  StartTextfieldRow(layout, &body_, "Dialog Body Text", "Body Text");
+
+  StartTextfieldRow(layout, &ok_button_label_, "OK Button Label", "Done");
+  AddCheckbox(layout, &has_ok_button_);
+
+  StartTextfieldRow(layout, &cancel_button_label_, "Cancel Button Label",
+                    "Cancel");
+  AddCheckbox(layout, &has_cancel_button_);
+
+  StartTextfieldRow(layout, &extra_button_label_, "Extra Button Label", "Edit");
+  AddCheckbox(layout, &has_extra_button_);
+
+  StartRowWithLabel(layout, "Modal Type");
+  mode_ = new Combobox(&mode_model_);
+  mode_->set_listener(this);
+  mode_->SetSelectedIndex(ui::MODAL_TYPE_CHILD);
+  layout->AddView(mode_);
+
+  StartRowWithLabel(layout, "Bubble");
+  AddCheckbox(layout, &bubble_);
+  AddCheckbox(layout, &persistent_bubble_);
+  persistent_bubble_->SetText(base::ASCIIToUTF16("Persistent"));
+
+  column_set = layout->AddColumnSet(kButtonsColumnId);
+  column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, kStretchy,
+                        GridLayout::USE_PREF, 0, 0);
+  layout->StartRowWithPadding(kFixed, kButtonsColumnId, kFixed,
+                              kUnrelatedControlVerticalSpacing);
+  show_ =
+      MdTextButton::CreateSecondaryUiButton(this, base::ASCIIToUTF16("Show"));
+  layout->AddView(show_);
+
+  // Grow the dialog a bit when this example is first selected, so it all fits.
+  gfx::Size dialog_size = container->GetWidget()->GetRestoredBounds().size();
+  dialog_size.set_height(dialog_size.height() + 80);
+  container->GetWidget()->SetSize(dialog_size);
+}
+
+void DialogExample::StartRowWithLabel(GridLayout* layout, const char* label) {
+  const float kFixedVerticalResize = 0.f;
+  layout->StartRowWithPadding(
+      kFixedVerticalResize, kFieldsColumnId, kFixedVerticalResize,
+      ViewsDelegate::GetInstance()->GetDialogRelatedControlVerticalSpacing());
+  layout->AddView(new Label(base::ASCIIToUTF16(label)));
+}
+
+void DialogExample::StartTextfieldRow(GridLayout* layout,
+                                      Textfield** member,
+                                      const char* label,
+                                      const char* value) {
+  StartRowWithLabel(layout, label);
+  Textfield* textfield = new Textfield();
+  layout->AddView(textfield);
+  textfield->set_controller(this);
+  textfield->SetText(base::ASCIIToUTF16(value));
+  *member = textfield;
+}
+
+void DialogExample::AddCheckbox(GridLayout* layout, Checkbox** member) {
+  Checkbox* checkbox = new Checkbox(base::string16());
+  checkbox->set_listener(this);
+  checkbox->SetChecked(true);
+  layout->AddView(checkbox);
+  *member = checkbox;
+}
+
+ui::ModalType DialogExample::GetModalType() const {
+  // "Fake" modeless happens when a DialogDelegate specifies window-modal, but
+  // doesn't provide a parent window.
+  if (mode_->selected_index() == kFakeModeless)
+    return ui::MODAL_TYPE_WINDOW;
+
+  return static_cast<ui::ModalType>(mode_->selected_index());
+}
+
+int DialogExample::GetDialogButtons() const {
+  int buttons = 0;
+  if (has_ok_button_->checked())
+    buttons |= ui::DIALOG_BUTTON_OK;
+  if (has_cancel_button_->checked())
+    buttons |= ui::DIALOG_BUTTON_CANCEL;
+  return buttons;
+}
+
+bool DialogExample::AllowDialogClose(bool accept) {
+  PrintStatus("Dialog closed with %s.", accept ? "Accept" : "Cancel");
+  last_dialog_ = nullptr;
+  last_body_label_ = nullptr;
+  return true;
+}
+
+void DialogExample::ResizeDialog() {
+  DCHECK(last_dialog_);
+  Widget* widget = last_dialog_->GetWidget();
+  gfx::Rect preferred_bounds(widget->GetRestoredBounds());
+  preferred_bounds.set_size(widget->non_client_view()->GetPreferredSize());
+
+  // Q: Do we need NonClientFrameView::GetWindowBoundsForClientBounds() here?
+  // A: When DialogCientView properly feeds back sizes, we do not.
+  widget->SetBoundsConstrained(preferred_bounds);
+}
+
+void DialogExample::ButtonPressed(Button* sender, const ui::Event& event) {
+  if (sender == show_) {
+    if (bubble_->checked()) {
+      Bubble* bubble = new Bubble(this, sender);
+      last_dialog_ = bubble;
+      BubbleDialogDelegateView::CreateBubble(bubble);
+    } else {
+      Dialog* dialog = new Dialog(this);
+      last_dialog_ = dialog;
+      dialog->InitDelegate();
+
+      // constrained_window::CreateBrowserModalDialogViews() allows dialogs to
+      // be created as MODAL_TYPE_WINDOW without specifying a parent.
+      gfx::NativeView parent = nullptr;
+      if (mode_->selected_index() != kFakeModeless)
+        parent = container()->GetWidget()->GetNativeView();
+
+      DialogDelegate::CreateDialogWidget(
+          dialog, container()->GetWidget()->GetNativeWindow(), parent);
+    }
+    last_dialog_->GetWidget()->Show();
+    return;
+  }
+
+  if (sender == bubble_) {
+    if (bubble_->checked() && GetModalType() != ui::MODAL_TYPE_CHILD) {
+      mode_->SetSelectedIndex(ui::MODAL_TYPE_CHILD);
+      PrintStatus("You nearly always want Child Modal for bubbles.");
+    }
+    persistent_bubble_->SetEnabled(bubble_->checked());
+    OnPerformAction(mode_);  // Validate the modal type.
+
+    if (!bubble_->checked() && GetModalType() == ui::MODAL_TYPE_CHILD) {
+      // Do something reasonable when simply unchecking bubble and re-enable.
+      mode_->SetSelectedIndex(ui::MODAL_TYPE_WINDOW);
+      OnPerformAction(mode_);
+    }
+    return;
+  }
+
+  // Other buttons are all checkboxes. Update the dialog if there is one.
+  if (last_dialog_) {
+    last_dialog_->GetDialogClientView()->UpdateDialogButtons();
+    ResizeDialog();
+  }
+}
+
+void DialogExample::ContentsChanged(Textfield* sender,
+                                    const base::string16& new_contents) {
+  if (!last_dialog_)
+    return;
+
+  if (sender == extra_button_label_)
+    PrintStatus("DialogClientView can never refresh the extra view.");
+
+  if (sender == title_) {
+    last_dialog_->GetWidget()->UpdateWindowTitle();
+  } else if (sender == body_) {
+    last_body_label_->SetText(new_contents);
+  } else {
+    last_dialog_->GetDialogClientView()->UpdateDialogButtons();
+  }
+
+  ResizeDialog();
+}
+
+void DialogExample::OnPerformAction(Combobox* combobox) {
+  bool enable = bubble_->checked() || GetModalType() != ui::MODAL_TYPE_CHILD;
+#if defined(OS_MACOSX)
+  enable = enable && GetModalType() != ui::MODAL_TYPE_SYSTEM;
+#endif
+  show_->SetEnabled(enable);
+  if (!enable && GetModalType() == ui::MODAL_TYPE_CHILD)
+    PrintStatus("MODAL_TYPE_CHILD can't be used with non-bubbles.");
+  if (!enable && GetModalType() == ui::MODAL_TYPE_SYSTEM)
+    PrintStatus("MODAL_TYPE_SYSTEM isn't supported on Mac.");
+}
+
+}  // namespace examples
+}  // namespace views
diff --git a/ui/views/examples/dialog_example.h b/ui/views/examples/dialog_example.h
new file mode 100644
index 0000000..3731846
--- /dev/null
+++ b/ui/views/examples/dialog_example.h
@@ -0,0 +1,96 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_VIEWS_EXAMPLES_DIALOG_EXAMPLE_H_
+#define UI_VIEWS_EXAMPLES_DIALOG_EXAMPLE_H_
+
+#include "base/macros.h"
+#include "ui/base/models/simple_combobox_model.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/combobox/combobox_listener.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/examples/example_base.h"
+
+namespace views {
+
+class Checkbox;
+class Combobox;
+class DialogDelegate;
+class GridLayout;
+class Label;
+class LabelButton;
+class Textfield;
+
+namespace examples {
+
+// An example that exercises BubbleDialogDelegateView or DialogDelegateView.
+class VIEWS_EXAMPLES_EXPORT DialogExample : public ExampleBase,
+                                            public ButtonListener,
+                                            public TextfieldController,
+                                            public ComboboxListener {
+ public:
+  DialogExample();
+  ~DialogExample() override;
+
+  // ExampleBase:
+  void CreateExampleView(View* container) override;
+
+ private:
+  template <class>
+  class Delegate;
+  class Bubble;
+  class Dialog;
+
+  // Helper methods to setup the configuration Views.
+  void StartRowWithLabel(GridLayout* layout, const char* label);
+  void StartTextfieldRow(GridLayout* layout,
+                         Textfield** member,
+                         const char* label,
+                         const char* value);
+  void AddCheckbox(GridLayout* layout, Checkbox** member);
+
+  // Interrogates the configuration Views for DialogDelegate.
+  ui::ModalType GetModalType() const;
+  int GetDialogButtons() const;
+
+  // Invoked when the dialog is closing.
+  bool AllowDialogClose(bool accept);
+
+  // Resize the dialog Widget to match the preferred size. Triggers Layout().
+  void ResizeDialog();
+
+  // ButtonListener:
+  void ButtonPressed(Button* sender, const ui::Event& event) override;
+
+  // TextfieldController:
+  void ContentsChanged(Textfield* sender,
+                       const base::string16& new_contents) override;
+
+  // ComboboxListener:
+  void OnPerformAction(Combobox* combobox) override;
+
+  DialogDelegate* last_dialog_ = nullptr;
+  Label* last_body_label_ = nullptr;
+
+  Textfield* title_;
+  Textfield* body_;
+  Textfield* ok_button_label_;
+  Checkbox* has_ok_button_;
+  Textfield* cancel_button_label_;
+  Checkbox* has_cancel_button_;
+  Textfield* extra_button_label_;
+  Checkbox* has_extra_button_;
+  Combobox* mode_;
+  Checkbox* bubble_;
+  Checkbox* persistent_bubble_;
+  LabelButton* show_;
+  ui::SimpleComboboxModel mode_model_;
+
+  DISALLOW_COPY_AND_ASSIGN(DialogExample);
+};
+
+}  // namespace examples
+}  // namespace views
+
+#endif  // UI_VIEWS_EXAMPLES_DIALOG_EXAMPLE_H_
diff --git a/ui/views/examples/examples_window.cc b/ui/views/examples/examples_window.cc
index 0cd2669..f6a1707 100644
--- a/ui/views/examples/examples_window.cc
+++ b/ui/views/examples/examples_window.cc
@@ -23,6 +23,7 @@
 #include "ui/views/examples/button_sticker_sheet.h"
 #include "ui/views/examples/checkbox_example.h"
 #include "ui/views/examples/combobox_example.h"
+#include "ui/views/examples/dialog_example.h"
 #include "ui/views/examples/label_example.h"
 #include "ui/views/examples/link_example.h"
 #include "ui/views/examples/menu_example.h"
@@ -61,6 +62,7 @@
   examples.push_back(base::MakeUnique<ButtonStickerSheet>());
   examples.push_back(base::MakeUnique<CheckboxExample>());
   examples.push_back(base::MakeUnique<ComboboxExample>());
+  examples.push_back(base::MakeUnique<DialogExample>());
   examples.push_back(base::MakeUnique<LabelExample>());
   examples.push_back(base::MakeUnique<LinkExample>());
   examples.push_back(base::MakeUnique<MenuExample>());
diff --git a/ui/views/layout/grid_layout.cc b/ui/views/layout/grid_layout.cc
index eb4dd9d1..8c7dcfb 100644
--- a/ui/views/layout/grid_layout.cc
+++ b/ui/views/layout/grid_layout.cc
@@ -236,11 +236,11 @@
 
   // Accumulate the size first.
   int size = 0;
-  for (auto column : same_size_columns_)
+  for (auto* column : same_size_columns_)
     size = std::max(size, column->Size());
 
   // Then apply it.
-  for (auto column : same_size_columns_)
+  for (auto* column : same_size_columns_)
     column->SetSize(size);
 }
 
@@ -496,7 +496,7 @@
 }
 
 void ColumnSet::UnifySameSizedColumnSizes() {
-  for (auto column : master_columns_)
+  for (auto* column : master_columns_)
     column->UnifySameSizedColumnSizes();
 }
 
@@ -583,7 +583,7 @@
 void ColumnSet::CalculateSize() {
   gfx::Size pref;
   // Reset the preferred and remaining sizes.
-  for (const auto& view_state : view_states_) {
+  for (auto* view_state : view_states_) {
     if (!view_state->pref_width_fixed || !view_state->pref_height_fixed) {
       pref = view_state->view->GetPreferredSize();
       if (!view_state->pref_width_fixed)
diff --git a/ui/views/test/ui_controls_factory_desktop_aurax11.cc b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
index d7b41b1..117a268 100644
--- a/ui/views/test/ui_controls_factory_desktop_aurax11.cc
+++ b/ui/views/test/ui_controls_factory_desktop_aurax11.cc
@@ -146,7 +146,7 @@
         aura::test::QueryLatestMousePositionRequestInHost(host);
     host->ConvertPixelsToDIP(&root_current_location);
 
-    auto screen = views::test::TestDesktopScreenX11::GetInstance();
+    auto* screen = views::test::TestDesktopScreenX11::GetInstance();
     DCHECK_EQ(screen, display::Screen::GetScreen());
     screen->set_cursor_screen_point(gfx::Point(screen_x, screen_y));
 
diff --git a/url/origin_unittest.cc b/url/origin_unittest.cc
index a5c3042..4e1139c 100644
--- a/url/origin_unittest.cc
+++ b/url/origin_unittest.cc
@@ -262,7 +262,7 @@
       "https-so://.", "https-so://foo", "https-so://.foo", "https-so://foo.",
   };
 
-  for (const auto& test_case : failure_cases) {
+  for (auto* test_case : failure_cases) {
     SCOPED_TRACE(test_case);
     GURL url(test_case);
     EXPECT_TRUE(url.is_valid());