diff --git a/DEPS b/DEPS
index 567f23dc..85937c6 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '61b721c449d022cdadf56adf4ea1a0b7e2850f18',
+  'skia_revision': '578f064a60b63ddfb00831e9e59a47060bfcefe0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '0dae245e03dc7694d44a1b2e6e0d13865bc5f1f6',
+  'v8_revision': '4ed8f7edf5dc80fb6240780af0ddb2875081dc89',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -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': '1d7018e92d315c883dca38dd083db44791761827',
+  'pdfium_revision': '717a4fc857d66017cecc4c8f8285713135b9dc68',
   # 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.
@@ -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': 'a75c463e8416e25de8c1d70ec210a1de89ea19a5',
+  'catapult_revision': '90835c8a63dee2c4d38c223acc2a58e54574e333',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -232,7 +232,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '1c1bd4dc650bac02aa9a79037fd8e4da527fd857', # commit position 16857
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'b369f97c44d3c4c6e33843c2db0698c80fd929c9', # commit position 16867
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/WATCHLISTS b/WATCHLISTS
index 9fa9e6ed..e5506e4 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1542,6 +1542,7 @@
     'arc': ['elijahtaylor+arcwatch@chromium.org',
             'hidehiko+watch@chromium.org',
             'lhchavez+watch@chromium.org',
+            'victorhsieh+watch@chromium.org',
             'yusukes+watch@chromium.org'],
     'arc_auth': ['khmel+watch@chromium.org'],
     'arc_kiosk': ['poromov+watch@chromium.org'],
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
index b9d58e1a..ffbcca9 100644
--- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
+++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/ActionModeTest.java
@@ -41,16 +41,17 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
-import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.os.Build;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.Espresso;
+import android.support.test.espresso.IdlingResource;
+import android.support.test.espresso.IdlingResource.ResourceCallback;
 import android.support.test.espresso.NoMatchingViewException;
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.Root;
-import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.GeneralLocation;
 import android.support.test.espresso.action.Press;
@@ -68,20 +69,18 @@
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
 import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.Log;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.webview_ui_test.R;
 import org.chromium.webview_ui_test.WebViewUiTestActivity;
 import org.chromium.webview_ui_test.test.util.UseLayout;
 import org.chromium.webview_ui_test.test.util.WebViewUiTestRule;
 
-import java.lang.reflect.Method;
-
 /**
  * Tests for WebView ActionMode.
  */
@@ -105,6 +104,8 @@
     public WebViewUiTestRule mWebViewActivityRule =
             new WebViewUiTestRule(WebViewUiTestActivity.class);
 
+    private ActionBarIdlingResource mActionBarIdlingResource;
+
     @Before
     public void setUp() {
         mWebViewActivityRule.launchActivity();
@@ -114,21 +115,13 @@
         onWebView(withId(R.id.webview))
                 .withElement(findElement(Locator.TAG_NAME, "p"))
                 .check(webMatches(getText(), containsString("Hello world")));
-        disableAnimation();
+        mActionBarIdlingResource = new ActionBarIdlingResource();
+        Espresso.registerIdlingResources(mActionBarIdlingResource);
     }
 
-    /**
-     * Only way to disable popup animations.
-     */
-    private void disableAnimation() {
-        try {
-            // This is a hidden method to disable animations.  It is also being used by CTS tests.
-            Method setDurationScale = ValueAnimator.class.getMethod(
-                    "setDurationScale", float.class);
-            setDurationScale.invoke(null, 0.0f);
-        } catch (Exception e) {
-            Log.e(TAG, "Couldn't disable animation", e);
-        }
+    @After
+    public void tearDown() {
+        Espresso.unregisterIdlingResources(mActionBarIdlingResource);
     }
 
     /**
@@ -138,9 +131,9 @@
     @SmallTest
     @UseLayout("edittext_webview")
     public void testCopyPaste() {
-        onView(withId(R.id.webview)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.webview);
         clickPopupAction(COPY_ACTION);
-        onView(withId(R.id.edittext)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.edittext);
         clickPopupAction(PASTE_ACTION);
         onView(withId(R.id.edittext))
                 .check(matches(withText("world")));
@@ -153,10 +146,10 @@
     @SmallTest
     @UseLayout("edittext_webview")
     public void testSelectAll() {
-        onView(withId(R.id.webview)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.webview);
         clickPopupAction("Select all");
         clickPopupAction(COPY_ACTION);
-        onView(withId(R.id.edittext)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.edittext);
         clickPopupAction(PASTE_ACTION);
         onView(withId(R.id.edittext))
                 .check(matches(withText("Hello world")));
@@ -173,7 +166,7 @@
         intending(anyIntent())
                 .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent()));
 
-        onView(withId(R.id.webview)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.webview);
         clickPopupAction(SHARE_ACTION);
 
         intended(allOf(hasAction(Intent.ACTION_CHOOSER),
@@ -194,7 +187,7 @@
         Intents.init();
         intending(anyIntent())
                 .respondWith(new Instrumentation.ActivityResult(Activity.RESULT_OK, new Intent()));
-        onView(withId(R.id.webview)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.webview);
         clickPopupAction(WEB_SEARCH_ACTION);
         intended(allOf(hasAction(Intent.ACTION_WEB_SEARCH),
                 hasExtras(allOf(hasEntry("com.android.browser.application_id",
@@ -213,7 +206,7 @@
     public void testAssist() {
         // TODO(aluo): Get SdkSuppress to work with the test runner
         if (Build.VERSION.SDK_INT < 24) return;
-        onView(withId(R.id.webview)).perform(longClickOnLastWord());
+        longClickOnLastWord(R.id.webview);
         clickPopupAction(ASSIST_ACTION);
         UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
         UiObject assistUi = device.findObject(new UiSelector().packageName(QUICK_SEARCH_BOX_PKG));
@@ -230,7 +223,7 @@
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
             try {
                 // On L and lower, use the espresso DEFAULT root matcher if ActionBar is detected
-                onView(withClassName(endsWith("widget.ActionBarContextView")))
+                onView(withClassName(endsWith("ActionBarContextView")))
                         .check(matches(isDisplayed()));
                 rootMatcher = DEFAULT;
             } catch (NoMatchingViewException | AssertionFailedError e) {
@@ -241,27 +234,30 @@
             // On M and above, can use the decoreView matcher
             rootMatcher = withDecorView(isEnabled());
         }
+
         try {
             onView(anyOf(withText(name), withContentDescription(name)))
                     .inRoot(rootMatcher)
                     .perform(click());
-        } catch (PerformException e) {
+        } catch (PerformException | NoMatchingViewException e) {
             // Take care of case when the item is in the overflow menu
             onView(withContentDescription(MORE_OPTIONS_ACTION))
-                    .inRoot(withDecorView(isEnabled()))
+                    .inRoot(rootMatcher)
                     .perform(click());
             onData(new MenuItemMatcher(equalTo(name))).inRoot(rootMatcher).perform(click());
         }
     }
 
     /**
-     * This view action clicks on center right of a view to select the last word
+     * Perform a view action that clicks on the last word and start the idling resource
+     * to wait for completion of the popup menu
      */
-    private static final ViewAction longClickOnLastWord() {
+    private final void longClickOnLastWord(int viewId) {
         // TODO(aluo): This function is not guaranteed to click on element. Change to
         // implementation that gets bounding box for elements using Javascript.
-        return actionWithAssertions(
-                new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER_RIGHT, Press.FINGER));
+        onView(withId(viewId)).perform(actionWithAssertions(
+                new GeneralClickAction(Tap.LONG, GeneralLocation.CENTER_RIGHT, Press.FINGER)));
+        mActionBarIdlingResource.start();
     }
 
     /**
@@ -285,4 +281,38 @@
             description.appendDescriptionOf(mTitleMatcher);
         }
     }
+
+    private class ActionBarIdlingResource implements IdlingResource {
+        private boolean mActionStarting;
+        private ResourceCallback mResourceCallback;
+
+        ActionBarIdlingResource() {
+            mActionStarting = false;
+            mResourceCallback = null;
+        }
+
+        @Override
+        public String getName() {
+            return "ActionBarIdlingResource";
+        }
+
+        @Override
+        public boolean isIdleNow() {
+            if (!mActionStarting) return true;
+            if (mWebViewActivityRule.isActionBarDisplayed()) {
+                mActionStarting = false;
+                if (mResourceCallback != null) mResourceCallback.onTransitionToIdle();
+            }
+            return !mActionStarting;
+        }
+
+        @Override
+        public void registerIdleTransitionCallback(ResourceCallback callback) {
+            mResourceCallback = callback;
+        }
+
+        public void start() {
+            mActionStarting = true;
+        }
+    }
 }
diff --git a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java
index d60a16bd..c3e6a72 100644
--- a/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java
+++ b/android_webview/tools/automated_ui_tests/javatests/src/org/chromium/webview_ui_test/test/util/WebViewUiTestRule.java
@@ -4,7 +4,21 @@
 
 package org.chromium.webview_ui_test.test.util;
 
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withChild;
+import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.hasItem;
+
 import android.content.Intent;
+import android.os.Build;
+import android.support.test.espresso.BaseLayerComponent;
+import android.support.test.espresso.DaggerBaseLayerComponent;
 import android.support.test.rule.ActivityTestRule;
 import android.webkit.WebView;
 
@@ -25,6 +39,7 @@
 
     private WebViewSyncWrapper mSyncWrapper;
     private String mLayout;
+    private BaseLayerComponent mBaseLayerComponent;
 
     public WebViewUiTestRule(Class<WebViewUiTestActivity> activityClass) {
         super(activityClass);
@@ -81,4 +96,35 @@
             Assert.fail(e.getMessage());
         }
     }
+
+    public boolean isActionBarDisplayed() {
+        if (mBaseLayerComponent == null) mBaseLayerComponent = DaggerBaseLayerComponent.create();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            // For M and above
+            if (hasItem(withDecorView(withChild(allOf(
+                    withClassName(endsWith("PopupBackgroundView")),
+                    isCompletelyDisplayed())))).matches(
+                    mBaseLayerComponent.activeRootLister().listActiveRoots())) {
+                return true;
+            }
+        } else {
+            // For L
+            if (hasItem(withDecorView(hasDescendant(allOf(
+                    withClassName(endsWith("ActionMenuItemView")),
+                    isCompletelyDisplayed())))).matches(
+                    mBaseLayerComponent.activeRootLister().listActiveRoots())) {
+                return true;
+            }
+
+            // Paste option is a popup on L
+            if (hasItem(withDecorView(withChild(withText("Paste")))).matches(
+                    mBaseLayerComponent.activeRootLister().listActiveRoots())) {
+                return true;
+            }
+        }
+
+
+        return false;
+    }
 }
diff --git a/ash/OWNERS b/ash/OWNERS
index 98b3759b..a3b6999b 100644
--- a/ash/OWNERS
+++ b/ash/OWNERS
@@ -9,3 +9,5 @@
 per-file ash_chromeos_strings.grdp=*
 per-file ash_switches.*=*
 per-file BUILD.gn=*
+
+# COMPONENT: UI>Shell
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 96ddf2f..c9bb0ea 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -385,6 +385,10 @@
     "files/memory_mapped_file_win.cc",
     "files/scoped_file.cc",
     "files/scoped_file.h",
+    "files/scoped_platform_handle.cc",
+    "files/scoped_platform_handle.h",
+    "files/scoped_platform_handle_posix.cc",
+    "files/scoped_platform_handle_win.cc",
     "files/scoped_temp_dir.cc",
     "files/scoped_temp_dir.h",
     "format_macros.h",
@@ -1949,6 +1953,7 @@
     "files/file_util_unittest.cc",
     "files/important_file_writer_unittest.cc",
     "files/memory_mapped_file_unittest.cc",
+    "files/scoped_platform_handle_unittest.cc",
     "files/scoped_temp_dir_unittest.cc",
     "gmock_unittest.cc",
     "guid_unittest.cc",
diff --git a/base/files/scoped_platform_handle.cc b/base/files/scoped_platform_handle.cc
new file mode 100644
index 0000000..a0c30155
--- /dev/null
+++ b/base/files/scoped_platform_handle.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_platform_handle.h"
+
+namespace base {
+
+ScopedPlatformHandle::ScopedPlatformHandle() : ScopedPlatformHandle(nullptr) {}
+
+ScopedPlatformHandle::ScopedPlatformHandle(std::nullptr_t) {}
+
+ScopedPlatformHandle::ScopedPlatformHandle(ScopedPlatformHandle&& other) =
+    default;
+
+ScopedPlatformHandle::ScopedPlatformHandle(HandleType handle)
+    : handle_(handle) {}
+
+ScopedPlatformHandle::ScopedPlatformHandle(ScopedHandleType handle)
+    : handle_(std::move(handle)) {}
+
+ScopedPlatformHandle::~ScopedPlatformHandle() {}
+
+ScopedPlatformHandle& ScopedPlatformHandle::operator=(
+    ScopedPlatformHandle&& other) = default;
+
+ScopedPlatformHandle::ScopedHandleType ScopedPlatformHandle::Take() {
+  return ScopedHandleType(release());
+}
+
+}  // namespace base
diff --git a/base/files/scoped_platform_handle.h b/base/files/scoped_platform_handle.h
new file mode 100644
index 0000000..cfff5a7
--- /dev/null
+++ b/base/files/scoped_platform_handle.h
@@ -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.
+
+#ifndef BASE_FILES_SCOPED_PLATFORM_HANDLE_H_
+#define BASE_FILES_SCOPED_PLATFORM_HANDLE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "base/win/scoped_handle.h"
+#elif defined(OS_POSIX)
+#include "base/files/scoped_file.h"
+#endif
+
+namespace base {
+
+// A ScopedPlatformHandle encapsulates ownership of either a Windows handle or
+// a POSIX file descriptor, while presenting a common interface for the sake
+// of simple, consistent, and safe ownership semantics. Platform-specific usage
+// details are thus relegated to code which either acquires or uses the
+// underlying platform resource.
+class BASE_EXPORT ScopedPlatformHandle {
+ public:
+#if defined(OS_WIN)
+  using HandleType = HANDLE;
+  using ScopedHandleType = win::ScopedHandle;
+#elif defined(OS_POSIX)
+  using HandleType = int;
+  using ScopedHandleType = ScopedFD;
+#endif
+
+  // Constructors for an invalid ScopedPlatformHandle.
+  ScopedPlatformHandle();
+  ScopedPlatformHandle(std::nullptr_t);
+
+  ScopedPlatformHandle(ScopedPlatformHandle&& other);
+
+  // These constructors always take ownership of the given handle.
+  explicit ScopedPlatformHandle(HandleType handle);
+  explicit ScopedPlatformHandle(ScopedHandleType handle);
+
+  ~ScopedPlatformHandle();
+
+  ScopedPlatformHandle& operator=(ScopedPlatformHandle&& other);
+
+  // Indicates whether this ScopedPlatformHandle is holding a valid handle.
+  bool is_valid() const;
+
+  // Closes the handle.
+  void reset();
+
+  // Returns the platform-specific handle value.
+  HandleType get() const;
+
+  // Returns the platform-specific handle value, releasing ownership of the
+  // handle.
+  HandleType release();
+
+  // Transfers ownership of the handle to a platform-specific scoper.
+  ScopedHandleType Take();
+
+ private:
+  ScopedHandleType handle_;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_PLATFORM_HANDLE_H_
diff --git a/base/files/scoped_platform_handle_posix.cc b/base/files/scoped_platform_handle_posix.cc
new file mode 100644
index 0000000..38ee85a6
--- /dev/null
+++ b/base/files/scoped_platform_handle_posix.cc
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_platform_handle.h"
+
+namespace base {
+
+bool ScopedPlatformHandle::is_valid() const {
+  return handle_.is_valid();
+}
+
+void ScopedPlatformHandle::reset() {
+  handle_.reset();
+}
+
+ScopedPlatformHandle::HandleType ScopedPlatformHandle::get() const {
+  return handle_.get();
+}
+
+ScopedPlatformHandle::HandleType ScopedPlatformHandle::release() {
+  return handle_.release();
+}
+
+}  // namespace base
diff --git a/base/files/scoped_platform_handle_unittest.cc b/base/files/scoped_platform_handle_unittest.cc
new file mode 100644
index 0000000..1b295854
--- /dev/null
+++ b/base/files/scoped_platform_handle_unittest.cc
@@ -0,0 +1,94 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_platform_handle.h"
+
+#include "base/files/file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+#include "base/win/scoped_handle.h"
+#elif defined(OS_POSIX)
+#include "base/files/scoped_file.h"
+#endif
+
+namespace base {
+namespace {
+
+class ScopedPlatformHandleTest : public testing::Test {
+ public:
+  ScopedPlatformHandleTest() { CHECK(temp_dir_.CreateUniqueTempDir()); }
+
+ protected:
+  ScopedPlatformHandle CreateValidHandle() {
+    return ScopedPlatformHandle(OpenTempFile().TakePlatformFile());
+  }
+
+ private:
+  base::File OpenTempFile() {
+    base::File temp_file(temp_dir_.GetPath().AppendASCII(
+                             base::StringPrintf("file_%d", next_file_id_)),
+                         base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    ++next_file_id_;
+    return temp_file;
+  }
+
+  ScopedTempDir temp_dir_;
+  int next_file_id_ = 1;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPlatformHandleTest);
+};
+
+TEST_F(ScopedPlatformHandleTest, Invalid) {
+  ScopedPlatformHandle default_value;
+  EXPECT_TRUE(!default_value.is_valid());
+
+  ScopedPlatformHandle null_value(nullptr);
+  EXPECT_TRUE(!null_value.is_valid());
+
+  default_value.reset();
+  null_value.reset();
+  EXPECT_TRUE(!default_value.is_valid());
+  EXPECT_TRUE(!null_value.is_valid());
+}
+
+TEST_F(ScopedPlatformHandleTest, BasicUsage) {
+  ScopedPlatformHandle handle_a = CreateValidHandle();
+  ScopedPlatformHandle handle_b = CreateValidHandle();
+  EXPECT_TRUE(handle_a.is_valid());
+  EXPECT_TRUE(handle_b.is_valid());
+
+  ScopedPlatformHandle::HandleType handle_a_value = handle_a.get();
+  ScopedPlatformHandle::HandleType handle_b_value = handle_b.get();
+  EXPECT_TRUE(handle_a.is_valid());
+  EXPECT_TRUE(handle_b.is_valid());
+
+  ScopedPlatformHandle::ScopedHandleType scoped_handle = handle_a.Take();
+  ScopedPlatformHandle::HandleType raw_handle = handle_b.release();
+  EXPECT_FALSE(handle_a.is_valid());
+  EXPECT_FALSE(handle_b.is_valid());
+
+  handle_a = ScopedPlatformHandle(std::move(scoped_handle));
+  handle_b = ScopedPlatformHandle(raw_handle);
+  EXPECT_TRUE(handle_a.is_valid());
+  EXPECT_TRUE(handle_b.is_valid());
+  EXPECT_EQ(handle_a_value, handle_a.get());
+  EXPECT_EQ(handle_b_value, handle_b.get());
+
+  handle_b = std::move(handle_a);
+  EXPECT_FALSE(handle_a.is_valid());
+  EXPECT_TRUE(handle_b.is_valid());
+  EXPECT_EQ(handle_a_value, handle_b.get());
+
+  handle_b.reset();
+  EXPECT_FALSE(handle_b.is_valid());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/files/scoped_platform_handle_win.cc b/base/files/scoped_platform_handle_win.cc
new file mode 100644
index 0000000..94235f2
--- /dev/null
+++ b/base/files/scoped_platform_handle_win.cc
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/scoped_platform_handle.h"
+
+namespace base {
+
+bool ScopedPlatformHandle::is_valid() const {
+  return handle_.IsValid();
+}
+
+void ScopedPlatformHandle::reset() {
+  handle_.Close();
+}
+
+ScopedPlatformHandle::HandleType ScopedPlatformHandle::get() const {
+  return handle_.Get();
+}
+
+ScopedPlatformHandle::HandleType ScopedPlatformHandle::release() {
+  return handle_.Take();
+}
+
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 31016f9..f86b9e9 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -156,7 +156,6 @@
 
 MemoryDumpManager::MemoryDumpManager()
     : delegate_(nullptr),
-      is_coordinator_(false),
       memory_tracing_enabled_(0),
       tracing_process_id_(kInvalidTracingProcessId),
       dumper_registrations_ignored_for_testing_(false),
@@ -214,14 +213,12 @@
   heap_profiling_enabled_ = true;
 }
 
-void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
-                                   bool is_coordinator) {
+void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate) {
   {
     AutoLock lock(lock_);
     DCHECK(delegate);
     DCHECK(!delegate_);
     delegate_ = delegate;
-    is_coordinator_ = is_coordinator;
     EnableHeapProfilingIfNeeded();
   }
 
@@ -460,21 +457,10 @@
                                     TRACE_ID_MANGLE(guid));
   MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
 
-  // Technically there is no need to grab the |lock_| here as the delegate is
-  // long-lived and can only be set by Initialize(), which is locked and
-  // necessarily happens before memory_tracing_enabled_ == true.
-  // Not taking the |lock_|, though, is lakely make TSan barf and, at this point
-  // (memory-infra is enabled) we're not in the fast-path anymore.
-  MemoryDumpManagerDelegate* delegate;
-  {
-    AutoLock lock(lock_);
-    delegate = delegate_;
-  }
-
   // The delegate will coordinate the IPC broadcast and at some point invoke
   // CreateProcessDump() to get a dump for the current process.
   MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
-  delegate->RequestGlobalMemoryDump(args, wrapped_callback);
+  delegate_->RequestGlobalMemoryDump(args, wrapped_callback);
 }
 
 void MemoryDumpManager::RequestGlobalDump(
@@ -862,7 +848,7 @@
       dump_scheduler_->NotifyPollingSupported();
 
     // Only coordinator process triggers periodic global memory dumps.
-    if (is_coordinator_)
+    if (delegate_->IsCoordinator())
       dump_scheduler_->NotifyPeriodicTriggerSupported();
   }
 
@@ -907,10 +893,6 @@
   return session_state_->IsDumpModeAllowed(dump_mode);
 }
 
-uint64_t MemoryDumpManager::GetTracingProcessId() const {
-  return delegate_->GetTracingProcessId();
-}
-
 MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
     MemoryDumpProvider* dump_provider,
     const char* name,
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 92cc2f4..c1f565c 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -22,6 +22,14 @@
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 
+// Forward declare |MemoryDumpManagerDelegateImplTest| so that we can make it a
+// friend of |MemoryDumpManager| and give it access to |SetInstanceForTesting|.
+namespace memory_instrumentation {
+
+class MemoryDumpManagerDelegateImplTest;
+
+}  // namespace memory_instrumentation
+
 namespace base {
 
 class SingleThreadTaskRunner;
@@ -54,13 +62,10 @@
   // On the other side, the MemoryDumpManager will not be fully operational
   // (i.e. will NACK any RequestGlobalMemoryDump()) until initialized.
   // Arguments:
-  //  is_coordinator: if true this MemoryDumpManager instance will act as a
-  //      coordinator and schedule periodic dumps (if enabled via TraceConfig);
-  //      false when the MemoryDumpManager is initialized in a slave process.
   //  delegate: inversion-of-control interface for embedder-specific behaviors
   //      (multiprocess handshaking). See the lifetime and thread-safety
   //      requirements in the |MemoryDumpManagerDelegate| docstring.
-  void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
+  void Initialize(MemoryDumpManagerDelegate* delegate);
 
   // (Un)Registers a MemoryDumpProvider instance.
   // Args:
@@ -135,7 +140,10 @@
   // retrieved by child processes only when tracing is enabled. This is
   // intended to express cross-process sharing of memory dumps on the
   // child-process side, without having to know its own child process id.
-  uint64_t GetTracingProcessId() const;
+  uint64_t GetTracingProcessId() const { return tracing_process_id_; }
+  void set_tracing_process_id(uint64_t tracing_process_id) {
+    tracing_process_id_ = tracing_process_id;
+  }
 
   // Returns the name for a the allocated_objects dump. Use this to declare
   // suballocator dumps from other dump providers.
@@ -156,6 +164,7 @@
   friend class MemoryDumpManagerDelegate;
   friend class MemoryDumpManagerTest;
   friend class MemoryDumpScheduler;
+  friend class memory_instrumentation::MemoryDumpManagerDelegateImplTest;
 
   // Descriptor used to hold information about registered MDPs.
   // Some important considerations about lifetime of this object:
@@ -350,9 +359,6 @@
 
   MemoryDumpManagerDelegate* delegate_;  // Not owned.
 
-  // When true, this instance is in charge of coordinating periodic dumps.
-  bool is_coordinator_;
-
   // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
   // to guard against disabling logging while dumping on another thread.
   Lock lock_;
@@ -388,9 +394,7 @@
   virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
                                        const MemoryDumpCallback& callback) = 0;
 
-  // Returns tracing process id of the current process. This is used by
-  // MemoryDumpManager::GetTracingProcessId.
-  virtual uint64_t GetTracingProcessId() const = 0;
+  virtual bool IsCoordinator() const = 0;
 
  protected:
   MemoryDumpManagerDelegate() {}
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 51d4194..330c75d 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -119,7 +119,8 @@
 // requests locally to the MemoryDumpManager instead of performing IPC dances.
 class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
  public:
-  MemoryDumpManagerDelegateForTesting() {
+  MemoryDumpManagerDelegateForTesting(bool is_coordinator)
+      : is_coordinator_(is_coordinator) {
     ON_CALL(*this, RequestGlobalMemoryDump(_, _))
         .WillByDefault(Invoke(
             this, &MemoryDumpManagerDelegateForTesting::CreateProcessDump));
@@ -129,13 +130,13 @@
                void(const MemoryDumpRequestArgs& args,
                     const MemoryDumpCallback& callback));
 
-  uint64_t GetTracingProcessId() const override {
-    NOTREACHED();
-    return MemoryDumpManager::kInvalidTracingProcessId;
-  }
+  bool IsCoordinator() const override { return is_coordinator_; }
 
   // Promote the CreateProcessDump to public so it can be used by test fixtures.
   using MemoryDumpManagerDelegate::CreateProcessDump;
+
+ private:
+  bool is_coordinator_;
 };
 
 class MockMemoryDumpProvider : public MemoryDumpProvider {
@@ -220,13 +221,12 @@
     mdm_.reset(new MemoryDumpManager());
     MemoryDumpManager::SetInstanceForTesting(mdm_.get());
     ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
-    delegate_.reset(new MemoryDumpManagerDelegateForTesting);
   }
 
   void TearDown() override {
     MemoryDumpManager::SetInstanceForTesting(nullptr);
-    mdm_.reset();
     delegate_.reset();
+    mdm_.reset();
     message_loop_.reset();
     TraceLog::DeleteForTesting();
   }
@@ -248,7 +248,8 @@
  protected:
   void InitializeMemoryDumpManager(bool is_coordinator) {
     mdm_->set_dumper_registrations_ignored_for_testing(true);
-    mdm_->Initialize(delegate_.get(), is_coordinator);
+    delegate_.reset(new MemoryDumpManagerDelegateForTesting(is_coordinator));
+    mdm_->Initialize(delegate_.get());
   }
 
   void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
@@ -897,7 +898,6 @@
   // initialization gets NACK-ed cleanly.
   {
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
-    EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
     RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                              MemoryDumpLevelOfDetail::DETAILED);
     EXPECT_FALSE(last_callback_success_);
@@ -906,9 +906,9 @@
   // Now late-initialize the MemoryDumpManager and check that the
   // RequestGlobalDump completes successfully.
   {
+    InitializeMemoryDumpManager(false /* is_coordinator */);
     EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
     EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
-    InitializeMemoryDumpManager(false /* is_coordinator */);
     RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
                              MemoryDumpLevelOfDetail::DETAILED);
     EXPECT_TRUE(last_callback_success_);
diff --git a/build/android/gradle/dependencies.jinja b/build/android/gradle/dependencies.jinja
index c7e884a8b..e978304 100644
--- a/build/android/gradle/dependencies.jinja
+++ b/build/android/gradle/dependencies.jinja
@@ -3,16 +3,22 @@
 {# found in the LICENSE file. #}
 {% macro expand_deps(variables, prefix) %}
 {% if variables is defined %}
+{% if variables.prebuilts is defined %}
 {% for path in variables.prebuilts %}
     {{ prefix }} files("{{ path }}")
 {% endfor %}
+{% endif %}
+{% if variables.java_project_deps is defined %}
 {% for proj in variables.java_project_deps %}
     {{ prefix }} project(":{{ proj }}")
 {% endfor %}
+{% endif %}
+{% if variables.android_project_deps is defined %}
 {% for proj in variables.android_project_deps %}
     {{ prefix }} project(path: ":{{ proj }}", configuration: "debug")
 {% endfor %}
 {% endif %}
+{% endif %}
 {% endmacro %}
 
 dependencies {
diff --git a/build/android/gradle/generate_gradle.py b/build/android/gradle/generate_gradle.py
index 7a8ec32..2044aa37 100755
--- a/build/android/gradle/generate_gradle.py
+++ b/build/android/gradle/generate_gradle.py
@@ -197,7 +197,10 @@
     return self.DepsInfo()['type']
 
   def ResZips(self):
-    return self.DepsInfo().get('owned_resources_zips')
+    return self.DepsInfo().get('owned_resources_zips', [])
+
+  def ResDirs(self):
+    return self.DepsInfo().get('owned_resources_dirs', [])
 
   def JavaFiles(self):
     if self._java_files is None:
@@ -213,7 +216,7 @@
     return [p for p in self.JavaFiles() if not p.startswith('..')]
 
   def PrebuiltJars(self):
-    return self.Gradle()['dependent_prebuilt_jars']
+    return self.Gradle().get('dependent_prebuilt_jars', [])
 
   def AllEntries(self):
     """Returns a list of all entries that the current entry depends on.
@@ -236,36 +239,30 @@
 class _ProjectContextGenerator(object):
   """Helper class to generate gradle build files"""
   def __init__(self, project_dir, build_vars, use_gradle_process_resources,
-      jinja_processor):
+      jinja_processor, split_projects):
     self.project_dir = project_dir
     self.build_vars = build_vars
     self.use_gradle_process_resources = use_gradle_process_resources
     self.jinja_processor = jinja_processor
+    self.split_projects = split_projects
 
-  def _GenJniLibs(self, entry):
-    native_section = entry.BuildConfig().get('native')
-    if native_section:
-      jni_libs = _CreateJniLibsDir(
-          constants.GetOutDirectory(), self.EntryOutputDir(entry),
-          native_section.get('libraries'))
-    else:
-      jni_libs = []
-    return jni_libs
+  def _GenJniLibs(self, root_entry):
+    libraries = []
+    for entry in self._GetEntries(root_entry):
+      libraries += entry.BuildConfig().get('native', [])
+    if libraries:
+      return _CreateJniLibsDir(constants.GetOutDirectory(),
+          self.EntryOutputDir(root_entry), libraries)
+    return []
 
-  def _GenJavaDirs(self, entry):
+  def _GenJavaDirs(self, root_entry):
+    java_files = []
+    for entry in self._GetEntries(root_entry):
+      java_files += entry.JavaFiles()
     java_dirs, excludes = _ComputeJavaSourceDirsAndExcludes(
-        constants.GetOutDirectory(), entry.JavaFiles())
-    if self.Srcjars(entry):
-      java_dirs.append(
-          os.path.join(self.EntryOutputDir(entry), _SRCJARS_SUBDIR))
+        constants.GetOutDirectory(), java_files)
     return java_dirs, excludes
 
-  def _GenResDirs(self, entry):
-    res_dirs = list(entry.DepsInfo().get('owned_resources_dirs', []))
-    if entry.ResZips():
-      res_dirs.append(os.path.join(self.EntryOutputDir(entry), _RES_SUBDIR))
-    return res_dirs
-
   def _GenCustomManifest(self, entry):
     """Returns the path to the generated AndroidManifest.xml.
 
@@ -297,43 +294,75 @@
   def _Relativize(self, entry, paths):
     return _RebasePath(paths, self.EntryOutputDir(entry))
 
-  def EntryOutputDir(self, entry):
-    return os.path.join(self.project_dir, entry.GradleSubdir())
-
-  def Srcjars(self, entry):
+  def _Srcjars(self, entry):
     srcjars = _RebasePath(entry.Gradle().get('bundled_srcjars', []))
     if not self.use_gradle_process_resources:
       srcjars += _RebasePath(entry.BuildConfig()['javac']['srcjars'])
     return srcjars
 
-  def GeneratedInputs(self, entry):
-    generated_inputs = []
-    generated_inputs.extend(self.Srcjars(entry))
-    generated_inputs.extend(_RebasePath(entry.ResZips()))
-    generated_inputs.extend(entry.GeneratedJavaFiles())
-    generated_inputs.extend(entry.PrebuiltJars())
-    return generated_inputs
+  def _GetEntries(self, entry):
+    if self.split_projects:
+      return [entry]
+    return entry.AllEntries()
 
-  def Generate(self, entry):
-    variables = {}
-    java_dirs, excludes = self._GenJavaDirs(entry)
-    variables['java_dirs'] = self._Relativize(entry, java_dirs)
-    variables['java_excludes'] = excludes
-    variables['jni_libs'] = self._Relativize(entry, self._GenJniLibs(entry))
-    variables['res_dirs'] = self._Relativize(entry, self._GenResDirs(entry))
-    android_manifest = entry.Gradle().get('android_manifest')
-    if not android_manifest:
-      android_manifest = self._GenCustomManifest(entry)
-    variables['android_manifest'] = self._Relativize(entry, android_manifest)
+  def EntryOutputDir(self, entry):
+    return os.path.join(self.project_dir, entry.GradleSubdir())
+
+  def AllSrcjars(self, root_entry):
+    srcjars = []
+    for entry in self._GetEntries(root_entry):
+      srcjars += self._Srcjars(entry)
+    return set(srcjars)
+
+  def AllResZips(self, root_entry):
+    res_zips = []
+    for entry in self._GetEntries(root_entry):
+      res_zips += entry.ResZips()
+    return set(_RebasePath(res_zips))
+
+  def GeneratedInputs(self, root_entry):
+    generated_inputs = set(self.AllResZips(root_entry))
+    generated_inputs.update(self.AllSrcjars(root_entry))
+    for entry in self._GetEntries(root_entry):
+      generated_inputs.update(entry.GeneratedJavaFiles())
+      generated_inputs.update(entry.PrebuiltJars())
+    return set(generated_inputs)
+
+  def Generate(self, root_entry):
     # TODO(agrieve): Add an option to use interface jars and see if that speeds
     # things up at all.
-    variables['prebuilts'] = self._Relativize(entry, entry.PrebuiltJars())
-    deps = [_ProjectEntry.FromBuildConfigPath(p)
-            for p in entry.Gradle()['dependent_android_projects']]
-    variables['android_project_deps'] = [d.ProjectName() for d in deps]
-    deps = [_ProjectEntry.FromBuildConfigPath(p)
-            for p in entry.Gradle()['dependent_java_projects']]
-    variables['java_project_deps'] = [d.ProjectName() for d in deps]
+    variables = {}
+    java_dirs, excludes = self._GenJavaDirs(root_entry)
+    java_dirs.sort()
+    variables['java_dirs'] = self._Relativize(root_entry, java_dirs)
+    variables['java_dirs'].append(_SRCJARS_SUBDIR)
+    variables['java_excludes'] = excludes
+    variables['jni_libs'] = self._Relativize(
+        root_entry, set(self._GenJniLibs(root_entry)))
+    variables['prebuilts'] = [
+        p for e in self._GetEntries(root_entry) for p in e.PrebuiltJars()]
+    variables['res_dirs'] = [
+        p for e in self._GetEntries(root_entry) for p in e.ResDirs()]
+    for entry in self._GetEntries(root_entry):
+      variables['prebuilts'] += entry.PrebuiltJars()
+      variables['res_dirs'] += entry.ResDirs()
+    variables['prebuilts'] = self._Relativize(
+        root_entry, set(variables['prebuilts']))
+    variables['res_dirs'] = self._Relativize(
+        root_entry, set(variables['res_dirs']))
+    variables['res_dirs'].append(_RES_SUBDIR)
+    android_manifest = root_entry.Gradle().get('android_manifest')
+    if not android_manifest:
+      android_manifest = self._GenCustomManifest(root_entry)
+    variables['android_manifest'] = self._Relativize(
+        root_entry, android_manifest)
+    if self.split_projects:
+      deps = [_ProjectEntry.FromBuildConfigPath(p)
+              for p in root_entry.Gradle()['dependent_android_projects']]
+      variables['android_project_deps'] = [d.ProjectName() for d in deps]
+      deps = [_ProjectEntry.FromBuildConfigPath(p)
+              for p in root_entry.Gradle()['dependent_java_projects']]
+      variables['java_project_deps'] = [d.ProjectName() for d in deps]
     return variables
 
 
@@ -611,6 +640,10 @@
   parser.add_argument('--use-gradle-process-resources',
                       action='store_true',
                       help='Have gradle generate R.java rather than ninja')
+  parser.add_argument('--split-projects',
+                      action='store_true',
+                      help='Split projects by their gn deps rather than '
+                           'combining all the dependencies of each target')
   args = parser.parse_args()
   if args.output_directory:
     constants.SetOutputDirectory(args.output_directory)
@@ -619,12 +652,17 @@
   devil_chromium.Initialize(output_directory=output_dir)
   run_tests_helper.SetLogLevel(args.verbose_count)
 
+  # TODO(wnwen): Fix packaging so that gradle resources work in this case.
+  if args.use_gradle_process_resources:
+    assert args.split_projects, (
+        'Gradle resources does not yet work without --split-projects.')
+
   _gradle_output_dir = os.path.abspath(
       args.project_dir.replace('$CHROMIUM_OUTPUT_DIR', output_dir))
   jinja_processor = jinja_template.JinjaProcessor(_FILE_DIR)
   build_vars = _ReadBuildVars(output_dir)
   generator = _ProjectContextGenerator(_gradle_output_dir, build_vars,
-      args.use_gradle_process_resources, jinja_processor)
+      args.use_gradle_process_resources, jinja_processor, args.split_projects)
   logging.warning('Creating project at: %s', generator.project_dir)
 
   if args.all:
@@ -649,9 +687,10 @@
   if args.all:
     main_entries = [e for e in main_entries if e.GetType() == 'android_apk']
 
-  all_entries = _FindAllProjectEntries(main_entries)
-  logging.info('Found %d dependent build_config targets.', len(all_entries))
-  entries = _CombineTestEntries(all_entries)
+  if args.split_projects:
+    main_entries = _FindAllProjectEntries(main_entries)
+    logging.info('Found %d dependent build_config targets.', len(main_entries))
+  entries = _CombineTestEntries(main_entries)
   logging.info('Creating %d projects for targets.', len(entries))
 
   logging.warning('Writing .gradle files...')
@@ -669,10 +708,10 @@
       generated_inputs.extend(generator.GeneratedInputs(entry))
       zip_tuples.extend(
           (s, os.path.join(generator.EntryOutputDir(entry), _SRCJARS_SUBDIR))
-          for s in generator.Srcjars(entry))
+          for s in generator.AllSrcjars(entry))
       zip_tuples.extend(
           (s, os.path.join(generator.EntryOutputDir(entry), _RES_SUBDIR))
-          for s in _RebasePath(entry.ResZips()))
+          for s in generator.AllResZips(entry))
       _WriteFile(
           os.path.join(generator.EntryOutputDir(entry), 'build.gradle'), data)
 
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 2d78933..fddca1b 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -27,14 +27,10 @@
   ]
 
   if (is_clang) {
-    rebased_android_toolchain_root =
-        rebase_path(android_toolchain_root, root_build_dir)
-    assert(rebased_android_toolchain_root != "")  # Mark as used.
     if (current_cpu == "mips64el") {
       cflags += [
-        # TODO(gordanac) Enable integrated-as.
-        "-fno-integrated-as",
-        "-B${rebased_android_toolchain_root}/bin",  # Else /usr/bin/as gets picked up.
+        # Have to force IAS for mips64.
+        "-fintegrated-as",
       ]
     }
   } else {
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc
index 96508cd..6829117 100644
--- a/cc/surfaces/compositor_frame_sink_support.cc
+++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -158,6 +158,8 @@
   if (!surface_manager_->using_surface_references())
     return;
 
+  SurfaceId last_surface_id = reference_tracker_.current_surface_id();
+
   // Populate list of surface references to add and remove based on reference
   // surfaces in current frame compared with the last frame. The list of
   // surface references includes references from both the pending and active
@@ -166,7 +168,6 @@
                                       active_referenced_surfaces,
                                       pending_referenced_surfaces);
 
-  SurfaceId last_surface_id = reference_tracker_.current_surface_id();
   UpdateSurfaceReferences(last_surface_id, local_surface_id);
 }
 
diff --git a/cc/surfaces/compositor_frame_sink_support_unittest.cc b/cc/surfaces/compositor_frame_sink_support_unittest.cc
index 7f5342d1..5e8f1fc 100644
--- a/cc/surfaces/compositor_frame_sink_support_unittest.cc
+++ b/cc/surfaces/compositor_frame_sink_support_unittest.cc
@@ -23,9 +23,10 @@
 namespace test {
 namespace {
 
-constexpr FrameSinkId kParentFrameSink(2, 1);
-constexpr FrameSinkId kChildFrameSink1(65563, 1);
-constexpr FrameSinkId kChildFrameSink2(65564, 1);
+constexpr FrameSinkId kDisplayFrameSink(2, 0);
+constexpr FrameSinkId kParentFrameSink(3, 0);
+constexpr FrameSinkId kChildFrameSink1(65563, 0);
+constexpr FrameSinkId kChildFrameSink2(65564, 0);
 constexpr FrameSinkId kArbitraryFrameSink(1337, 7331);
 
 std::vector<SurfaceId> empty_surface_ids() {
@@ -77,7 +78,9 @@
       : surface_manager_(SurfaceManager::LifetimeType::REFERENCES) {}
   ~CompositorFrameSinkSupportTest() override {}
 
-  CompositorFrameSinkSupport& parent_support() { return *supports_[0]; }
+  CompositorFrameSinkSupport& display_support() { return *supports_[0]; }
+
+  CompositorFrameSinkSupport& parent_support() { return *supports_[1]; }
   Surface* parent_surface() {
     return parent_support().current_surface_for_testing();
   }
@@ -85,12 +88,12 @@
     return parent_support().ReferenceTrackerForTesting();
   }
 
-  CompositorFrameSinkSupport& child_support1() { return *supports_[1]; }
+  CompositorFrameSinkSupport& child_support1() { return *supports_[2]; }
   Surface* child_surface1() {
     return child_support1().current_surface_for_testing();
   }
 
-  CompositorFrameSinkSupport& child_support2() { return *supports_[2]; }
+  CompositorFrameSinkSupport& child_support2() { return *supports_[3]; }
   Surface* child_surface2() {
     return child_support2().current_surface_for_testing();
   }
@@ -136,6 +139,10 @@
                                      begin_frame_source_.get()));
     surface_manager_.SetDependencyTracker(std::move(dependency_tracker));
     supports_.push_back(base::MakeUnique<CompositorFrameSinkSupport>(
+        this, &surface_manager_, kDisplayFrameSink, true /* is_root */,
+        true /* handles_frame_sink_id_invalidation */,
+        true /* needs_sync_points */));
+    supports_.push_back(base::MakeUnique<CompositorFrameSinkSupport>(
         this, &surface_manager_, kParentFrameSink, false /* is_root */,
         true /* handles_frame_sink_id_invalidation */,
         true /* needs_sync_points */));
@@ -177,6 +184,38 @@
   DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupportTest);
 };
 
+// The display root surface should have a surface reference from the top-level
+// root added/removed when a CompositorFrame is submitted with a new SurfaceId.
+TEST_F(CompositorFrameSinkSupportTest, RootSurfaceReceivesReferences) {
+  const SurfaceId display_id_first = MakeSurfaceId(kDisplayFrameSink, 1);
+  const SurfaceId display_id_second = MakeSurfaceId(kDisplayFrameSink, 2);
+
+  // Submit a CompositorFrame for the first display root surface.
+  display_support().SubmitCompositorFrame(
+      display_id_first.local_surface_id(),
+      MakeCompositorFrame({MakeSurfaceId(kParentFrameSink, 1)}));
+
+  // A surface reference from the top-level root is added and there shouldn't be
+  // a temporary reference.
+  EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty());
+  EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
+              UnorderedElementsAre(display_id_first));
+
+  // Submit a CompositorFrame for the second display root surface.
+  display_support().SubmitCompositorFrame(
+      display_id_second.local_surface_id(),
+      MakeCompositorFrame({MakeSurfaceId(kParentFrameSink, 2)}));
+
+  // A surface reference from the top-level root to |display_id_second| should
+  // be added and the reference to |display_root_first| removed.
+  EXPECT_THAT(GetTempReferences(kDisplayFrameSink), IsEmpty());
+  EXPECT_THAT(GetChildReferences(surface_manager().GetRootSurfaceId()),
+              UnorderedElementsAre(display_id_second));
+
+  // Surface |display_id_first| is unreachable and should get deleted.
+  EXPECT_EQ(nullptr, surface_manager().GetSurfaceForId(display_id_first));
+}
+
 // The parent Surface is blocked on |child_id1| and |child_id2|.
 TEST_F(CompositorFrameSinkSupportTest, DisplayCompositorLockingBlockedOnTwo) {
   const SurfaceId parent_id = MakeSurfaceId(kParentFrameSink, 1);
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 4cc3b46..050ae19 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -104,7 +104,7 @@
         android:layout_weight="0"
         android:visibility="invisible" />
 
-    <!-- Site suggestion tiles -->
+    <!-- Site suggestion tile grid -->
     <org.chromium.chrome.browser.suggestions.TileGridLayout
         android:id="@+id/tile_grid_layout"
         android:layout_width="wrap_content"
@@ -116,7 +116,7 @@
         android:paddingTop="@dimen/tile_grid_layout_padding_top"
         android:paddingBottom="4dp" />
 
-    <!-- Site suggestions tile grid placeholder -->
+    <!-- Site suggestion tile grid placeholder -->
     <ViewStub
         android:id="@+id/tile_grid_placeholder_stub"
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/tile_view.xml b/chrome/android/java/res/layout/tile_view.xml
index f820e8f..2dbcc11 100644
--- a/chrome/android/java/res/layout/tile_view.xml
+++ b/chrome/android/java/res/layout/tile_view.xml
@@ -12,39 +12,42 @@
     android:paddingStart="4dp"
     android:paddingEnd="4dp" >
 
+    <!-- The main icon. -->
     <ImageView
         android:id="@+id/tile_view_icon"
         android:layout_width="@dimen/tile_view_icon_size"
         android:layout_height="@dimen/tile_view_icon_size"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
-        android:layout_marginTop="12dp"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/tile_view_icon_margin_top"
         android:contentDescription="@null" />
 
+    <!-- The offline badge. -->
     <org.chromium.chrome.browser.widget.TintedImageView
         android:id="@+id/offline_badge"
         android:layout_width="@dimen/tile_view_offline_badge_size"
         android:layout_height="@dimen/tile_view_offline_badge_size"
-        android:layout_marginStart="48dp"
+        android:layout_gravity="top|end"
         android:visibility="gone"
         android:background="@drawable/offline_badge_background"
         android:contentDescription="@string/accessibility_ntp_offline_badge"
         chrome:tint="@color/tile_view_offline_badge_tint"
         android:src="@drawable/offline_pin_round" />
 
+    <!-- The touch highlight. -->
     <View
+        android:id="@+id/tile_view_highlight"
         android:layout_width="@dimen/tile_view_icon_size"
         android:layout_height="@dimen/tile_view_icon_size"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="12dp"
-        android:layout_marginTop="12dp"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="@dimen/tile_view_icon_margin_top"
         android:background="@drawable/tile_view_highlight" />
 
+    <!-- The title. -->
     <TextView
         android:id="@+id/tile_view_title"
-        android:layout_width="72dp"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="66dp"
+        android:layout_marginTop="@dimen/tile_view_title_margin_top"
         android:ellipsize="end"
         android:gravity="center_horizontal"
         android:lines="2"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 43bb7ce..8eb4862 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -276,8 +276,13 @@
     <dimen name="tile_grid_layout_max_horizontal_spacing">16dp</dimen>
     <dimen name="tile_view_bg_corner_radius">2dp</dimen>
     <dimen name="tile_view_width">80dp</dimen>
+    <dimen name="tile_view_width_condensed">64dp</dimen>
     <dimen name="tile_view_icon_size">48dp</dimen>
+    <dimen name="tile_view_icon_margin_top">12dp</dimen>
+    <dimen name="tile_view_icon_margin_top_condensed">8dp</dimen>
     <dimen name="tile_view_offline_badge_size">24dp</dimen>
+    <dimen name="tile_view_title_margin_top">66dp</dimen>
+    <dimen name="tile_view_title_margin_top_condensed">62dp</dimen>
     <dimen name="ntp_logo_height">116dp</dimen>
     <dimen name="ntp_search_box_height">62dp</dimen>
     <dimen name="ntp_search_box_shadow_width">4dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 3d2ad9a..9f24a05 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -132,6 +132,7 @@
     public static final String IMPROVED_A2HS = "ImprovedA2HS";
     public static final String NO_CREDIT_CARD_ABORT = "NoCreditCardAbort";
     public static final String NTP_CONDENSED_LAYOUT = "NTPCondensedLayout";
+    public static final String NTP_CONDENSED_TILE_LAYOUT = "NTPCondensedTileLayout";
     public static final String NTP_FAKE_OMNIBOX_TEXT = "NTPFakeOmniboxText";
     public static final String NTP_FOREIGN_SESSIONS_SUGGESTIONS = "NTPForeignSessionsSuggestions";
     public static final String NTP_OFFLINE_PAGES_FEATURE_NAME = "NTPOfflinePages";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 3d124dd..7484e5f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -37,7 +37,6 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tabmodel.DocumentModeAssassin;
 import org.chromium.chrome.browser.upgrade.UpgradeActivity;
-import org.chromium.content.browser.ChildProcessCreationParams;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.lang.reflect.Field;
@@ -125,7 +124,6 @@
 
         // Kick off long running IO tasks that can be done in parallel.
         mNativeInitializationController = new NativeInitializationController(this);
-        initializeChildProcessCreationParams();
         mNativeInitializationController.startBackgroundTasks(shouldAllocateChildConnection());
     }
 
@@ -135,11 +133,6 @@
         return true;
     }
 
-    /**
-     * Allow derived classes to initialize their own {@link ChildProcessCreationParams}.
-     */
-    protected void initializeChildProcessCreationParams() {}
-
     @Override
     public void postInflationStartup() {
         final View firstDrawView = getViewToBeDrawnBeforeInitializingNative();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 53d8d2f..57a49d7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -76,10 +76,16 @@
     private static final String PARAM_NTP_TILE_TITLE_LINES = "ntp_tile_title_lines";
 
     /**
-     * The maximum number of tiles to try and fit in a row. On smaller screens, there may not be
-     * enough space to fit all of them.
+     * Experiment parameter for whether to use the condensed tile layout on small screens.
      */
-    private static final int MAX_TILE_COLUMNS = 4;
+    private static final String PARAM_CONDENSED_TILE_LAYOUT_FOR_SMALL_SCREENS_ENABLED =
+            "condensed_tile_layout_for_small_screens_enabled";
+
+    /**
+     * Experiment parameter for whether to use the condensed tile layout on large screens.
+     */
+    private static final String PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED =
+            "condensed_tile_layout_for_large_screens_enabled";
 
     private NewTabPageRecyclerView mRecyclerView;
 
@@ -234,6 +240,7 @@
 
         mTileGridLayout = (TileGridLayout) mNewTabPageLayout.findViewById(R.id.tile_grid_layout);
         mTileGridLayout.setMaxRows(getMaxTileRows(searchProviderHasLogo));
+        mTileGridLayout.setMaxColumns(getMaxTileColumns());
         mTileGroup = new TileGroup(mActivity, mManager, mContextMenuManager, mTileGroupDelegate,
                 /* observer = */ this, offlinePageBridge, getTileTitleLines());
 
@@ -248,7 +255,7 @@
         mNewTabPageLayout.addOnLayoutChangeListener(this);
         setSearchProviderHasLogo(searchProviderHasLogo);
 
-        mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * MAX_TILE_COLUMNS);
+        mTileGroup.startObserving(getMaxTileRows(searchProviderHasLogo) * getMaxTileColumns());
 
         // Set up snippets
         NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout,
@@ -805,6 +812,20 @@
                 ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_NTP_MAX_TILE_ROWS, defaultValue);
     }
 
+    /**
+     * Determines The maximum number of tiles to try and fit in a row. On smaller screens, there
+     * may not be enough space to fit all of them.
+     */
+    private int getMaxTileColumns() {
+        if (!mUiConfig.getCurrentDisplayStyle().isSmall()
+                && ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                           ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT,
+                           PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED, false)) {
+            return 5;
+        }
+        return 4;
+    }
+
     private static int getTileTitleLines() {
         int defaultValue = 2;
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_CONDENSED_LAYOUT)) {
@@ -814,6 +835,17 @@
                 ChromeFeatureList.NTP_CONDENSED_LAYOUT, PARAM_NTP_TILE_TITLE_LINES, defaultValue);
     }
 
+    private boolean shouldUseCondensedTileLayout() {
+        if (mUiConfig.getCurrentDisplayStyle().isSmall()) {
+            return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                    ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT,
+                    PARAM_CONDENSED_TILE_LAYOUT_FOR_SMALL_SCREENS_ENABLED, false);
+        }
+        return ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                ChromeFeatureList.NTP_CONDENSED_TILE_LAYOUT,
+                PARAM_CONDENSED_TILE_LAYOUT_FOR_LARGE_SCREENS_ENABLED, false);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (mNewTabPageLayout != null) {
@@ -855,7 +887,8 @@
 
     @Override
     public void onTileDataChanged() {
-        mTileGroup.renderTileViews(mTileGridLayout, !mLoadHasCompleted);
+        mTileGroup.renderTileViews(
+                mTileGridLayout, !mLoadHasCompleted, shouldUseCondensedTileLayout());
         mSnapshotTileGridChanged = true;
 
         // The page contents are initially hidden; otherwise they'll be drawn centered on the page
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
index 11f5d1e..5a2563f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -107,11 +107,13 @@
             super(LayoutInflater.from(parentView.getContext())
                             .inflate(R.layout.suggestions_site_tile_grid, parentView, false));
             mLayout = (TileGridLayout) itemView;
+            mLayout.setMaxRows(getMaxTileRows());
+            mLayout.setMaxColumns(MAX_TILE_COLUMNS);
         }
 
         public void onBindViewHolder(TileGroup tileGroup) {
-            mLayout.setMaxRows(getMaxTileRows());
-            tileGroup.renderTileViews(mLayout, /* trackLoadTasks = */ false);
+            tileGroup.renderTileViews(mLayout, /* trackLoadTasks = */ false,
+                    /* condensed = */ false);
         }
 
         public void updateIconView(Tile tile) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
index 31d13d5..45341c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
@@ -19,16 +19,18 @@
  * A layout that arranges tiles in a grid.
  */
 public class TileGridLayout extends FrameLayout {
-    private static final int MAX_COLUMNS = 4;
+    private final int mVerticalSpacing;
+    private final int mMinHorizontalSpacing;
+    private final int mMaxHorizontalSpacing;
+    private final int mMaxWidth;
 
-    private int mVerticalSpacing;
-    private int mExtraVerticalSpacing;
-    private int mMinHorizontalSpacing;
-    private int mMaxHorizontalSpacing;
-    private int mMaxWidth;
     private int mMaxRows;
+    private int mMaxColumns;
+    private int mExtraVerticalSpacing;
 
     /**
+     * Constructor for inflating from XML.
+     *
      * @param context The view context in which this item will be shown.
      * @param attrs The attributes of the XML tag that is inflating the view.
      */
@@ -45,14 +47,20 @@
     }
 
     /**
-     * Sets the maximum number of rows to display. Any items that don't fit within these rows will
-     * be hidden.
+     * Sets the maximum number of rows to display. Any items that don't fit will be hidden.
      */
     public void setMaxRows(int rows) {
         mMaxRows = rows;
     }
 
     /**
+     * Sets the maximum number of columns to display. Any items that don't fit will be hidden.
+     */
+    public void setMaxColumns(int columns) {
+        mMaxColumns = columns;
+    }
+
+    /**
      * Sets the extra vertical spacing that must be used. It will be distributed evenly above each
      * row.
      */
@@ -105,7 +113,7 @@
         int childWidth = getChildAt(0).getMeasuredWidth();
         int numColumns = MathUtils.clamp(
                 (gridWidth + mMinHorizontalSpacing) / (childWidth + mMinHorizontalSpacing), 1,
-                MAX_COLUMNS);
+                mMaxColumns);
 
         // Ensure column spacing isn't greater than mMaxHorizontalSpacing.
         int gridWidthMinusColumns = Math.max(0, gridWidth - numColumns * childWidth);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
index ceaa781..8c8b078 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -242,8 +242,10 @@
      * possible because view inflation and icon loading are slow.
      * @param tileGridLayout The layout to render the tile views into.
      * @param trackLoadTasks Whether to track load tasks.
+     * @param condensed Whether to use a condensed layout.
      */
-    public void renderTileViews(TileGridLayout tileGridLayout, boolean trackLoadTasks) {
+    public void renderTileViews(
+            TileGridLayout tileGridLayout, boolean trackLoadTasks, boolean condensed) {
         // Map the old tile views by url so they can be reused later.
         Map<String, TileView> oldTileViews = new HashMap<>();
         int childCount = tileGridLayout.getChildCount();
@@ -259,7 +261,8 @@
         for (Tile tile : mTiles) {
             TileView tileView = oldTileViews.get(tile.getUrl());
             if (tileView == null) {
-                tileView = buildTileView(tile, tileGridLayout, trackLoadTasks, mTitleLinesCount);
+                tileView = buildTileView(
+                        tile, tileGridLayout, trackLoadTasks, mTitleLinesCount, condensed);
             } else {
                 tileView.updateIfDataChanged(tile);
             }
@@ -282,13 +285,14 @@
      * @param parentView The parent of the new tile view.
      * @param trackLoadTask Whether to track a load task.
      * @param titleLines The number of text lines to use for each tile title.
+     * @param condensed Whether to use a condensed layout.
      * @return The new tile view.
      */
-    private TileView buildTileView(
-            Tile tile, ViewGroup parentView, boolean trackLoadTask, int titleLines) {
+    private TileView buildTileView(Tile tile, ViewGroup parentView, boolean trackLoadTask,
+            int titleLines, boolean condensed) {
         TileView tileView = (TileView) LayoutInflater.from(parentView.getContext())
                                     .inflate(R.layout.tile_view, parentView, false);
-        tileView.initialize(tile, titleLines);
+        tileView.initialize(tile, titleLines, condensed);
 
         // Note: It is important that the callbacks below don't keep a reference to the tile or
         // modify them as there is no guarantee that the same tile would be used to update the view.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
index 0c36d8e..316e0a4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
@@ -5,7 +5,9 @@
 package org.chromium.chrome.browser.suggestions;
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.util.AttributeSet;
+import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -46,14 +48,43 @@
      * after inflation.
      * @param tile The tile that holds the data to populate this view.
      * @param titleLines The number of text lines to use for the tile title.
+     * @param condensed Whether to use a condensed layout.
      */
-    public void initialize(Tile tile, int titleLines) {
+    public void initialize(Tile tile, int titleLines, boolean condensed) {
         mTitleView.setLines(titleLines);
         mUrl = tile.getUrl();
+
+        // TODO(mvanouwerkerk): Move this code to xml - https://crbug.com/695817.
+        if (condensed) {
+            Resources res = getResources();
+
+            setPadding(0, 0, 0, 0);
+            LayoutParams tileParams = (LayoutParams) getLayoutParams();
+            tileParams.width = res.getDimensionPixelOffset(R.dimen.tile_view_width_condensed);
+            setLayoutParams(tileParams);
+
+            LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+            iconParams.setMargins(0,
+                    res.getDimensionPixelOffset(R.dimen.tile_view_icon_margin_top_condensed), 0, 0);
+            mIconView.setLayoutParams(iconParams);
+
+            View highlightView = findViewById(R.id.tile_view_highlight);
+            LayoutParams highlightParams = (LayoutParams) highlightView.getLayoutParams();
+            highlightParams.setMargins(0,
+                    res.getDimensionPixelOffset(R.dimen.tile_view_icon_margin_top_condensed), 0, 0);
+            highlightView.setLayoutParams(highlightParams);
+
+            LayoutParams titleParams = (LayoutParams) mTitleView.getLayoutParams();
+            titleParams.setMargins(0,
+                    res.getDimensionPixelOffset(R.dimen.tile_view_title_margin_top_condensed), 0,
+                    0);
+            mTitleView.setLayoutParams(titleParams);
+        }
+
         renderTile(tile);
     }
 
-    /** @return The url associated to this view. */
+    /** @return The url associated with this view. */
     public String getUrl() {
         return mUrl;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
index 7abec8c..39ed7ca4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java
@@ -133,6 +133,12 @@
         return sGooglePlayInstallState;
     }
 
+    /* Returns whether launching renderer in WebAPK process is enabled by Chrome. */
+    public static boolean canLaunchRendererInWebApkProcess() {
+        return isEnabled() && LibraryLoader.isInitialized()
+                && nativeCanLaunchRendererInWebApkProcess();
+    }
+
     /**
      * Check the cached value to figure out if the feature is enabled. We have to use the cached
      * value because native library may not yet been loaded.
@@ -179,5 +185,6 @@
     }
 
     private static native boolean nativeCanUseGooglePlayToInstallWebApk();
+    private static native boolean nativeCanLaunchRendererInWebApkProcess();
     private static native boolean nativeCanInstallFromUnknownSources();
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
index 360b5262..a5a6521 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -31,6 +31,9 @@
     /** Manages whether to check update for the WebAPK, and starts update check if needed. */
     private WebApkUpdateManager mUpdateManager;
 
+    /** Indicates whether launching renderer in WebAPK process is enabled. */
+    private boolean mCanLaunchRendererInWebApkProcess;
+
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
@@ -124,6 +127,7 @@
         super.finishNativeInitialization();
         if (!isInitialized()) return;
         getActivityTab().setWebappManifestScope(mWebappInfo.scopeUri().toString());
+        mCanLaunchRendererInWebApkProcess = ChromeWebApkHost.canLaunchRendererInWebApkProcess();
     }
 
     @Override
@@ -149,20 +153,14 @@
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
-        // WebAPK hosts Chrome's renderer processes by declaring the Chrome's renderer service in
-        // its AndroidManifest.xml. We set {@link ChildProcessCreationParams} for WebAPK's renderer
-        // process so the {@link ChildProcessLauncher} knows which application's renderer
-        // service to connect.
-        initializeChildProcessCreationParams(true);
-    }
+    public void onResumeWithNative() {
+        super.onResumeWithNative();
 
-    @Override
-    protected void initializeChildProcessCreationParams() {
-        // TODO(hanxi): crbug.com/611842. Investigates whether this function works for multiple
-        // windows or with --site-per-process enabled.
-        initializeChildProcessCreationParams(true);
+        // When launching Chrome renderer in WebAPK process is enabled, WebAPK hosts Chrome's
+        // renderer processes by declaring the Chrome's renderer service in its AndroidManifest.xml
+        // and sets {@link ChildProcessCreationParams} for WebAPK's renderer process so the
+        // {@link ChildProcessLauncher} knows which application's renderer service to connect to.
+        initializeChildProcessCreationParams(mCanLaunchRendererInWebApkProcess);
     }
 
     @Override
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 4f3c701..39c52c9 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -14463,6 +14463,12 @@
       <message name="IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed New Tab Page layout." translateable="false">
         Show a condensed layout on the New Tab Page.
       </message>
+      <message name="IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_NAME" desc="Name for the flag to enable the condensed tile layout on the New Tab Page." translateable="false">
+        Condensed NTP tile layout
+      </message>
+      <message name="IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_DESCRIPTION" desc="Description for the flag to enable the condensed tile layout on the New Tab Page." translateable="false">
+        Show a condensed tile layout on the New Tab Page.
+      </message>
       <message name="IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME" desc="Name for the flag to show a Google G in the omnibox on the New Tab Page." translateable="false">
         Google G in New Tab Page omnibox
       </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 13328e25..e73e74a 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -8,6 +8,11 @@
     </message>
   </if>
 
+  <!-- Shared across multiple pages -->
+  <message name="IDS_SETTINGS_MORE_ACTIONS" desc="Tooltip text (shows on hover or for screenreaders) for a button that shows a menu with more actions when clicked or tapped">
+    More actions...
+  </message>
+
   <!-- About Page -->
   <message name="IDS_SETTINGS_ABOUT_PAGE_BROWSER_VERSION" desc="The text label describing the version of the browser, example: Version 57.0.2937.0 (Developer Build) unknown (64-bit)">
     Version <ph name="PRODUCT_VERSION">$1<ex>15.0.865.0</ex></ph> (<ph name="PRODUCT_CHANNEL">$2<ex>Developer Build</ex></ph>) <ph name="PRODUCT_MODIFIER">$3</ph> <ph name="PRODUCT_VERSION_BITS">$4</ph>
@@ -319,9 +324,6 @@
   </message>
 
   <!-- Passwords and Autofill Page -->
-  <message name="IDS_SETTINGS_OVERFLOW_MENU" desc="Alt text for the overflow button on a list item. Triggers a context menu when clicked.">
-    Menu
-  </message>
   <message name="IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE" desc="Name of the settings page which allows managing passwords and autofill settings.">
     Passwords and forms
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 560bcaf..8a67168 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1559,6 +1559,7 @@
     "//rlz/features",
     "//services/image_decoder/public/cpp",
     "//services/preferences/public/interfaces/",
+    "//services/resource_coordinator:lib",
     "//services/service_manager/public/cpp",
     "//services/shape_detection/public/interfaces",
     "//skia",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b5c99f9..b532bf1 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -50,6 +50,7 @@
   "+services/image_decoder/public/interfaces",
   "+services/preferences/public/cpp",
   "+services/preferences/public/interfaces",
+  "+services/resource_coordinator",
   "+services/service_manager",
   "+services/shape_detection/public/interfaces",
   "+services/ui/public",
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index 59a9170f..2fa63d69 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -28,7 +28,7 @@
 per-file chrome_content_browser_client_browsertest.cc=*
 per-file chrome_content_browser_client_unittest.cc=*
 
-# Mojo manfiests
+# Mojo manifests
 per-file *manifest_overlay.json=set noparent
 per-file *manifest_overlay.json=file://ipc/SECURITY_OWNERS
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e203935..5dd3eb11 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -585,6 +585,21 @@
 #endif  // OS_ANDROID
 
 #if defined(OS_ANDROID)
+const FeatureEntry::FeatureParam kCondensedTileLayoutForSmallScreensEnabled[] =
+    {{"condensed_tile_layout_for_small_screens_enabled", "true"}};
+
+const FeatureEntry::FeatureParam kCondensedTileLayoutForLargeScreensEnabled[] =
+    {{"condensed_tile_layout_for_large_screens_enabled", "true"}};
+
+const FeatureEntry::FeatureVariation
+    kNTPCondensedTileLayoutFeatureVariations[] = {
+        {"(small screens)", kCondensedTileLayoutForSmallScreensEnabled,
+         arraysize(kCondensedTileLayoutForSmallScreensEnabled), nullptr},
+        {"(large screens)", kCondensedTileLayoutForLargeScreensEnabled,
+         arraysize(kCondensedTileLayoutForLargeScreensEnabled), nullptr}};
+#endif  // OS_ANDROID
+
+#if defined(OS_ANDROID)
 const FeatureEntry::Choice kUpdateMenuItemSummaryChoices[] = {
     {IDS_FLAGS_UPDATE_MENU_ITEM_NO_SUMMARY, "", ""},
     {IDS_FLAGS_UPDATE_MENU_ITEM_DEFAULT_SUMMARY,
@@ -1948,6 +1963,12 @@
     {"ntp-condensed-layout", IDS_FLAGS_NTP_CONDENSED_LAYOUT_NAME,
      IDS_FLAGS_NTP_CONDENSED_LAYOUT_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kNTPCondensedLayoutFeature)},
+    {"ntp-condensed-tile-layout", IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_NAME,
+     IDS_FLAGS_NTP_CONDENSED_TILE_LAYOUT_DESCRIPTION, kOsAndroid,
+     FEATURE_WITH_VARIATIONS_VALUE_TYPE(
+         chrome::android::kNTPCondensedTileLayoutFeature,
+         kNTPCondensedTileLayoutFeatureVariations,
+         ntp_snippets::kStudyName)},
     {"ntp-google-g-in-omnibox", IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_NAME,
      IDS_FLAGS_NTP_GOOGLE_G_IN_OMNIBOX_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::NTPShowGoogleGInOmniboxFeature)},
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index b8aa537..5e66ec0e 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -55,6 +55,7 @@
     &kImprovedA2HS,
     &kNoCreditCardAbort,
     &kNTPCondensedLayoutFeature,
+    &kNTPCondensedTileLayoutFeature,
     &kNTPFakeOmniboxTextFeature,
     &kNTPOfflinePagesFeature,
     &NTPShowGoogleGInOmniboxFeature,
@@ -138,6 +139,9 @@
 const base::Feature kNTPCondensedLayoutFeature{
     "NTPCondensedLayout", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kNTPCondensedTileLayoutFeature{
+    "NTPCondensedTileLayout", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 31f422f..1951766 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -27,6 +27,7 @@
 extern const base::Feature kImprovedA2HS;
 extern const base::Feature kNoCreditCardAbort;
 extern const base::Feature kNTPCondensedLayoutFeature;
+extern const base::Feature kNTPCondensedTileLayoutFeature;
 extern const base::Feature kNTPFakeOmniboxTextFeature;
 extern const base::Feature kNTPOfflinePagesFeature;
 extern const base::Feature NTPShowGoogleGInOmniboxFeature;
diff --git a/chrome/browser/android/webapk/chrome_webapk_host.cc b/chrome/browser/android/webapk/chrome_webapk_host.cc
index 0d73490..f7653c4e 100644
--- a/chrome/browser/android/webapk/chrome_webapk_host.cc
+++ b/chrome/browser/android/webapk/chrome_webapk_host.cc
@@ -13,6 +13,10 @@
 // Variations flag to enable installing WebAPKs using Google Play.
 const char* kPlayInstall = "play_install";
 
+// Variations flag to enable launching Chrome renderer in WebAPK process.
+const char* kLaunchRendererInWebApkProcess =
+    "launch_renderer_in_webapk_process";
+
 }  // anonymous namespace
 
 // static
@@ -42,6 +46,15 @@
 }
 
 // static
+jboolean CanLaunchRendererInWebApkProcess(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& clazz) {
+  return variations::GetVariationParamValueByFeature(
+             chrome::android::kImprovedA2HS, kLaunchRendererInWebApkProcess) ==
+         "true";
+}
+
+// static
 jboolean CanInstallFromUnknownSources(
     JNIEnv* env,
     const base::android::JavaParamRef<jclass>& clazz) {
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 1e20b66c..bf9b94a 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -197,6 +197,7 @@
 #include "printing/features/features.h"
 #include "services/image_decoder/public/interfaces/constants.mojom.h"
 #include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
@@ -3097,6 +3098,13 @@
       base::Bind(&metrics::LeakDetectorRemoteController::Create),
       ui_task_runner);
 #endif
+
+  registry->AddInterface(
+      base::Bind(
+          &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest,
+          base::Unretained(memory_instrumentation::CoordinatorImpl::GetInstance(
+              ui_task_runner))),
+      ui_task_runner);
 }
 
 void ChromeContentBrowserClient::ExposeInterfacesToMediaService(
@@ -3193,6 +3201,15 @@
   registry->AddInterface(
       base::Bind(&metrics::CallStackProfileCollector::Create,
                  metrics::CallStackProfileParams::GPU_PROCESS));
+
+  auto ui_task_runner = content::BrowserThread::GetTaskRunnerForThread(
+      content::BrowserThread::UI);
+  registry->AddInterface(
+      base::Bind(
+          &memory_instrumentation::CoordinatorImpl::BindCoordinatorRequest,
+          base::Unretained(memory_instrumentation::CoordinatorImpl::GetInstance(
+              ui_task_runner))),
+      ui_task_runner);
 }
 
 void ChromeContentBrowserClient::RegisterInProcessServices(
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
index 7cabf4c8..86b343b5 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.h
@@ -98,6 +98,10 @@
                            TestAttributePromptPageGetsLoaded);
   FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
                            TestAuthCodeGetsProperlyReceivedFromGaia);
+  FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
+                           TestActiveDirectoryEnrollment_Success);
+  FRIEND_TEST_ALL_PREFIXES(EnterpriseEnrollmentTest,
+                           TestActiveDirectoryEnrollment_UIErrors);
   FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, RequiresNoInput);
   FRIEND_TEST_ALL_PREFIXES(HandsOffNetworkScreenTest, ContinueClickedOnlyOnce);
   FRIEND_TEST_ALL_PREFIXES(EnrollmentScreenUnitTest, Retries);
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 2a75d861..41f22f90 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -14,6 +14,8 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/upstart_client.h"
 #include "content/public/test/test_utils.h"
 
 using testing::_;
@@ -22,6 +24,20 @@
 
 namespace chromeos {
 
+namespace {
+
+const char kAdMachineNameInput[] =
+    "document.querySelector('#oauth-enroll-ad-join-ui /deep/ "
+    "#machineNameInput')";
+const char kAdUsernameInput[] =
+    "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #userInput')";
+const char kAdPasswordInput[] =
+    "document.querySelector('#oauth-enroll-ad-join-ui /deep/ #passwordInput')";
+const char kAdTestRealm[] = "test_realm.com";
+const char kAdTestUser[] = "test_user@test_realm.com";
+
+}  // namespace
+
 class EnterpriseEnrollmentTest : public LoginManagerTest {
  public:
   EnterpriseEnrollmentTest()
@@ -41,7 +57,7 @@
   }
 
   using OnSetupEnrollmentHelper =
-      void (*)(EnterpriseEnrollmentHelperMock* mock);
+      std::function<void(EnterpriseEnrollmentHelperMock*)>;
 
   // The given function will be executed when the next enrollment helper is
   // created.
@@ -75,6 +91,29 @@
                           "}));");
   }
 
+  // Submits Active Directory domain join credentials.
+  void SubmitActiveDirectoryCredentials(const std::string& machine_name,
+                                        const std::string& username,
+                                        const std::string& password) {
+    EXPECT_TRUE(IsStepDisplayed("ad-join"));
+    js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".hidden");
+    js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".hidden");
+    js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".hidden");
+    const std::string set_machine_name =
+        std::string(kAdMachineNameInput) + ".value = '" + machine_name + "'";
+    const std::string set_username =
+        std::string(kAdUsernameInput) + ".value = '" + username + "'";
+    const std::string set_password =
+        std::string(kAdPasswordInput) + ".value = '" + password + "'";
+    js_checker().ExecuteAsync(set_machine_name);
+    js_checker().ExecuteAsync(set_username);
+    js_checker().ExecuteAsync(set_password);
+    js_checker().Evaluate(
+        "document.querySelector('#oauth-enroll-ad-join-ui /deep/ "
+        "#button').fire('tap')");
+    ExecutePendingJavaScript();
+  }
+
   void DisableAttributePromptUpdate() {
     AddEnrollmentSetupFunction(
         [](EnterpriseEnrollmentHelperMock* enrollment_helper) {
@@ -103,6 +142,19 @@
         });
   }
 
+  // Forces the Active Directory domain join flow during enterprise enrollment.
+  void SetupActiveDirectoryJoin() {
+    AddEnrollmentSetupFunction([this](
+        EnterpriseEnrollmentHelperMock* enrollment_helper) {
+      // Causes the attribute-prompt flow to activate.
+      EXPECT_CALL(*enrollment_helper, EnrollUsingAuthCode("test_auth_code", _))
+          .WillOnce(InvokeWithoutArgs([this]() {
+            this->enrollment_screen()->JoinDomain(base::BindOnce([](
+                const std::string& realm) { EXPECT_EQ(kAdTestRealm, realm); }));
+          }));
+    });
+  }
+
   // Fills out the UI with device attribute information and submits it.
   void SubmitAttributePromptUpdate() {
     // Fill out the attribute prompt info and submit it.
@@ -229,4 +281,73 @@
   enrollment_screen()->enrollment_helper_.reset();
 }
 
+// Shows the enrollment screen and mocks the enrollment helper to show Active
+// Directory domain join screen. Verifies the domain join screen is displayed.
+// Submits Active Directory credentials. Verifies that the AuthpolicyClient
+// calls us back with the correct realm.
+IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest,
+                       TestActiveDirectoryEnrollment_Success) {
+  ShowEnrollmentScreen();
+  DisableAttributePromptUpdate();
+  SetupActiveDirectoryJoin();
+  SubmitEnrollmentCredentials();
+
+  chromeos::DBusThreadManager::Get()
+      ->GetUpstartClient()
+      ->StartAuthPolicyService();
+
+  SubmitActiveDirectoryCredentials("machine_name", kAdTestUser, "password");
+  EXPECT_FALSE(IsStepDisplayed("ad-join"));
+
+  CompleteEnrollment();
+  // Verify that the success page is displayed.
+  EXPECT_TRUE(IsStepDisplayed("success"));
+  EXPECT_FALSE(IsStepDisplayed("error"));
+
+  // We have to remove the enrollment_helper before the dtor gets called.
+  enrollment_screen()->enrollment_helper_.reset();
+}
+
+// Shows the enrollment screen and mocks the enrollment helper to show Active
+// Directory domain join screen. Verifies the domain join screen is displayed.
+// Submits Active Directory different incorrect credentials. Verifies that the
+// correct error is displayed.
+IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentTest,
+                       TestActiveDirectoryEnrollment_UIErrors) {
+  ShowEnrollmentScreen();
+  SetupActiveDirectoryJoin();
+  SubmitEnrollmentCredentials();
+
+  chromeos::DBusThreadManager::Get()
+      ->GetUpstartClient()
+      ->StartAuthPolicyService();
+
+  // Checking error in case of empty password. Whether password is not empty
+  // being checked in the UI. Machine name length is checked after that in the
+  // authpolicyd.
+  SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser, "");
+  EXPECT_TRUE(IsStepDisplayed("ad-join"));
+  js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid");
+  js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".isInvalid");
+  js_checker().ExpectTrue(std::string(kAdPasswordInput) + ".isInvalid");
+
+  // Checking error in case of too long machine name.
+  SubmitActiveDirectoryCredentials("too_long_machine_name", kAdTestUser,
+                                   "password");
+  EXPECT_TRUE(IsStepDisplayed("ad-join"));
+  js_checker().ExpectTrue(std::string(kAdMachineNameInput) + ".isInvalid");
+  js_checker().ExpectFalse(std::string(kAdUsernameInput) + ".isInvalid");
+  js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".isInvalid");
+
+  // Checking error in case of bad username (without realm).
+  SubmitActiveDirectoryCredentials("machine_name", "test_user", "password");
+  EXPECT_TRUE(IsStepDisplayed("ad-join"));
+  js_checker().ExpectFalse(std::string(kAdMachineNameInput) + ".isInvalid");
+  js_checker().ExpectTrue(std::string(kAdUsernameInput) + ".isInvalid");
+  js_checker().ExpectFalse(std::string(kAdPasswordInput) + ".isInvalid");
+
+  // We have to remove the enrollment_helper before the dtor gets called.
+  enrollment_screen()->enrollment_helper_.reset();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
index 396b7bcc..079cdc3 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html
@@ -33,7 +33,7 @@
       <span hidden$="[[!device.connecting]]">$i18n{bluetoothConnecting}</span>
       <div hidden$="[[!device.paired]]">
         <paper-icon-button icon="cr:more-vert" on-tap="onMenuButtonTap_"
-            tabindex$="[[tabindex]]">
+            tabindex$="[[tabindex]]" title="$i18n{moreActions}">
         </paper-icon-button>
         <dialog id="dotsMenu" is="cr-action-menu">
           <button class="dropdown-item" role="option"
diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html
index 35b41ee..5ad62f5 100644
--- a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html
+++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html
@@ -31,7 +31,7 @@
       </div>
       <div class="name">[[model.name]]</div>
       <paper-icon-button id="dots" icon="cr:more-vert"
-          on-tap="onDotsTap_"></paper-icon-button>
+          title="$i18n{moreActions}" on-tap="onDotsTap_"></paper-icon-button>
       <template is="cr-lazy-render" id="menu">
         <dialog is="cr-action-menu">
           <button class="dropdown-item" role="option" id="view"
diff --git a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
index e5482d8..07f09756 100644
--- a/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_known_networks_page.html
@@ -22,7 +22,8 @@
           <div class="settings-box self-stretch">
             <div class="start">[[item.Name]]</div>
             <paper-icon-button preferred icon="cr:more-vert"
-                tabindex$="[[tabindex]]" on-tap="onMenuButtonTap_">
+                tabindex$="[[tabindex]]" on-tap="onMenuButtonTap_"
+                title="$i18n{moreActions}">
             </paper-icon-button>
           </div>
         </template>
@@ -35,7 +36,7 @@
           <div class="settings-box self-stretch">
             <div class="start">[[item.Name]]</div>
             <paper-icon-button icon="cr:more-vert"  tabindex$="[[tabindex]]"
-                on-tap="onMenuButtonTap_">
+                on-tap="onMenuButtonTap_" title="$i18n{moreActions}">
             </paper-icon-button>
           </div>
         </template>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index 078c9a6..2271af5 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -122,7 +122,8 @@
                 </template>
 </if>
                 <paper-icon-button id="more-[[item.language.code]]"
-                    icon="cr:more-vert" on-tap="onDotsTap_">
+                    icon="cr:more-vert" on-tap="onDotsTap_"
+                    title="$i18n{moreActions}">
                 </paper-icon-button>
               </div>
             </template>
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html
index 1a1c0893..1a68b89d 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html
@@ -24,7 +24,8 @@
       </div>
       <template is="dom-if" if="[[editable]]">
         <paper-icon-button id="dots" icon="cr:more-vert"
-            tabindex$="[[tabindex]]" on-tap="onDotsTap_">
+            tabindex$="[[tabindex]]" on-tap="onDotsTap_"
+            title="$i18n{moreActions}">
         </paper-icon-button>
         <template is="cr-lazy-render" id="menu">
           <dialog is="cr-action-menu">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
index 8a3fc74c..fd464fc 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -77,7 +77,7 @@
             </div>
             <template is="dom-if" if="[[item.metadata.isLocal]]">
               <paper-icon-button id="addressMenu" icon="cr:more-vert"
-                  on-tap="onAddressMenuTap_" alt="$i18n{overflowMenu}">
+                  on-tap="onAddressMenuTap_" title="$i18n{moreActions}">
               </paper-icon-button>
             </template>
             <template is="dom-if" if="[[!item.metadata.isLocal]]">
@@ -135,7 +135,7 @@
                   class="expiration-date">[[expiration_(item)]]</div>
               <template is="dom-if" if="[[item.metadata.isLocal]]">
                 <paper-icon-button id="creditCardMenu" icon="cr:more-vert"
-                    on-tap="onCreditCardMenuTap_" alt="$i18n{overflowMenu}">
+                    on-tap="onCreditCardMenuTap_" title="$i18n{moreActions}">
                 </paper-icon-button>
               </template>
               <template is="dom-if" if="[[!item.metadata.isLocal]]">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
index b857b200..04806d4 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -100,7 +100,7 @@
                   value="[[getEmptyPassword_(item.numCharactersInPassword)]]">
               </input>
               <paper-icon-button id="passwordMenu" icon="cr:more-vert"
-                  on-tap="onPasswordMenuTap_" alt="$i18n{overflowMenu}"
+                  on-tap="onPasswordMenuTap_" title="$i18n{moreActions}"
                   tabindex$="[[tabIndex]]">
               </paper-icon-button>
             </div>
@@ -137,7 +137,7 @@
           <paper-icon-button id="removeExceptionButton"
               icon="cr:close" on-tap="onRemoveExceptionButtonTap_"
               tabindex$="[[tabIndex]]"
-              alt="$i18n{deletePasswordException}">
+              title="$i18n{deletePasswordException}">
           </paper-icon-button>
         </div>
       </template>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers_list.html b/chrome/browser/resources/settings/printing_page/cups_printers_list.html
index e3d456fe..8a7f683c 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers_list.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printers_list.html
@@ -39,7 +39,8 @@
           <span class="name" id="printer-name">[[item.printerName]]</span>
           <!--TODO(xdai): Add icon for enterprise CUPS printer. -->
         </div>
-        <paper-icon-button icon="cr:more-vert" on-tap="onOpenActionMenuTap_">
+        <paper-icon-button icon="cr:more-vert" on-tap="onOpenActionMenuTap_"
+            title="$i18n{moreActions}">
         </paper-icon-button>
       </div>
     </template>
diff --git a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html
index 5496507..68407ef 100644
--- a/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html
+++ b/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html
@@ -26,7 +26,7 @@
       </div>
       <div class="keyword-column">[[engine.keyword]]</div>
       <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]"
-          on-tap="onDotsTap_">
+          on-tap="onDotsTap_" title="$i18n{moreActions}">
       </paper-icon-button>
       <dialog is="cr-action-menu">
         <button class="dropdown-item" role="option" on-tap="onManageTap_"
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
index 600e4c54..033e9fae 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html
@@ -59,7 +59,7 @@
       <div id="keyword-column">[[engine.keyword]]</div>
       <div id="url-column" class="text-elide">[[engine.url]]</div>
       <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]"
-          on-tap="onDotsTap_">
+          on-tap="onDotsTap_" title="$i18n{moreActions}">
       </paper-icon-button>
       <dialog is="cr-action-menu">
         <button class="dropdown-item" role="option" on-tap="onMakeDefaultTap_"
diff --git a/chrome/browser/resources/settings/site_settings/protocol_handlers.html b/chrome/browser/resources/settings/site_settings/protocol_handlers.html
index 58a391e..33fbfec 100644
--- a/chrome/browser/resources/settings/site_settings/protocol_handlers.html
+++ b/chrome/browser/resources/settings/site_settings/protocol_handlers.html
@@ -49,7 +49,7 @@
             </div>
 
             <paper-icon-button icon="cr:more-vert" on-tap="showMenu_"
-                class="dropdown-trigger">
+                class="dropdown-trigger" title="$i18n{moreActions}">
             </paper-icon-button>
           </div>
 
diff --git a/chrome/browser/resources/settings/site_settings/site_list.html b/chrome/browser/resources/settings/site_settings/site_list.html
index 6f2117f..3fa1a14 100644
--- a/chrome/browser/resources/settings/site_settings/site_list.html
+++ b/chrome/browser/resources/settings/site_settings/site_list.html
@@ -85,7 +85,7 @@
 
             <paper-icon-button id="dots" icon="cr:more-vert"
                 hidden="[[isActionMenuHidden_(item.source)]]"
-                on-tap="onShowActionMenuTap_">
+                on-tap="onShowActionMenuTap_" title="$i18n{moreActions}">
             </paper-icon-button>
             <template is="dom-if" if="[[enableSiteSettings_]]">
               <div on-tap="onOriginTap_" actionable>
diff --git a/chrome/browser/resources/settings/site_settings/usb_devices.html b/chrome/browser/resources/settings/site_settings/usb_devices.html
index 6abb7e3b0..57a312c 100644
--- a/chrome/browser/resources/settings/site_settings/usb_devices.html
+++ b/chrome/browser/resources/settings/site_settings/usb_devices.html
@@ -31,7 +31,7 @@
           <div class="middle">[[item.origin]]</div>
 
           <paper-icon-button icon="cr:more-vert" on-tap="showMenu_"
-              class="dropdown-trigger">
+              class="dropdown-trigger" title="$i18n{moreActions}">
           </paper-icon-button>
         </div>
       </div>
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index 9f0642c..6e80660 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -44,7 +44,11 @@
 namespace {
 
 // The size of each step unlaunched apps should increase their relevance by.
-const double kUnlaunchedAppRelevanceStepSize = 0.0001;
+constexpr double kUnlaunchedAppRelevanceStepSize = 0.0001;
+
+// The minimum capacity we reserve in the Apps container which will be filled
+// with extensions and ARC apps, to avoid successive reallocation.
+constexpr size_t kMinimumReservedAppsContainerCapacity = 60U;
 }
 
 namespace app_list {
@@ -58,21 +62,31 @@
       const base::Time& install_time)
       : data_source_(data_source),
         id_(id),
-        indexed_name_(base::UTF8ToUTF16(name)),
+        name_(base::UTF8ToUTF16(name)),
         last_launch_time_(last_launch_time),
         install_time_(install_time) {}
   ~App() {}
 
+  TokenizedString* GetTokenizedIndexedName() {
+    // Tokenizing a string is expensive. Don't pay the price for it at
+    // construction of every App, but rather, only when needed (i.e. when the
+    // query is not empty and cache the result.
+    if (!tokenized_indexed_name_)
+      tokenized_indexed_name_ = base::MakeUnique<TokenizedString>(name_);
+    return tokenized_indexed_name_.get();
+  }
+
   AppSearchProvider::DataSource* data_source() { return data_source_; }
   const std::string& id() const { return id_; }
-  const TokenizedString& indexed_name() const { return indexed_name_; }
+  const base::string16& name() const { return name_; }
   const base::Time& last_launch_time() const { return last_launch_time_; }
   const base::Time& install_time() const { return install_time_; }
 
  private:
   AppSearchProvider::DataSource* data_source_;
+  std::unique_ptr<TokenizedString> tokenized_indexed_name_;
   const std::string id_;
-  const TokenizedString indexed_name_;
+  const base::string16 name_;
   const base::Time last_launch_time_;
   const base::Time install_time_;
 
@@ -131,8 +145,8 @@
       AppListControllerDelegate* list_controller,
       AppListItemList* top_level_item_list,
       bool is_recommended) override {
-    return std::unique_ptr<AppResult>(new ExtensionAppResult(
-        profile(), app_id, list_controller, is_recommended));
+    return base::MakeUnique<ExtensionAppResult>(
+        profile(), app_id, list_controller, is_recommended);
   }
 
   // extensions::ExtensionRegistryObserver overrides:
@@ -165,11 +179,10 @@
         continue;
       }
 
-      std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App(
+      apps->emplace_back(base::MakeUnique<AppSearchProvider::App>(
           this, extension->id(), extension->short_name(),
           prefs->GetLastLaunchTime(extension->id()),
           prefs->GetInstallTime(extension->id())));
-      apps->push_back(std::move(app));
     }
   }
 
@@ -210,10 +223,9 @@
       if (!app_info->launchable || !app_info->showInLauncher)
         continue;
 
-      std::unique_ptr<AppSearchProvider::App> app(new AppSearchProvider::App(
+      apps->emplace_back(base::MakeUnique<AppSearchProvider::App>(
           this, app_id, app_info->name, app_info->last_launch_time,
           app_info->install_time));
-      apps->push_back(std::move(app));
     }
   }
 
@@ -222,8 +234,8 @@
       AppListControllerDelegate* list_controller,
       AppListItemList* top_level_item_list,
       bool is_recommended) override {
-    return std::unique_ptr<AppResult>(
-        new ArcAppResult(profile(), app_id, list_controller, is_recommended));
+    return base::MakeUnique<ArcAppResult>(profile(), app_id, list_controller,
+                                          is_recommended);
   }
 
   // ArcAppListPrefs::Observer overrides:
@@ -256,16 +268,12 @@
       top_level_item_list_(top_level_item_list),
       clock_(std::move(clock)),
       update_results_factory_(this) {
-  data_sources_.push_back(
-      std::unique_ptr<DataSource>(new ExtensionDataSource(profile, this)));
+  data_sources_.emplace_back(
+      base::MakeUnique<ExtensionDataSource>(profile, this));
 #if defined(OS_CHROMEOS)
-  if (arc::IsArcAllowedForProfile(profile)) {
-    data_sources_.push_back(
-        std::unique_ptr<DataSource>(new ArcDataSource(profile, this)));
-  }
+  if (arc::IsArcAllowedForProfile(profile))
+    data_sources_.emplace_back(base::MakeUnique<ArcDataSource>(profile, this));
 #endif
-
-  RefreshApps();
 }
 
 AppSearchProvider::~AppSearchProvider() {}
@@ -273,12 +281,10 @@
 void AppSearchProvider::Start(bool /*is_voice_query*/,
                               const base::string16& query) {
   query_ = query;
-  ClearResults();
-
-  bool show_recommendations = query.empty();
+  const bool show_recommendations = query.empty();
   // Refresh list of apps to ensure we have the latest launch time information.
   // This will also cause the results to update.
-  if (show_recommendations)
+  if (show_recommendations || apps_.empty())
     RefreshApps();
 
   UpdateResults();
@@ -289,27 +295,29 @@
 
 void AppSearchProvider::RefreshApps() {
   apps_.clear();
-  for (auto& data_source : data_sources_) {
+  apps_.reserve(kMinimumReservedAppsContainerCapacity);
+  for (auto& data_source : data_sources_)
     data_source->AddApps(&apps_);
-  }
 }
 
 void AppSearchProvider::UpdateResults() {
-  const TokenizedString query_terms(query_);
-  bool show_recommendations = query_.empty();
-  ClearResults();
+  const bool show_recommendations = query_.empty();
 
+  // No need to clear the current results as we will swap them with
+  // |new_results| at the end.
+  SearchProvider::Results new_results;
+  const size_t apps_size = apps_.size();
+  new_results.reserve(apps_size);
   if (show_recommendations) {
     // Build a map of app ids to their position in the app list.
     std::map<std::string, size_t> id_to_app_list_index;
-    for (size_t i = 0; i < top_level_item_list_->item_count(); ++i) {
+    for (size_t i = 0; i < top_level_item_list_->item_count(); ++i)
       id_to_app_list_index[top_level_item_list_->item_at(i)->id()] = i;
-    }
 
     for (auto& app : apps_) {
       std::unique_ptr<AppResult> result = app->data_source()->CreateResult(
           app->id(), list_controller_, top_level_item_list_, true);
-      result->set_title(app->indexed_name().text());
+      result->set_title(app->name());
 
       // Use the app list order to tiebreak apps that have never been launched.
       // The apps that have been installed or launched recently should be
@@ -318,34 +326,37 @@
                                   ? app->install_time()
                                   : app->last_launch_time();
       if (time.is_null()) {
-        auto it = id_to_app_list_index.find(app->id());
+        const auto& it = id_to_app_list_index.find(app->id());
         // If it's in a folder, it won't be in |id_to_app_list_index|. Rank
         // those as if they are at the end of the list.
-        size_t app_list_index =
-            it == id_to_app_list_index.end() ? apps_.size() : (*it).second;
-        if (app_list_index > apps_.size())
-          app_list_index = apps_.size();
+        const size_t app_list_index = (it == id_to_app_list_index.end())
+                                          ? apps_size
+                                          : std::min(apps_size, it->second);
 
         result->set_relevance(kUnlaunchedAppRelevanceStepSize *
-                              (apps_.size() - app_list_index));
+                              (apps_size - app_list_index));
       } else {
         result->UpdateFromLastLaunchedOrInstalledTime(clock_->Now(), time);
       }
-      Add(std::move(result));
+      new_results.emplace_back(std::move(result));
     }
   } else {
+    const TokenizedString query_terms(query_);
     for (auto& app : apps_) {
       std::unique_ptr<AppResult> result = app->data_source()->CreateResult(
           app->id(), list_controller_, top_level_item_list_, false);
       TokenizedStringMatch match;
-      if (!match.Calculate(query_terms, app->indexed_name()))
+      TokenizedString* indexed_name = app->GetTokenizedIndexedName();
+      if (!match.Calculate(query_terms, *indexed_name))
         continue;
 
-      result->UpdateFromMatch(app->indexed_name(), match);
-      Add(std::move(result));
+      result->UpdateFromMatch(*indexed_name, match);
+      new_results.emplace_back(std::move(result));
     }
   }
 
+  SwapResults(&new_results);
+
   update_results_factory_.InvalidateWeakPtrs();
 }
 
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.h b/chrome/browser/ui/app_list/search/app_search_provider.h
index 4273c2e..a957ce41a 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.h
+++ b/chrome/browser/ui/app_list/search/app_search_provider.h
@@ -28,7 +28,7 @@
  public:
   class App;
   class DataSource;
-  typedef std::vector<std::unique_ptr<App>> Apps;
+  using Apps = std::vector<std::unique_ptr<App>>;
 
   AppSearchProvider(Profile* profile,
                     AppListControllerDelegate* list_controller,
diff --git a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
index 5ee16d4..5fe60f5 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider_unittest.cc
@@ -73,9 +73,8 @@
 
     // Sort results by relevance.
     std::vector<SearchResult*> sorted_results;
-    std::copy(app_search_->results().begin(),
-              app_search_->results().end(),
-              std::back_inserter(sorted_results));
+    for (const auto& result : app_search_->results())
+      sorted_results.emplace_back(result.get());
     std::sort(sorted_results.begin(), sorted_results.end(), &MoreRelevant);
 
     std::string result_str;
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc
index 5079b99..7467dab7 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.cc
+++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -56,9 +56,9 @@
 }
 
 std::unique_ptr<SearchResult> ArcAppResult::Duplicate() const {
-  std::unique_ptr<SearchResult> copy(
-      new ArcAppResult(profile(), app_id(), controller(),
-                       display_type() == DISPLAY_RECOMMENDATION));
+  std::unique_ptr<SearchResult> copy =
+      base::MakeUnique<ArcAppResult>(profile(), app_id(), controller(),
+                                     display_type() == DISPLAY_RECOMMENDATION);
   copy->set_title(title());
   copy->set_title_tags(title_tags());
   copy->set_relevance(relevance());
diff --git a/chrome/browser/ui/app_list/search/extension_app_result.cc b/chrome/browser/ui/app_list/search/extension_app_result.cc
index 877fc96..52ff6ab 100644
--- a/chrome/browser/ui/app_list/search/extension_app_result.cc
+++ b/chrome/browser/ui/app_list/search/extension_app_result.cc
@@ -90,9 +90,9 @@
 }
 
 std::unique_ptr<SearchResult> ExtensionAppResult::Duplicate() const {
-  std::unique_ptr<SearchResult> copy(
-      new ExtensionAppResult(profile(), app_id(), controller(),
-                             display_type() == DISPLAY_RECOMMENDATION));
+  std::unique_ptr<SearchResult> copy = base::MakeUnique<ExtensionAppResult>(
+      profile(), app_id(), controller(),
+      display_type() == DISPLAY_RECOMMENDATION);
   copy->set_title(title());
   copy->set_title_tags(title_tags());
   copy->set_relevance(relevance());
diff --git a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
index 8f8871f..cf331fb 100644
--- a/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/launcher_search/launcher_search_provider.cc
@@ -16,8 +16,8 @@
 
 namespace {
 
-const int kLauncherSearchProviderQueryDelayInMs = 100;
-const int kLauncherSearchProviderMaxResults = 6;
+constexpr int kLauncherSearchProviderQueryDelayInMs = 100;
+constexpr int kLauncherSearchProviderMaxResults = 6;
 
 }  // namespace
 
@@ -64,11 +64,12 @@
   extension_results_[extension_id] = std::move(results);
 
   // Update results with other extension results.
-  ClearResults();
+  SearchProvider::Results new_results;
   for (const auto& item : extension_results_) {
     for (const auto& result : item.second)
-      Add(result->Duplicate());
+      new_results.emplace_back(result->Duplicate());
   }
+  SwapResults(&new_results);
 }
 
 void LauncherSearchProvider::DelayQuery(const base::Closure& closure) {
diff --git a/chrome/browser/ui/app_list/search/omnibox_provider.cc b/chrome/browser/ui/app_list/search/omnibox_provider.cc
index e9f990d..52c8c9a 100644
--- a/chrome/browser/ui/app_list/search/omnibox_provider.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_provider.cc
@@ -47,21 +47,20 @@
 }
 
 void OmniboxProvider::PopulateFromACResult(const AutocompleteResult& result) {
-  ClearResults();
-  for (ACMatches::const_iterator it = result.begin();
-       it != result.end();
-       ++it) {
-    if (!it->destination_url.is_valid())
+  SearchProvider::Results new_results;
+  new_results.reserve(result.size());
+  for (const AutocompleteMatch& match : result) {
+    if (!match.destination_url.is_valid())
       continue;
 
-    Add(std::unique_ptr<SearchResult>(new OmniboxResult(
-        profile_, list_controller_, controller_.get(), is_voice_query_, *it)));
+    new_results.emplace_back(base::MakeUnique<OmniboxResult>(
+        profile_, list_controller_, controller_.get(), is_voice_query_, match));
   }
+  SwapResults(&new_results);
 }
 
 void OmniboxProvider::OnResultChanged(bool default_match_changed) {
-  const AutocompleteResult& result = controller_->result();
-  PopulateFromACResult(result);
+  PopulateFromACResult(controller_->result());
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index 1239302..3506a1f 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -33,18 +33,19 @@
 namespace {
 
 // Maximum number of results to show in each mixer group.
-const size_t kMaxAppsGroupResults = 8;
-const size_t kMaxOmniboxResults = 4;
-const size_t kMaxWebstoreResults = 2;
-const size_t kMaxSuggestionsResults = 6;
+constexpr size_t kMaxAppsGroupResults = 8;
+constexpr size_t kMaxOmniboxResults = 4;
+constexpr size_t kMaxWebstoreResults = 2;
+constexpr size_t kMaxSuggestionsResults = 6;
 
 #if defined(OS_CHROMEOS)
-const size_t kMaxLauncherSearchResults = 2;
+constexpr size_t kMaxLauncherSearchResults = 2;
 #endif
 
 // Constants related to the SuggestionsService in AppList field trial.
-const char kSuggestionsProviderFieldTrialName[] = "SuggestionsAppListProvider";
-const char kSuggestionsProviderFieldTrialEnabledPrefix[] = "Enabled";
+constexpr char kSuggestionsProviderFieldTrialName[] =
+    "SuggestionsAppListProvider";
+constexpr char kSuggestionsProviderFieldTrialEnabledPrefix[] = "Enabled";
 
 // Returns whether the user is part of a group where the Suggestions provider is
 // enabled.
@@ -61,9 +62,10 @@
     Profile* profile,
     AppListModel* model,
     AppListControllerDelegate* list_controller) {
-  std::unique_ptr<SearchController> controller(
-      new SearchController(model->search_box(), model->results(),
-                           HistoryFactory::GetForBrowserContext(profile)));
+  std::unique_ptr<SearchController> controller =
+      base::MakeUnique<SearchController>(
+          model->search_box(), model->results(),
+          HistoryFactory::GetForBrowserContext(profile));
 
   // Add mixer groups. There are three main groups: apps, webstore and
   // omnibox. Each group has a "soft" maximum number of results. However, if
@@ -76,22 +78,21 @@
   // Add search providers.
   controller->AddProvider(
       apps_group_id,
-      std::unique_ptr<SearchProvider>(new AppSearchProvider(
+      base::MakeUnique<AppSearchProvider>(
           profile, list_controller, base::MakeUnique<base::DefaultClock>(),
-          model->top_level_item_list())));
-  controller->AddProvider(omnibox_group_id,
-                          std::unique_ptr<SearchProvider>(
-                              new OmniboxProvider(profile, list_controller)));
-  controller->AddProvider(webstore_group_id,
-                          std::unique_ptr<SearchProvider>(
-                              new WebstoreProvider(profile, list_controller)));
+          model->top_level_item_list()));
+  controller->AddProvider(
+      omnibox_group_id,
+      base::MakeUnique<OmniboxProvider>(profile, list_controller));
+  controller->AddProvider(
+      webstore_group_id,
+      base::MakeUnique<WebstoreProvider>(profile, list_controller));
   if (IsSuggestionsSearchProviderEnabled()) {
     size_t suggestions_group_id =
         controller->AddGroup(kMaxSuggestionsResults, 1.0);
     controller->AddProvider(
         suggestions_group_id,
-        std::unique_ptr<SearchProvider>(
-            new SuggestionsSearchProvider(profile, list_controller)));
+        base::MakeUnique<SuggestionsSearchProvider>(profile, list_controller));
   }
 
   // LauncherSearchProvider is added only when flag is enabled, not in guest
@@ -101,9 +102,8 @@
       !profile->IsGuestSession()) {
     size_t search_api_group_id =
         controller->AddGroup(kMaxLauncherSearchResults, 1.0);
-    controller->AddProvider(
-        search_api_group_id,
-        std::unique_ptr<SearchProvider>(new LauncherSearchProvider(profile)));
+    controller->AddProvider(search_api_group_id,
+                            base::MakeUnique<LauncherSearchProvider>(profile));
   }
 #endif
 
diff --git a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
index 1adf31c..bea13e27b 100644
--- a/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
+++ b/chrome/browser/ui/app_list/search/suggestions/suggestions_search_provider_unittest.cc
@@ -76,9 +76,10 @@
     suggestions_search_->Start(false, base::UTF8ToUTF16(query));
 
     // Sort results from most to least relevant.
-    std::vector<SearchResult*> sorted_results(
-        suggestions_search_->results().begin(),
-        suggestions_search_->results().end());
+    std::vector<SearchResult*> sorted_results;
+    sorted_results.reserve(suggestions_search_->results().size());
+    for (const auto& result : suggestions_search_->results())
+      sorted_results.emplace_back(result.get());
     std::sort(sorted_results.begin(), sorted_results.end(), &MostRelevant);
 
     std::string result_str;
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
index 044cfac..12b0c575 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider.cc
@@ -96,8 +96,7 @@
 
   // Add a placeholder result which when clicked will run the user's query in a
   // browser. This placeholder is removed when the search results arrive.
-  Add(std::unique_ptr<SearchResult>(
-      new SearchWebstoreResult(profile_, controller_, query_)));
+  Add(base::MakeUnique<SearchWebstoreResult>(profile_, controller_, query_));
 }
 
 void WebstoreProvider::Stop() {
@@ -192,8 +191,8 @@
   if (!match.Calculate(query, title))
     return std::unique_ptr<SearchResult>();
 
-  std::unique_ptr<SearchResult> result(new WebstoreResult(
-      profile_, app_id, icon_url, is_paid, item_type, controller_));
+  std::unique_ptr<SearchResult> result = base::MakeUnique<WebstoreResult>(
+      profile_, app_id, icon_url, is_paid, item_type, controller_);
   result->UpdateFromMatch(title, match);
   return result;
 }
diff --git a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
index 6e10205..b316a28 100644
--- a/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
+++ b/chrome/browser/ui/app_list/search/webstore/webstore_provider_browsertest.cc
@@ -219,7 +219,7 @@
                      size_t expected_result_size) {
     ASSERT_EQ(expected_result_size, webstore_provider_->results().size());
     for (size_t i = 0; i < expected_result_size; ++i) {
-      const SearchResult* result = webstore_provider_->results()[i];
+      const SearchResult* result = (webstore_provider_->results()[i]).get();
       // A search for an installed app will return a general webstore search
       // instead of an app in the webstore.
       if (!strcmp(expected_results[i].id, kWebstoreUrlPlaceholder)) {
diff --git a/chrome/browser/ui/ash/OWNERS b/chrome/browser/ui/ash/OWNERS
index 2e0c4bf..8437fb3 100644
--- a/chrome/browser/ui/ash/OWNERS
+++ b/chrome/browser/ui/ash/OWNERS
@@ -3,3 +3,5 @@
 oshima@chromium.org
 sky@chromium.org
 stevenjb@chromium.org
+
+# COMPONENT: UI>Shell
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index efd0662..62a45c9d 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -331,15 +331,7 @@
       ContentAutofillDriverFactory::FromWebContents(web_contents());
   DCHECK(factory);
 
-  for (content::RenderFrameHost* frame : web_contents()->GetAllFrames()) {
-    // No need to notify non-live frames.
-    // And actually they have no corresponding drivers in the factory's map.
-    if (!frame->IsRenderFrameLive())
-      continue;
-    ContentAutofillDriver* driver = factory->DriverForFrame(frame);
-    DCHECK(driver);
-    driver->NotifyFirstUserGestureObservedInTab();
-  }
+  factory->OnFirstUserGestureObserved();
 }
 
 bool ChromeAutofillClient::IsContextSecure() {
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
index 16e764eb..be069af5 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -494,7 +494,7 @@
 
   // Add "?" icon with tooltip.
   storageTooltip_.reset([[AutofillTooltipController alloc]
-      initWithArrowLocation:info_bubble::kTopRight]);
+      initWithArrowLocation:info_bubble::kTopTrailing]);
   [storageTooltip_ setImage:ui::ResourceBundle::GetSharedInstance()
                                 .GetNativeImageNamed(IDR_AUTOFILL_TOOLTIP_ICON)
                                 .ToNSImage()];
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller.mm b/chrome/browser/ui/cocoa/base_bubble_controller.mm
index ffaae11..2768e53 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller.mm
@@ -114,7 +114,7 @@
                                                                   self));
   }
 
-  [bubble_ setArrowLocation:info_bubble::kTopRight];
+  [bubble_ setArrowLocation:info_bubble::kTopTrailing];
 }
 
 - (void)dealloc {
@@ -411,11 +411,13 @@
                                   info_bubble::kBubbleArrowWidth / 2.0, 0);
       offsets = [[parentWindow_ contentView] convertSize:offsets toView:nil];
       switch ([bubble_ arrowLocation]) {
-        case info_bubble::kTopRight:
-          origin.x -= NSWidth([window frame]) - offsets.width;
+        case info_bubble::kTopTrailing:
+          origin.x -=
+              isRTL ? offsets.width : NSWidth([window frame]) - offsets.width;
           break;
-        case info_bubble::kTopLeft:
-          origin.x -= offsets.width;
+        case info_bubble::kTopLeading:
+          origin.x -=
+              isRTL ? NSWidth([window frame]) - offsets.width : offsets.width;
           break;
         case info_bubble::kNoArrow:
         // FALLTHROUGH.
@@ -431,7 +433,7 @@
       // edge aligns with the anchor. If the arrow is to the left then there's
       // nothing to do because the left edge is already aligned with the left
       // edge of the anchor.
-      if ([bubble_ arrowLocation] == info_bubble::kTopRight) {
+      if ([bubble_ arrowLocation] == info_bubble::kTopTrailing) {
         origin.x -= NSWidth([window frame]);
       }
       break;
diff --git a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
index 05466b1..c7cc3b1e 100644
--- a/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/base_bubble_controller_unittest.mm
@@ -165,7 +165,7 @@
 // Test that kAlignEdgeToAnchorEdge and a left bubble arrow correctly aligns the
 // left edge of the buble to the anchor point.
 TEST_F(BaseBubbleControllerTest, LeftAlign) {
-  [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft];
+  [[controller_ bubble] setArrowLocation:info_bubble::kTopLeading];
   [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge];
   [controller_ showWindow:nil];
 
@@ -181,7 +181,7 @@
 // Test that kAlignEdgeToAnchorEdge and a right bubble arrow correctly aligns
 // the right edge of the buble to the anchor point.
 TEST_F(BaseBubbleControllerTest, RightAlign) {
-  [[controller_ bubble] setArrowLocation:info_bubble::kTopRight];
+  [[controller_ bubble] setArrowLocation:info_bubble::kTopTrailing];
   [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge];
   [controller_ showWindow:nil];
 
@@ -197,7 +197,7 @@
 // Test that kAlignArrowToAnchor and a left bubble arrow correctly aligns
 // the bubble arrow to the anchor point.
 TEST_F(BaseBubbleControllerTest, AnchorAlignLeftArrow) {
-  [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft];
+  [[controller_ bubble] setArrowLocation:info_bubble::kTopLeading];
   [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
   [controller_ showWindow:nil];
 
@@ -214,7 +214,7 @@
 // Test that kAlignArrowToAnchor and a right bubble arrow correctly aligns
 // the bubble arrow to the anchor point.
 TEST_F(BaseBubbleControllerTest, AnchorAlignRightArrow) {
-  [[controller_ bubble] setArrowLocation:info_bubble::kTopRight];
+  [[controller_ bubble] setArrowLocation:info_bubble::kTopTrailing];
   [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
   [controller_ showWindow:nil];
 
@@ -248,7 +248,7 @@
 // ensures offscreen initialization is done using correct screen metrics.
 TEST_F(BaseBubbleControllerTest, PositionedBeforeShow) {
   // Verify default alignment settings, used when initialized in SetUp().
-  EXPECT_EQ(info_bubble::kTopRight, [[controller_ bubble] arrowLocation]);
+  EXPECT_EQ(info_bubble::kTopTrailing, [[controller_ bubble] arrowLocation]);
   EXPECT_EQ(info_bubble::kAlignArrowToAnchor, [[controller_ bubble] alignment]);
 
   // Verify the default frame (positioned relative to the test_window() origin).
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
index 2d80a49d..2cd7a5d 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bubble_controller.mm
@@ -144,7 +144,7 @@
       [BrowserWindowController browserWindowControllerForWindow:parentWindow];
 
   InfoBubbleView* bubble = self.bubble;
-  [bubble setArrowLocation:info_bubble::kTopRight];
+  [bubble setArrowLocation:info_bubble::kTopTrailing];
 
   // Insure decent positioning even in the absence of a browser controller,
   // which will occur for some unit tests.
diff --git a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
index 47166727..e8d55a7 100644
--- a/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/content_settings/content_setting_bubble_cocoa.mm
@@ -791,7 +791,7 @@
   ContentSettingSimpleBubbleModel* simple_bubble =
       contentSettingBubbleModel_->AsSimpleBubbleModel();
 
-  [[self bubble] setArrowLocation:info_bubble::kTopRight];
+  [[self bubble] setArrowLocation:info_bubble::kTopTrailing];
 
   // Adapt window size to bottom buttons. Do this before all other layouting.
   if (simple_bubble && !simple_bubble->bubble_content().manage_text.empty())
diff --git a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
index 9050f5d..e3abc4c 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_action_platform_delegate_cocoa.mm
@@ -77,7 +77,7 @@
   [ExtensionPopupController host:std::move(host)
                        inBrowser:controller_->browser()
                       anchoredAt:GetPopupPoint()
-                   arrowLocation:info_bubble::kTopRight
+                   arrowLocation:info_bubble::kTopTrailing
                          devMode:devMode];
 }
 
diff --git a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
index deed5a8c..a4d65986 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_installed_bubble_controller.mm
@@ -285,9 +285,9 @@
   if (installedBubble_ &&
       installedBubble_->anchor_position() ==
           ExtensionInstalledBubble::ANCHOR_OMNIBOX) {
-    [self.bubble setArrowLocation:info_bubble::kTopLeft];
+    [self.bubble setArrowLocation:info_bubble::kTopLeading];
   } else {
-    [self.bubble setArrowLocation:info_bubble::kTopRight];
+    [self.bubble setArrowLocation:info_bubble::kTopTrailing];
   }
 
   // Set appropriate icon, resizing if necessary.
diff --git a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
index 4099c11..75177f2f 100644
--- a/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/extensions/toolbar_actions_bar_bubble_mac.mm
@@ -87,7 +87,7 @@
 
     ui::NativeTheme* nativeTheme = ui::NativeTheme::GetInstanceForNativeUi();
     [[self bubble] setAlignment:info_bubble::kAlignArrowToAnchor];
-    [[self bubble] setArrowLocation:info_bubble::kTopRight];
+    [[self bubble] setArrowLocation:info_bubble::kTopTrailing];
     [[self bubble] setBackgroundColor:
         skia::SkColorToCalibratedNSColor(nativeTheme->GetSystemColor(
             ui::NativeTheme::kColorId_DialogBackground))];
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.h b/chrome/browser/ui/cocoa/info_bubble_view.h
index 09fa4745..3787f29 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view.h
+++ b/chrome/browser/ui/cocoa/info_bubble_view.h
@@ -25,9 +25,9 @@
 };
 
 enum BubbleArrowLocation {
-  kTopLeft,
+  kTopLeading,
   kTopCenter,
-  kTopRight,
+  kTopTrailing,
   kNoArrow,
 };
 
diff --git a/chrome/browser/ui/cocoa/info_bubble_view.mm b/chrome/browser/ui/cocoa/info_bubble_view.mm
index 103db6b5..0d3f23d2 100644
--- a/chrome/browser/ui/cocoa/info_bubble_view.mm
+++ b/chrome/browser/ui/cocoa/info_bubble_view.mm
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #import "chrome/browser/ui/cocoa/info_bubble_window.h"
+#import "chrome/browser/ui/cocoa/l10n_util.h"
 #import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h"
 
 @implementation InfoBubbleView
@@ -17,7 +18,7 @@
 
 - (id)initWithFrame:(NSRect)frameRect {
   if ((self = [super initWithFrame:frameRect])) {
-    arrowLocation_ = info_bubble::kTopLeft;
+    arrowLocation_ = info_bubble::kTopLeading;
     alignment_ = info_bubble::kAlignArrowToAnchor;
     cornerFlags_ = info_bubble::kRoundedAllCorners;
     backgroundColor_.reset([[NSColor whiteColor] retain]);
@@ -64,14 +65,17 @@
                         bottomRightCornerRadius:bottomRadius];
 
   // Add the bubble arrow.
+  BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
   CGFloat dX = 0;
+  CGFloat leftOffset = info_bubble::kBubbleArrowXOffset;
+  CGFloat rightOffset = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset -
+                        info_bubble::kBubbleArrowWidth;
   switch (arrowLocation_) {
-    case info_bubble::kTopLeft:
-      dX = info_bubble::kBubbleArrowXOffset;
+    case info_bubble::kTopLeading:
+      dX = isRTL ? rightOffset : leftOffset;
       break;
-    case info_bubble::kTopRight:
-      dX = NSWidth(bounds) - info_bubble::kBubbleArrowXOffset -
-          info_bubble::kBubbleArrowWidth;
+    case info_bubble::kTopTrailing:
+      dX = isRTL ? leftOffset : rightOffset;
       break;
     case info_bubble::kTopCenter:
       dX = NSMidX(bounds) - info_bubble::kBubbleArrowWidth / 2.0;
@@ -103,12 +107,15 @@
   CGFloat tipXOffset =
       info_bubble::kBubbleArrowXOffset + info_bubble::kBubbleArrowWidth / 2.0;
   CGFloat xOffset = 0.0;
+  BOOL isRTL = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
+  CGFloat leftOffset = NSMaxX(bounds) - tipXOffset;
+  CGFloat rightOffset = NSMinX(bounds) + tipXOffset;
   switch(arrowLocation_) {
-    case info_bubble::kTopRight:
-      xOffset = NSMaxX(bounds) - tipXOffset;
+    case info_bubble::kTopTrailing:
+      xOffset = isRTL ? rightOffset : leftOffset;
       break;
-    case info_bubble::kTopLeft:
-      xOffset = NSMinX(bounds) + tipXOffset;
+    case info_bubble::kTopLeading:
+      xOffset = isRTL ? leftOffset : rightOffset;
       break;
     case info_bubble::kTopCenter:
       xOffset = NSMidX(bounds);
diff --git a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
index 54fa903..68c237a 100644
--- a/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/passwords/passwords_bubble_controller.mm
@@ -118,7 +118,7 @@
         browserWindowControllerForWindow:[self parentWindow]];
     anchorPoint = [controller locationBarBridge]->GetBubblePointForDecoration(
         [self decorationForBubble]);
-    arrow = info_bubble::kTopRight;
+    arrow = info_bubble::kTopTrailing;
   } else {
     // Center the bubble if there's no location bar.
     NSRect contentFrame = [[[self parentWindow] contentView] frame];
diff --git a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
index 63e41ba..2fc70ee 100644
--- a/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
+++ b/chrome/browser/ui/cocoa/validation_message_bubble_cocoa.mm
@@ -47,7 +47,7 @@
   if ((self = [super initWithWindow:window.get()
                        parentWindow:parentWindow
                          anchoredAt:anchorPoint])) {
-    [[self bubble] setArrowLocation:info_bubble::kTopLeft];
+    [[self bubble] setArrowLocation:info_bubble::kTopLeading];
     self.shouldOpenAsKeyWindow = NO;
 
     NSView* contentView = [ValidationMessageBubbleController
diff --git a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
index f8baba4..f7e8f1ee5 100644
--- a/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
+++ b/chrome/browser/ui/cocoa/website_settings/chooser_bubble_ui_cocoa.mm
@@ -246,7 +246,8 @@
 }
 
 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation {
-  return [self hasLocationBar] ? info_bubble::kTopLeft : info_bubble::kNoArrow;
+  return [self hasLocationBar] ? info_bubble::kTopLeading
+                               : info_bubble::kNoArrow;
 }
 
 - (NSWindow*)getExpectedParentWindow {
diff --git a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm
index 3d0dc43..f100a71 100644
--- a/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/website_settings/permission_bubble_controller.mm
@@ -479,7 +479,7 @@
 }
 
 - (info_bubble::BubbleArrowLocation)getExpectedArrowLocation {
-  return info_bubble::kTopLeft;
+  return info_bubble::kTopLeading;
 }
 
 - (NSWindow*)getExpectedParentWindow {
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
index 31b9d3c..dbbb273 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -213,7 +213,7 @@
   if ((self = [super initWithWindow:window.get()
                        parentWindow:parentWindow
                          anchoredAt:NSZeroPoint])) {
-    [[self bubble] setArrowLocation:info_bubble::kTopLeft];
+    [[self bubble] setArrowLocation:info_bubble::kTopLeading];
 
     // Create the container view that uses flipped coordinates.
     NSRect contentFrame = NSMakeRect(0, 0, [self defaultWindowWidth], 300);
diff --git a/chrome/browser/ui/views/ash/OWNERS b/chrome/browser/ui/views/ash/OWNERS
index 6c1a33b..28ae752 100644
--- a/chrome/browser/ui/views/ash/OWNERS
+++ b/chrome/browser/ui/views/ash/OWNERS
@@ -2,3 +2,5 @@
 sky@chromium.org
 jamescook@chromium.org
 erg@chromium.org
+
+# COMPONENT: UI>Shell
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 1983e899..88bb7db 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -44,8 +44,14 @@
                               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) {}
+  // outlive this object. |list| is the PaymentRequestItemList object that will
+  // own this.
+  PaymentMethodListItem(autofill::CreditCard* card,
+                        PaymentRequest* request,
+                        PaymentRequestItemList* list,
+                        bool selected)
+      : payments::PaymentRequestItemList::Item(request, list, selected),
+        card_(card) {}
   ~PaymentMethodListItem() override {}
 
  private:
@@ -72,6 +78,8 @@
     columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                        0, views::GridLayout::USE_PREF, 0, 0);
 
+    columns->AddPaddingColumn(0, kPaymentRequestButtonSpacing);
+
     // A column for the card icon
     columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::CENTER,
                        0, views::GridLayout::USE_PREF, 0, 0);
@@ -97,14 +105,20 @@
     card_info_container->AddChildView(new views::Label(
         card_->GetInfo(autofill::AutofillType(autofill::CREDIT_CARD_NAME_FULL),
                        g_browser_process->GetApplicationLocale())));
+    // TODO(anthonyvd): Add the "card is incomplete" label once the
+    // completedness logic is implemented.
     layout->AddView(card_info_container.release());
 
-    std::unique_ptr<views::ImageView> checkmark =
-        base::MakeUnique<views::ImageView>();
-    checkmark->set_can_process_events_within_subtree(false);
-    checkmark->SetImage(
+    checkmark_ = base::MakeUnique<views::ImageView>();
+    checkmark_->set_id(
+        static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW));
+    checkmark_->set_owned_by_client();
+    checkmark_->set_can_process_events_within_subtree(false);
+    checkmark_->SetImage(
         gfx::CreateVectorIcon(views::kMenuCheckIcon, 0xFF609265));
-    layout->AddView(checkmark.release());
+    layout->AddView(checkmark_.get());
+    if (!selected())
+      checkmark_->SetVisible(false);
 
     std::unique_ptr<views::ImageView> card_icon_view =
         CreateCardIconView(card_->type());
@@ -114,10 +128,33 @@
     return std::move(row);
   }
 
+  void SelectedStateChanged() override {
+    // This could be called before CreateItemView, so before |checkmark_| is
+    // instantiated.
+    if (checkmark_)
+      checkmark_->SetVisible(selected());
+
+    request()->set_selected_credit_card(card_);
+  }
+
   // views::ButtonListener:
-  void ButtonPressed(views::Button* sender, const ui::Event& event) override {}
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override {
+    if (IsComplete()) {
+      list()->SelectItem(this);
+    } else {
+      // TODO(anthonyvd): Display the editor, pre-populated with the data that
+      // already exists in |card|.
+    }
+  }
+
+  bool IsComplete() const {
+    // TODO(anthonyvd): Hook this up to the card completedness logic when it's
+    // implemented in PaymentRequest.
+    return true;
+  }
 
   autofill::CreditCard* card_;
+  std::unique_ptr<views::ImageView> checkmark_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentMethodListItem);
 };
@@ -132,19 +169,28 @@
       request->credit_cards();
 
   for (autofill::CreditCard* card : available_cards) {
-    payment_method_list_.AddItem(base::MakeUnique<PaymentMethodListItem>(card));
+    std::unique_ptr<PaymentMethodListItem> item =
+        base::MakeUnique<PaymentMethodListItem>(
+            card, request, &payment_method_list_,
+            card == request->selected_credit_card());
+    payment_method_list_.AddItem(std::move(item));
   }
 }
 
 PaymentMethodViewController::~PaymentMethodViewController() {}
 
 std::unique_ptr<views::View> PaymentMethodViewController::CreateView() {
+  std::unique_ptr<views::View> list_view =
+      payment_method_list_.CreateListView();
+  list_view->set_id(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
   return CreatePaymentView(
       CreateSheetHeaderView(
-          true, l10n_util::GetStringUTF16(
-                    IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME),
+          true,
+          l10n_util::GetStringUTF16(
+              IDS_PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_NAME),
           this),
-      payment_method_list_.CreateListView());
+      std::move(list_view));
 }
 
 std::unique_ptr<views::View>
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc b/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc
new file mode 100644
index 0000000..b8d3dea
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc
@@ -0,0 +1,129 @@
+// 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_dialog_view_ids.h"
+#include "chrome/browser/ui/views/payments/payment_request_interactive_uitest_base.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/payments/payment_request.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace payments {
+
+class PaymentMethodViewControllerTest
+    : public PaymentRequestInteractiveTestBase {
+ protected:
+  PaymentMethodViewControllerTest()
+      : PaymentRequestInteractiveTestBase(
+            "/payment_request_no_shipping_test.html") {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PaymentMethodViewControllerTest);
+};
+
+IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, EmptyList) {
+  InvokePaymentRequestUI();
+  OpenPaymentMethodScreen();
+
+  views::View* list_view = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
+  EXPECT_TRUE(list_view);
+  EXPECT_FALSE(list_view->has_children());
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest, OneCardSelected) {
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
+
+  PersonalDataLoadedObserverMock personal_data_observer;
+  personal_data_manager->AddObserver(&personal_data_observer);
+  base::RunLoop data_loop;
+  EXPECT_CALL(personal_data_observer, OnPersonalDataChanged())
+      .WillOnce(QuitMessageLoop(&data_loop));
+  autofill::CreditCard card = autofill::test::GetCreditCard();
+  personal_data_manager->AddCreditCard(card);
+  data_loop.Run();
+
+  InvokePaymentRequestUI();
+  OpenPaymentMethodScreen();
+
+  PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0];
+  EXPECT_EQ(1U, request->credit_cards().size());
+
+  views::View* list_view = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
+  EXPECT_TRUE(list_view);
+  EXPECT_EQ(1, list_view->child_count());
+
+  EXPECT_EQ(card, *request->selected_credit_card());
+  views::View* checkmark_view = list_view->child_at(0)->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW));
+  EXPECT_TRUE(checkmark_view->visible());
+}
+
+IN_PROC_BROWSER_TEST_F(PaymentMethodViewControllerTest,
+                       OneCardSelectedOutOfMany) {
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
+
+  PersonalDataLoadedObserverMock personal_data_observer1;
+  personal_data_manager->AddObserver(&personal_data_observer1);
+  base::RunLoop card1_loop;
+  EXPECT_CALL(personal_data_observer1, OnPersonalDataChanged())
+      .WillOnce(QuitMessageLoop(&card1_loop));
+  autofill::CreditCard card1 = autofill::test::GetCreditCard();
+  // Ensure that this card is the first suggestion.
+  card1.set_use_count(5U);
+  personal_data_manager->AddCreditCard(card1);
+  card1_loop.Run();
+  personal_data_manager->RemoveObserver(&personal_data_observer1);
+
+  EXPECT_EQ(1U, personal_data_manager->GetCreditCardsToSuggest().size());
+
+  PersonalDataLoadedObserverMock personal_data_observer2;
+  personal_data_manager->AddObserver(&personal_data_observer2);
+  base::RunLoop card2_loop;
+  EXPECT_CALL(personal_data_observer2, OnPersonalDataChanged())
+      .WillOnce(QuitMessageLoop(&card2_loop));
+  autofill::CreditCard card2 = autofill::test::GetCreditCard2();
+  card2.set_use_count(1U);
+  personal_data_manager->AddCreditCard(card2);
+  card2_loop.Run();
+  personal_data_manager->RemoveObserver(&personal_data_observer2);
+
+  InvokePaymentRequestUI();
+  OpenPaymentMethodScreen();
+
+  PaymentRequest* request = GetPaymentRequests(GetActiveWebContents())[0];
+  EXPECT_EQ(2U, request->credit_cards().size());
+  EXPECT_EQ(card1, *request->selected_credit_card());
+
+  views::View* list_view = dialog_view()->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_SHEET_LIST_VIEW));
+  EXPECT_TRUE(list_view);
+  EXPECT_EQ(2, list_view->child_count());
+
+  EXPECT_EQ(card1, *request->selected_credit_card());
+  views::View* checkmark_view = list_view->child_at(0)->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW));
+  EXPECT_TRUE(checkmark_view->visible());
+
+  views::View* checkmark_view2 = list_view->child_at(1)->GetViewByID(
+      static_cast<int>(DialogViewID::PAYMENT_METHOD_ITEM_CHECKMARK_VIEW));
+  EXPECT_FALSE(checkmark_view2->visible());
+
+  // Simulate selecting the second card.
+  ClickOnDialogViewAndWait(list_view->child_at(1));
+
+  EXPECT_EQ(card2, *request->selected_credit_card());
+  EXPECT_FALSE(checkmark_view->visible());
+  EXPECT_TRUE(checkmark_view2->visible());
+
+  // Clicking on the second card again should not modify any state.
+  ClickOnDialogViewAndWait(list_view->child_at(1));
+
+  EXPECT_EQ(card2, *request->selected_credit_card());
+  EXPECT_FALSE(checkmark_view->visible());
+  EXPECT_TRUE(checkmark_view2->visible());
+}
+
+}  // namespace payments
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 e408da8..3b49bd6 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
@@ -12,12 +12,10 @@
 #include "chrome/browser/ui/views/payments/validating_textfield.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
-#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"
 
@@ -27,19 +25,6 @@
 
 const base::Time kJune2017 = base::Time::FromDoubleT(1497552271);
 
-ACTION_P(QuitMessageLoop, loop) {
-  loop->Quit();
-}
-
-class PersonalDataLoadedObserverMock
-    : public autofill::PersonalDataManagerObserver {
- public:
-  PersonalDataLoadedObserverMock() {}
-  virtual ~PersonalDataLoadedObserverMock() {}
-
-  MOCK_METHOD0(OnPersonalDataChanged, void());
-};
-
 }  // namespace
 
 class PaymentRequestCreditCardEditorTest
@@ -74,8 +59,7 @@
                    autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR);
 
   // Verifying the data is in the DB.
-  autofill::PersonalDataManager* personal_data_manager =
-      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   personal_data_manager->AddObserver(&personal_data_observer_);
 
   ResetEventObserver(DialogEvent::BACK_NAVIGATION);
@@ -126,8 +110,7 @@
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH));
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
 
-  autofill::PersonalDataManager* personal_data_manager =
-      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size());
 }
 
@@ -196,8 +179,7 @@
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH));
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
 
-  autofill::PersonalDataManager* personal_data_manager =
-      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size());
 }
 
@@ -232,8 +214,7 @@
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_MONTH));
   EXPECT_FALSE(IsEditorComboboxInvalid(autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR));
 
-  autofill::PersonalDataManager* personal_data_manager =
-      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   EXPECT_EQ(0u, personal_data_manager->GetCreditCards().size());
 }
 
@@ -274,8 +255,7 @@
             GetErrorLabelForType(autofill::CREDIT_CARD_NUMBER));
 
   // Verifying the data is in the DB.
-  autofill::PersonalDataManager* personal_data_manager =
-      GetPaymentRequests(GetActiveWebContents())[0]->personal_data_manager();
+  autofill::PersonalDataManager* personal_data_manager = GetDataManager();
   personal_data_manager->AddObserver(&personal_data_observer_);
 
   ResetEventObserver(DialogEvent::BACK_NAVIGATION);
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 e3de7b51..df302b0f 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
@@ -29,6 +29,10 @@
   ORDER_SUMMARY_LINE_ITEM_2,
   ORDER_SUMMARY_LINE_ITEM_3,
 
+  // The following are views contained within the Payment Method Sheet.
+  PAYMENT_METHOD_SHEET_LIST_VIEW,
+  PAYMENT_METHOD_ITEM_CHECKMARK_VIEW,
+
   // Used to label the error labels with an offset, which gets added to
   // the Autofill type value they represent (for tests).
   ERROR_LABEL_OFFSET,
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 991adf4..6e14875 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
@@ -11,6 +11,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/autofill/personal_data_manager_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/payments/payment_request_dialog_view_ids.h"
@@ -35,6 +37,9 @@
 
 namespace payments {
 
+PersonalDataLoadedObserverMock::PersonalDataLoadedObserverMock() {}
+PersonalDataLoadedObserverMock::~PersonalDataLoadedObserverMock() {}
+
 PaymentRequestInteractiveTestBase::PaymentRequestInteractiveTestBase(
     const std::string& test_file_path)
     : test_file_path_(test_file_path),
@@ -153,6 +158,12 @@
   return payment_requests_ptrs;
 }
 
+autofill::PersonalDataManager*
+PaymentRequestInteractiveTestBase::GetDataManager() {
+  return autofill::PersonalDataManagerFactory::GetForProfile(
+      Profile::FromBrowserContext(GetActiveWebContents()->GetBrowserContext()));
+}
+
 void PaymentRequestInteractiveTestBase::CreatePaymentRequestForTest(
     content::WebContents* web_contents,
     mojo::InterfaceRequest<payments::mojom::PaymentRequest> request) {
@@ -171,6 +182,12 @@
   views::View* view =
       delegate_->dialog_view()->GetViewByID(static_cast<int>(view_id));
   DCHECK(view);
+  ClickOnDialogViewAndWait(view);
+}
+
+void PaymentRequestInteractiveTestBase::ClickOnDialogViewAndWait(
+    views::View* view) {
+  DCHECK(view);
   base::RunLoop run_loop;
   ui_test_utils::MoveMouseToCenterAndPress(
       view, ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP,
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 3b718a8..663dd91 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
@@ -15,8 +15,10 @@
 #include "chrome/browser/ui/views/payments/test_chrome_payment_request_delegate.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/autofill/core/browser/field_types.h"
+#include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "components/payments/payment_request.mojom.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "ui/views/widget/widget_observer.h"
 
 namespace content {
@@ -32,6 +34,23 @@
 enum class DialogViewID;
 class PaymentRequest;
 
+namespace {
+
+ACTION_P(QuitMessageLoop, loop) {
+  loop->Quit();
+}
+
+}  // namespace
+
+class PersonalDataLoadedObserverMock
+    : public autofill::PersonalDataManagerObserver {
+ public:
+  PersonalDataLoadedObserverMock();
+  ~PersonalDataLoadedObserverMock() override;
+
+  MOCK_METHOD0(OnPersonalDataChanged, void());
+};
+
 // Base class for any interactive PaymentRequest test that will need to open
 // the UI and interact with it.
 class PaymentRequestInteractiveTestBase
@@ -68,12 +87,14 @@
   void OpenPaymentMethodScreen();
   void OpenCreditCardEditorScreen();
 
+  content::WebContents* GetActiveWebContents();
+
   // Convenience method to get a list of PaymentRequest associated with
   // |web_contents|.
   const std::vector<PaymentRequest*> GetPaymentRequests(
       content::WebContents* web_contents);
 
-  content::WebContents* GetActiveWebContents();
+  autofill::PersonalDataManager* GetDataManager();
 
   void CreatePaymentRequestForTest(
       content::WebContents* web_contents,
@@ -82,6 +103,7 @@
   // Click on a view from within the dialog and waits for an observed event
   // to be observed.
   void ClickOnDialogViewAndWait(DialogViewID view_id);
+  void ClickOnDialogViewAndWait(views::View* view);
 
   // Setting the |value| in the textfield of a given |type|.
   void SetEditorTextfieldValue(const base::string16& value,
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list.cc b/chrome/browser/ui/views/payments/payment_request_item_list.cc
index 0cb3ce87..dde7ff9 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.cc
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.cc
@@ -10,7 +10,10 @@
 
 namespace payments {
 
-PaymentRequestItemList::Item::Item() {}
+PaymentRequestItemList::Item::Item(PaymentRequest* request,
+                                   PaymentRequestItemList* list,
+                                   bool selected)
+    : request_(request), list_(list), selected_(selected) {}
 
 PaymentRequestItemList::Item::~Item() {}
 
@@ -23,13 +26,21 @@
   return item_view_.get();
 }
 
-PaymentRequestItemList::PaymentRequestItemList() {}
+void PaymentRequestItemList::Item::SetSelected(bool selected) {
+  selected_ = selected;
+  SelectedStateChanged();
+}
+
+PaymentRequestItemList::PaymentRequestItemList() : selected_item_(nullptr) {}
 
 PaymentRequestItemList::~PaymentRequestItemList() {}
 
 void PaymentRequestItemList::AddItem(
     std::unique_ptr<PaymentRequestItemList::Item> item) {
+  DCHECK_EQ(this, item->list());
   items_.push_back(std::move(item));
+  if (items_.back()->selected())
+    SelectItem(items_.back().get());
 }
 
 std::unique_ptr<views::View> PaymentRequestItemList::CreateListView() {
@@ -46,4 +57,25 @@
   return content_view;
 }
 
+void PaymentRequestItemList::SelectItem(PaymentRequestItemList::Item* item) {
+  DCHECK_EQ(this, item->list());
+  if (selected_item_ == item)
+    return;
+
+  UnselectSelectedItem();
+
+  selected_item_ = item;
+  item->SetSelected(true);
+}
+
+void PaymentRequestItemList::UnselectSelectedItem() {
+  // It's possible that no item is currently selected, either during list
+  // creation or in the middle of the selection operation when the previously
+  // selected item has been deselected but the new one isn't selected yet.
+  if (selected_item_)
+    selected_item_->SetSelected(false);
+
+  selected_item_ = nullptr;
+}
+
 }  // 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
index 71f4c04..09aafea0 100644
--- a/chrome/browser/ui/views/payments/payment_request_item_list.h
+++ b/chrome/browser/ui/views/payments/payment_request_item_list.h
@@ -16,17 +16,21 @@
 
 namespace payments {
 
+class PaymentRequest;
+
 // 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
+// expiration 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();
+    // Creates an item that will be owned by |list| with the initial state set
+    // to |selected|.
+    Item(PaymentRequest* request, PaymentRequestItemList* list, bool selected);
     virtual ~Item();
 
     // Gets the view associated with this item. It's owned by this object so
@@ -34,12 +38,33 @@
     // view.
     views::View* GetItemView();
 
+    bool selected() const { return selected_; }
+    // Changes the selected state of this item to |selected| and calls
+    // SelectedStateChanged.
+    void SetSelected(bool selected);
+
+    // Returns a pointer to the PaymentRequestItemList that owns this object.
+    PaymentRequestItemList* list() { return list_; }
+
+    // Returns a pointer to the PaymentRequest object associated with this
+    // instance of the UI.
+    PaymentRequest* request() { return request_; }
+
    protected:
     // Creates and returns the view associated with this list item.
     virtual std::unique_ptr<views::View> CreateItemView() = 0;
 
+    // Called when the selected state of this item changes. Subclasses may
+    // assume that they are the only selected item in |list| when this is
+    // called. This could be called before CreateItemView so subclasses should
+    // be aware that their views might not exist yet.
+    virtual void SelectedStateChanged() = 0;
+
    private:
     std::unique_ptr<views::View> item_view_;
+    PaymentRequest* request_;
+    PaymentRequestItemList* list_;
+    bool selected_;
 
     DISALLOW_COPY_AND_ASSIGN(Item);
   };
@@ -47,7 +72,7 @@
   PaymentRequestItemList();
   ~PaymentRequestItemList();
 
-  // Adds an item to this list.
+  // Adds an item to this list. |item->list()| should return this object.
   void AddItem(std::unique_ptr<Item> item);
 
   // Creates and returns the UI representation of this list. It iterates over
@@ -55,8 +80,17 @@
   // hierarchy.
   std::unique_ptr<views::View> CreateListView();
 
+  // Deselects the currently selected item and selects |item| instead.
+  void SelectItem(Item* item);
+
  private:
+  // Unselects the currently selected item. This is private so that the list can
+  // use it when selecting a new item while avoiding consumers of this class
+  // putting the list in a state where no item is selected.
+  void UnselectSelectedItem();
+
   std::vector<std::unique_ptr<Item>> items_;
+  Item* selected_item_;
 
   DISALLOW_COPY_AND_ASSIGN(PaymentRequestItemList);
 };
diff --git a/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
new file mode 100644
index 0000000..8f1f86d
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_request_item_list_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/payments/payment_request_item_list.h"
+
+#include <algorithm>
+
+#include "base/memory/ptr_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/views/view.h"
+
+namespace payments {
+
+namespace {
+
+class TestListItem : public PaymentRequestItemList::Item {
+ public:
+  TestListItem(PaymentRequestItemList* list, bool selected)
+      : PaymentRequestItemList::Item(nullptr, list, selected),
+        selected_state_changed_calls_count_(0) {}
+
+  int selected_state_changed_calls_count() {
+    return selected_state_changed_calls_count_;
+  }
+
+ private:
+  std::unique_ptr<views::View> CreateItemView() override {
+    return base::MakeUnique<views::View>();
+  }
+
+  void SelectedStateChanged() override {
+    ++selected_state_changed_calls_count_;
+  }
+
+  int selected_state_changed_calls_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestListItem);
+};
+
+}  // namespace
+
+TEST(PaymentRequestItemListTest, TestAddItem) {
+  PaymentRequestItemList list;
+
+  std::unique_ptr<views::View> list_view = list.CreateListView();
+  EXPECT_FALSE(list_view->has_children());
+
+  std::vector<std::unique_ptr<TestListItem>> items;
+  items.push_back(base::MakeUnique<TestListItem>(&list, false));
+  items.push_back(base::MakeUnique<TestListItem>(&list, true));
+  items.push_back(base::MakeUnique<TestListItem>(&list, false));
+  items.push_back(base::MakeUnique<TestListItem>(&list, true));
+
+  // The unique_ptr objects will become owned by |list|, but the underlying
+  // pointers will be needed for assertions after the unique_ptr is moved.
+  std::vector<TestListItem*> item_pointers;
+  for (auto& item : items) {
+    item_pointers.push_back(item.get());
+    list.AddItem(std::move(item));
+  }
+
+  EXPECT_FALSE(item_pointers[0]->selected());
+  // Only one item should be selected at a time, so adding item at index 3 with
+  // |selected| set to true should have deselected item at index 1.
+  EXPECT_FALSE(item_pointers[1]->selected());
+  EXPECT_FALSE(item_pointers[2]->selected());
+  EXPECT_TRUE(item_pointers[3]->selected());
+
+  list_view = list.CreateListView();
+  EXPECT_EQ(4, list_view->child_count());
+}
+
+TEST(PaymentRequestItemListTest, TestSelectItemResultsInSingleItemSelected) {
+  PaymentRequestItemList list;
+
+  std::vector<std::unique_ptr<TestListItem>> items;
+  items.push_back(base::MakeUnique<TestListItem>(&list, false));
+  items.push_back(base::MakeUnique<TestListItem>(&list, false));
+  items.push_back(base::MakeUnique<TestListItem>(&list, false));
+
+  // The unique_ptr objects will become owned by |list|, but the underlying
+  // pointers will be needed for assertions after the unique_ptr is moved.
+  std::vector<TestListItem*> item_pointers;
+  for (auto& item : items) {
+    item_pointers.push_back(item.get());
+    list.AddItem(std::move(item));
+  }
+
+  // Only one item should be selected at once and items should have their
+  // SelectedStateChanged() function called when they are selected and when
+  // they are unselected.
+  list.SelectItem(item_pointers[0]);
+  EXPECT_TRUE(item_pointers[0]->selected());
+  EXPECT_EQ(1, item_pointers[0]->selected_state_changed_calls_count());
+
+  EXPECT_FALSE(item_pointers[1]->selected());
+  EXPECT_EQ(0, item_pointers[1]->selected_state_changed_calls_count());
+
+  EXPECT_FALSE(item_pointers[2]->selected());
+  EXPECT_EQ(0, item_pointers[2]->selected_state_changed_calls_count());
+
+  list.SelectItem(item_pointers[2]);
+  EXPECT_FALSE(item_pointers[0]->selected());
+  EXPECT_EQ(2, item_pointers[0]->selected_state_changed_calls_count());
+
+  EXPECT_FALSE(item_pointers[1]->selected());
+  EXPECT_EQ(0, item_pointers[1]->selected_state_changed_calls_count());
+
+  EXPECT_TRUE(item_pointers[2]->selected());
+  EXPECT_EQ(1, item_pointers[2]->selected_state_changed_calls_count());
+
+  list.SelectItem(item_pointers[1]);
+  EXPECT_FALSE(item_pointers[0]->selected());
+  EXPECT_EQ(2, item_pointers[0]->selected_state_changed_calls_count());
+
+  EXPECT_TRUE(item_pointers[1]->selected());
+  EXPECT_EQ(1, item_pointers[1]->selected_state_changed_calls_count());
+
+  EXPECT_FALSE(item_pointers[2]->selected());
+  EXPECT_EQ(2, item_pointers[2]->selected_state_changed_calls_count());
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 88caad3..886fab62 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -82,6 +82,7 @@
       {"edit", IDS_SETTINGS_EDIT},
       {"learnMore", IDS_LEARN_MORE},
       {"menuButtonLabel", IDS_SETTINGS_MENU_BUTTON_LABEL},
+      {"moreActions", IDS_SETTINGS_MORE_ACTIONS},
       {"ok", IDS_OK},
       {"restart", IDS_SETTINGS_RESTART},
       {"save", IDS_SAVE},
@@ -1042,7 +1043,6 @@
 
 void AddPasswordsAndFormsStrings(content::WebUIDataSource* html_source) {
   LocalizedString localized_strings[] = {
-      {"overflowMenu", IDS_SETTINGS_OVERFLOW_MENU},
       {"passwordsAndAutofillPageTitle",
        IDS_SETTINGS_PASSWORDS_AND_AUTOFILL_PAGE_TITLE},
       {"autofill", IDS_SETTINGS_AUTOFILL},
diff --git a/chrome/renderer/app_categorizer.cc b/chrome/renderer/app_categorizer.cc
index 4251977..3d7a180 100644
--- a/chrome/renderer/app_categorizer.cc
+++ b/chrome/renderer/app_categorizer.cc
@@ -20,11 +20,6 @@
   "plus.sandbox.google.com"
 };
 
-const char* const kPredefinedPlusDomains[] = {
-  "plus.google.com",
-  "plus.sandbox.google.com"
-};
-
 bool IsInWhitelistedDomain(
     const GURL& url, const char* const domains[], size_t number_of_domains) {
   for (size_t i = 0; i < number_of_domains; ++i) {
@@ -55,19 +50,6 @@
   if (!app_url.SchemeIsCryptographic())
     return false;
 
-  std::string manifest_url_path = manifest_url.path();
-  bool is_photo_app =
-      manifest_url.SchemeIsCryptographic() &&
-      manifest_url.DomainIs("ssl.gstatic.com") &&
-      (base::StartsWith(manifest_url_path, "/s2/oz/nacl/",
-                        base::CompareCase::SENSITIVE) ||
-       base::StartsWith(manifest_url_path, "/photos/nacl/",
-                        base::CompareCase::SENSITIVE)) &&
-      IsInWhitelistedDomain(
-          app_url,
-          kPredefinedPlusDomains,
-          arraysize(kPredefinedPlusDomains));
-
   bool is_hangouts_app =
       manifest_url.SchemeIsFileSystem() &&
       manifest_url.inner_url() != NULL &&
@@ -76,5 +58,5 @@
       (manifest_url.inner_url()->host() == app_url.host()) &&
       IsHangoutsUrl(app_url);
 
-  return is_photo_app || is_hangouts_app;
+  return is_hangouts_app;
 }
diff --git a/chrome/renderer/app_categorizer_unittest.cc b/chrome/renderer/app_categorizer_unittest.cc
index 8a882aa..69b5f0b 100644
--- a/chrome/renderer/app_categorizer_unittest.cc
+++ b/chrome/renderer/app_categorizer_unittest.cc
@@ -34,32 +34,6 @@
   "https://talkgadget.evil.com/hangouts/foo"    // domain not whitelisted
 };
 
-const char* kPhotosAppURLs[] = {
-  "https://foo.plus.google.com",
-  "https://foo.plus.sandbox.google.com"
-};
-
-const char* kPhotosManifestURLs[] = {
-  "https://ssl.gstatic.com/photos/nacl/foo",
-  "https://ssl.gstatic.com/s2/oz/nacl/foo"
-};
-
-const char* kBadPhotosAppURLs[] = {
-  "https://plus.google.com/foo",
-  "https://plus.google.com/foo",
-  "https://plus.google.com/foo",
-  "http://plus.google.com/foo", // http scheme
-  "https://plus.evil.com/foo",  // domain not whitelisted
-};
-
-const char* kBadPhotosManifestURLs[] = {
-  "http://ssl.gstatic.com/photos/nacl/foo",         // http scheme
-  "https://lss.gstatic.com/photos/nacl/foo",        // bad hostname
-  "https://ssl.gstatic.com/wrong/photos/nacl/foo",  // bad path
-  "https://ssl.gstatic.com/photos/nacl/foo",
-  "https://ssl.gstatic.com/photos/nacl/foo",
-};
-
 }  // namespace
 
 TEST(AppCategorizerTest, IsHangoutsUrl) {
@@ -101,25 +75,4 @@
         GURL("filesystem:https://meet.google.com/foo"),
         GURL("https://hangouts.google.com/hangouts/foo")));
   }
-
-  // Photos app
-  {
-    EXPECT_EQ(arraysize(kPhotosAppURLs), arraysize(kPhotosManifestURLs));
-    for (size_t i = 0; i < arraysize(kPhotosAppURLs); ++i) {
-      EXPECT_TRUE(AppCategorizer::IsWhitelistedApp(
-          GURL(kPhotosManifestURLs[i]), GURL(kPhotosAppURLs[i])));
-    }
-    // The app/manifest two sides do not have any coorelation for the Photos app
-    for (size_t i = 0; i < arraysize(kPhotosAppURLs); ++i) {
-      EXPECT_TRUE(AppCategorizer::IsWhitelistedApp(
-          GURL(kPhotosManifestURLs[(i + 1) % arraysize(kPhotosAppURLs)]),
-          GURL(kPhotosAppURLs[i])));
-    }
-
-    EXPECT_EQ(arraysize(kBadPhotosAppURLs), arraysize(kBadPhotosManifestURLs));
-    for (size_t i = 0; i < arraysize(kBadPhotosAppURLs); ++i) {
-      EXPECT_FALSE(AppCategorizer::IsWhitelistedApp(
-          GURL(kBadPhotosManifestURLs[i]), GURL(kBadPhotosAppURLs[i])));
-    }
-  }
 }
diff --git a/chrome/renderer/chrome_content_renderer_client_unittest.cc b/chrome/renderer/chrome_content_renderer_client_unittest.cc
index ce3ad61..25e9c33 100644
--- a/chrome/renderer/chrome_content_renderer_client_unittest.cc
+++ b/chrome/renderer/chrome_content_renderer_client_unittest.cc
@@ -61,9 +61,6 @@
 #if !defined(DISABLE_NACL)
 const char kExtensionUrl[] = "chrome-extension://extension_id/background.html";
 
-const char kPhotosAppURL[] = "https://foo.plus.google.com";
-const char kPhotosManifestURL[] = "https://ssl.gstatic.com/photos/nacl/foo";
-
 const char kChatManifestFS[] = "filesystem:https://talkgadget.google.com/foo";
 #endif
 
@@ -277,15 +274,6 @@
   // interfaces. There is a whitelist for the app URL and the manifest URL.
   {
     WebPluginParams params;
-    // Whitelisted Photos app is allowed (two app URLs, two manifest URLs)
-    EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
-        GURL(kPhotosAppURL),
-        kNaClRestricted,
-        nullptr,
-        &params));
-    EXPECT_FALSE(AllowsDevInterfaces(params));
-
     // Whitelisted Chat app is allowed.
     EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
         GURL(kChatManifestFS),
@@ -296,51 +284,33 @@
 
     // Whitelisted manifest URL, bad app URLs, NOT allowed.
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
+        GURL(kChatManifestFS),
         GURL("http://plus.google.com/foo"),  // http scheme
-        kNaClRestricted,
-        nullptr,
-        &params));
+        kNaClRestricted, nullptr, &params));
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
+        GURL(kChatManifestFS),
         GURL("http://plus.sandbox.google.com/foo"),  // http scheme
-        kNaClRestricted,
-        nullptr,
-        &params));
+        kNaClRestricted, nullptr, &params));
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
+        GURL(kChatManifestFS),
         GURL("https://plus.google.evil.com/foo"),  // bad host
-        kNaClRestricted,
-        nullptr,
-        &params));
+        kNaClRestricted, nullptr, &params));
     // Whitelisted app URL, bad manifest URL, NOT allowed.
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
         GURL("http://ssl.gstatic.com/s2/oz/nacl/foo"),  // http scheme
-        GURL(kPhotosAppURL),
-        kNaClRestricted,
-        nullptr,
-        &params));
+        GURL(kChatAppURL), kNaClRestricted, nullptr, &params));
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
         GURL("https://ssl.gstatic.evil.com/s2/oz/nacl/foo"),  // bad host
-        GURL(kPhotosAppURL),
-        kNaClRestricted,
-        nullptr,
-        &params));
+        GURL(kChatAppURL), kNaClRestricted, nullptr, &params));
     EXPECT_FALSE(ChromeContentRendererClient::IsNaClAllowed(
         GURL("https://ssl.gstatic.com/wrong/s2/oz/nacl/foo"),  // bad path
-        GURL(kPhotosAppURL),
-        kNaClRestricted,
-        nullptr,
-        &params));
+        GURL(kChatAppURL), kNaClRestricted, nullptr, &params));
   }
   // Whitelisted URLs can't get 'dev' interfaces with --enable-nacl.
   {
     WebPluginParams params;
     EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
-        GURL(kPhotosAppURL),
-        kNaClUnrestricted,
-        nullptr,
+        GURL(kChatManifestFS), GURL(kChatAppURL), kNaClUnrestricted, nullptr,
         &params));
     EXPECT_FALSE(AllowsDevInterfaces(params));
   }
@@ -350,10 +320,7 @@
     WebPluginParams params;
     AddFakeDevAttribute(&params);
     EXPECT_TRUE(ChromeContentRendererClient::IsNaClAllowed(
-        GURL(kPhotosManifestURL),
-        GURL(kPhotosAppURL),
-        kNaClRestricted,
-        nullptr,
+        GURL(kChatManifestFS), GURL(kChatAppURL), kNaClRestricted, nullptr,
         &params));
     EXPECT_FALSE(AllowsDevInterfaces(params));
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 49a64ef..f4601a9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -580,6 +580,7 @@
         # TODO(crbug.com/679127): Investigate why these tests currently break
         # on Mac, and enable them.
         sources += [
+          "../browser/ui/views/payments/payment_method_view_controller_interactive_uitest.cc",
           "../browser/ui/views/payments/payment_request_credit_card_editor_interactive_uitest.cc",
           "../browser/ui/views/payments/payment_request_interactive_uitest.cc",
           "../browser/ui/views/payments/payment_request_interactive_uitest_base.cc",
@@ -4813,6 +4814,7 @@
       "../browser/ui/views/confirm_bubble_views_unittest.cc",
       "../browser/ui/views/global_error_bubble_view_unittest.cc",
       "../browser/ui/views/payments/credit_card_editor_view_controller_unittest.cc",
+      "../browser/ui/views/payments/payment_request_item_list_unittest.cc",
       "../browser/ui/views/payments/validating_textfield_unittest.cc",
       "../browser/ui/views/payments/view_stack_unittest.cc",
       "../browser/ui/views/website_settings/website_settings_popup_view_unittest.cc",
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 9dfe6ff5..5b3a0231 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -395,7 +395,6 @@
       "dom_distiller/content/browser/test/dom_distiller_js_browsertest.cc",
       "password_manager/content/renderer/credential_manager_client_browsertest.cc",
       "security_state/content/content_utils_browsertest.cc",
-      "tracing/child/child_trace_message_filter_browsertest.cc",
     ]
 
     data = [
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index 4223737..0f6fb08 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -67,6 +67,7 @@
   gfx::RectF TransformBoundingBoxToViewportCoordinates(
       const gfx::RectF& bounding_box) override;
   void DidInteractWithCreditCardForm() override;
+  void NotifyFirstUserGestureObservedInTab() override;
 
   // mojom::AutofillDriver:
   void FirstUserGestureObserved() override;
@@ -93,10 +94,6 @@
   // Called when the frame has navigated.
   void DidNavigateFrame(content::NavigationHandle* navigation_handle);
 
-  // Tells the render frame that a user gesture was observed
-  // somewhere in the tab (including in a different frame).
-  void NotifyFirstUserGestureObservedInTab();
-
   AutofillExternalDelegate* autofill_external_delegate() {
     return &autofill_external_delegate_;
   }
diff --git a/components/autofill/core/browser/autofill_driver.h b/components/autofill/core/browser/autofill_driver.h
index a702eb26..e8b95d8 100644
--- a/components/autofill/core/browser/autofill_driver.h
+++ b/components/autofill/core/browser/autofill_driver.h
@@ -103,6 +103,10 @@
   // Called when the user interacted with a credit card form, so that
   // the current page's security state can be updated appropriately.
   virtual void DidInteractWithCreditCardForm() = 0;
+
+  // Tells the associated frame that a user gesture was observed somewhere in
+  // the tab (including in a different frame).
+  virtual void NotifyFirstUserGestureObservedInTab() {}
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver_factory.cc b/components/autofill/core/browser/autofill_driver_factory.cc
index 19d369bb1..224c1efd 100644
--- a/components/autofill/core/browser/autofill_driver_factory.cc
+++ b/components/autofill/core/browser/autofill_driver_factory.cc
@@ -20,20 +20,8 @@
   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() {
+  user_gesture_seen_ = false;
   client_->HideAutofillPopup();
 }
 
@@ -41,4 +29,30 @@
   client_->HideAutofillPopup();
 }
 
+void AutofillDriverFactory::OnFirstUserGestureObserved() {
+  if (user_gesture_seen_)
+    return;
+
+  for (auto& driver : driver_map_)
+    driver.second->NotifyFirstUserGestureObservedInTab();
+
+  user_gesture_seen_ = true;
+}
+
+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();
+    if (user_gesture_seen_)
+      insertion_result.first->second->NotifyFirstUserGestureObservedInTab();
+  }
+}
+
+void AutofillDriverFactory::DeleteForKey(void* key) {
+  driver_map_.erase(key);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_driver_factory.h b/components/autofill/core/browser/autofill_driver_factory.h
index 8446d7a..ff48bb6 100644
--- a/components/autofill/core/browser/autofill_driver_factory.h
+++ b/components/autofill/core/browser/autofill_driver_factory.h
@@ -17,11 +17,9 @@
 class AutofillDriver;
 
 // Manages the lifetime of AutofillDrivers for a particular AutofillClient by
-// creating, retrieveing and deleting on demand.
+// creating, notifying, retrieving and deleting on demand.
 class AutofillDriverFactory {
-  // The API is protected to guarantee subclasses that nothing else can
-  // interfere with the map of drivers.
- protected:
+ public:
   explicit AutofillDriverFactory(AutofillClient* client);
 
   ~AutofillDriverFactory();
@@ -30,8 +28,27 @@
   // null if there is none.
   AutofillDriver* DriverForKey(void* key);
 
+  // Handles finished navigation in any of the frames.
+  void NavigationFinished();
+
+  // Handles hiding of the corresponding tab.
+  void TabHidden();
+
+  // Call this to notify the factory that one of the frames saw a user gesture.
+  // The factory will distribute this information to all drivers when it comes
+  // for the first time since the last main frame navigation to a different
+  // page. It will also notify drivers added later (see AddForKey).
+  void OnFirstUserGestureObserved();
+
+  AutofillClient* client() { return client_; };
+
+ protected:
+  // The API manipulating the drivers map is protected to guarantee subclasses
+  // that nothing else can interfere with the map of drivers.
+
   // Adds a driver, constructed by calling |factory_method|, for |key|. If there
-  // already is a driver for |key|, |factory_method| is not called.
+  // already is a driver for |key|, |factory_method| is not called. This might
+  // end up notifying the driver that a user gesture has been observed.
   void AddForKey(
       void* key,
       base::Callback<std::unique_ptr<AutofillDriver>()> factory_method);
@@ -39,19 +56,13 @@
   // 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_;
 
+  bool user_gesture_seen_ = false;  // The state for OnFirstUserGestureObserved.
+
   DISALLOW_COPY_AND_ASSIGN(AutofillDriverFactory);
 };
 
diff --git a/components/autofill/core/browser/autofill_driver_factory_unittest.cc b/components/autofill/core/browser/autofill_driver_factory_unittest.cc
index e79c4716..8355161 100644
--- a/components/autofill/core/browser/autofill_driver_factory_unittest.cc
+++ b/components/autofill/core/browser/autofill_driver_factory_unittest.cc
@@ -25,7 +25,8 @@
 };
 
 // Just a stub AutofillDriver implementation which announces its construction
-// and desctruction by updating the passed |instance_counter|.
+// and desctruction by updating the passed |instance_counter|. It also records
+// when "user gesture observed" was signalled to it.
 class CountingAutofillDriver : public TestAutofillDriver {
  public:
   CountingAutofillDriver(int* instance_counter)
@@ -35,8 +36,19 @@
 
   ~CountingAutofillDriver() override { --*instance_counter_; }
 
+  // Note that EXPECT_CALL cannot be used here, because creation and
+  // notification of the same driver might be done by a single AddForKey call
+  // from the test. Therefore tracking the "gesture_observed" flag is done
+  // explicitly here.
+  void NotifyFirstUserGestureObservedInTab() override {
+    gesture_observed_ = true;
+  }
+
+  bool gesture_observed() { return gesture_observed_; }
+
  private:
   int* const instance_counter_;
+  bool gesture_observed_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(CountingAutofillDriver);
 };
@@ -51,11 +63,8 @@
 
   ~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.
@@ -85,6 +94,11 @@
   // constants.
   void* KeyFrom(int x) { return reinterpret_cast<void*>(x); }
 
+  // Convenience accessor with a cast to CountingAutofillDriver.
+  CountingAutofillDriver* GetDriver(void* key) {
+    return static_cast<CountingAutofillDriver*>(factory_.DriverForKey(key));
+  }
+
   std::unique_ptr<AutofillDriver> CreateDriver() {
     ++drivers_created_;
     return base::MakeUnique<CountingAutofillDriver>(instance_counter_.val());
@@ -173,4 +187,54 @@
   factory_.TabHidden();
 }
 
+// Without calling OnFirstUserGestureObserved on the factory, the factory will
+// not call NotifyFirstUserGestureObservedInTab on a driver.
+TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_NotCalled) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_FALSE(GetDriver(KeyFrom(1))->gesture_observed());
+}
+
+// Call OnFirstUserGestureObserved on the factory with one driver. The factory
+// will call NotifyFirstUserGestureObservedInTab on that driver.
+TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledOld) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  factory_.OnFirstUserGestureObserved();
+  EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
+}
+
+// Call OnFirstUserGestureObserved on the factory without drivers. Add a
+// driver. The factory will call NotifyFirstUserGestureObservedInTab on that
+// driver.
+TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNew) {
+  factory_.OnFirstUserGestureObserved();
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
+}
+
+// Combining the CalledOld and CalledNew test cases into one.
+TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_MultipleDrivers) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  factory_.OnFirstUserGestureObserved();
+  EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
+
+  factory_.AddForKey(KeyFrom(7), CreateDriverCallback());
+  EXPECT_TRUE(GetDriver(KeyFrom(7))->gesture_observed());
+}
+
+// Call OnFirstUserGestureObserved on the factory with one driver. Simulate
+// navigation to a different page. Add a driver. The factory will not call
+// NotifyFirstUserGestureObservedInTab on that driver.
+TEST_F(AutofillDriverFactoryTest, OnFirstUserGestureObserved_CalledNavigation) {
+  factory_.AddForKey(KeyFrom(1), CreateDriverCallback());
+  factory_.OnFirstUserGestureObserved();
+  EXPECT_TRUE(GetDriver(KeyFrom(1))->gesture_observed());
+
+  EXPECT_CALL(client_, HideAutofillPopup());
+  factory_.NavigationFinished();
+
+  // Adding a sub-frame
+  factory_.AddForKey(KeyFrom(2), CreateDriverCallback());
+  EXPECT_FALSE(GetDriver(KeyFrom(2))->gesture_observed());
+}
+
 }  // namespace autofill
diff --git a/components/nacl/browser/pnacl_translation_cache.cc b/components/nacl/browser/pnacl_translation_cache.cc
index a183d59..1f71fe39 100644
--- a/components/nacl/browser/pnacl_translation_cache.cc
+++ b/components/nacl/browser/pnacl_translation_cache.cc
@@ -42,7 +42,7 @@
 // operations. It also tracks the open disk_cache::Entry
 // and ensures that the entry is closed.
 class PnaclTranslationCacheEntry
-    : public base::RefCounted<PnaclTranslationCacheEntry> {
+    : public base::RefCountedThreadSafe<PnaclTranslationCacheEntry> {
  public:
   static PnaclTranslationCacheEntry* GetReadEntry(
       base::WeakPtr<PnaclTranslationCache> cache,
@@ -76,7 +76,7 @@
   };
 
  private:
-  friend class base::RefCounted<PnaclTranslationCacheEntry>;
+  friend class base::RefCountedThreadSafe<PnaclTranslationCacheEntry>;
   PnaclTranslationCacheEntry(base::WeakPtr<PnaclTranslationCache> cache,
                              const std::string& key,
                              bool is_read);
diff --git a/components/omnibox/browser/in_memory_url_index_types.cc b/components/omnibox/browser/in_memory_url_index_types.cc
index 9718068..69798d1 100644
--- a/components/omnibox/browser/in_memory_url_index_types.cc
+++ b/components/omnibox/browser/in_memory_url_index_types.cc
@@ -62,10 +62,9 @@
 
 std::vector<size_t> OffsetsFromTermMatches(const TermMatches& matches) {
   std::vector<size_t> offsets;
-  for (TermMatches::const_iterator i = matches.begin(); i != matches.end();
-       ++i) {
-    offsets.push_back(i->offset);
-    offsets.push_back(i->offset + i->length);
+  for (const auto& match : matches) {
+    offsets.push_back(match.offset);
+    offsets.push_back(match.offset + match.length);
   }
   return offsets;
 }
@@ -98,11 +97,10 @@
                                     WordStarts* word_starts) {
   String16Vector words =
       String16VectorFromString16(cleaned_uni_string, false, word_starts);
-  String16Set word_set;
-  for (String16Vector::const_iterator iter = words.begin(); iter != words.end();
-       ++iter)
-    word_set.insert(base::i18n::ToLower(*iter).substr(0, kMaxSignificantChars));
-  return word_set;
+  for (auto& word : words)
+    word = base::i18n::ToLower(word).substr(0, kMaxSignificantChars);
+  return String16Set(std::make_move_iterator(words.begin()),
+                     std::make_move_iterator(words.end()));
 }
 
 String16Vector String16VectorFromString16(
@@ -141,25 +139,29 @@
 }
 
 Char16Set Char16SetFromString16(const base::string16& term) {
-  Char16Set characters;
-  for (base::string16::const_iterator iter = term.begin(); iter != term.end();
-       ++iter)
-    characters.insert(*iter);
-  return characters;
+  return Char16Set(term.begin(), term.end());
 }
 
 // HistoryInfoMapValue ---------------------------------------------------------
 
-HistoryInfoMapValue::HistoryInfoMapValue() {}
+HistoryInfoMapValue::HistoryInfoMapValue() = default;
 HistoryInfoMapValue::HistoryInfoMapValue(const HistoryInfoMapValue& other) =
     default;
-HistoryInfoMapValue::~HistoryInfoMapValue() {}
+HistoryInfoMapValue::HistoryInfoMapValue(HistoryInfoMapValue&& other) = default;
+HistoryInfoMapValue& HistoryInfoMapValue::operator=(
+    const HistoryInfoMapValue& other) = default;
+HistoryInfoMapValue& HistoryInfoMapValue::operator=(
+    HistoryInfoMapValue&& other) = default;
+HistoryInfoMapValue::~HistoryInfoMapValue() = default;
 
 // RowWordStarts ---------------------------------------------------------------
 
-RowWordStarts::RowWordStarts() {}
+RowWordStarts::RowWordStarts() = default;
 RowWordStarts::RowWordStarts(const RowWordStarts& other) = default;
-RowWordStarts::~RowWordStarts() {}
+RowWordStarts::RowWordStarts(RowWordStarts&& other) = default;
+RowWordStarts& RowWordStarts::operator=(const RowWordStarts& other) = default;
+RowWordStarts& RowWordStarts::operator=(RowWordStarts&& other) = default;
+RowWordStarts::~RowWordStarts() = default;
 
 void RowWordStarts::Clear() {
   url_word_starts_.clear();
diff --git a/components/omnibox/browser/in_memory_url_index_types.h b/components/omnibox/browser/in_memory_url_index_types.h
index 070ba43..6d38a79f 100644
--- a/components/omnibox/browser/in_memory_url_index_types.h
+++ b/components/omnibox/browser/in_memory_url_index_types.h
@@ -147,6 +147,9 @@
 struct HistoryInfoMapValue {
   HistoryInfoMapValue();
   HistoryInfoMapValue(const HistoryInfoMapValue& other);
+  HistoryInfoMapValue(HistoryInfoMapValue&& other);
+  HistoryInfoMapValue& operator=(const HistoryInfoMapValue& other);
+  HistoryInfoMapValue& operator=(HistoryInfoMapValue&& other);
   ~HistoryInfoMapValue();
 
   // This field is always populated.
@@ -166,6 +169,9 @@
 struct RowWordStarts {
   RowWordStarts();
   RowWordStarts(const RowWordStarts& other);
+  RowWordStarts(RowWordStarts&& other);
+  RowWordStarts& operator=(const RowWordStarts& other);
+  RowWordStarts& operator=(RowWordStarts&& other);
   ~RowWordStarts();
 
   // Clears both url_word_starts_ and title_word_starts_.
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc
index 1e08dce..14996f64d 100644
--- a/components/omnibox/browser/in_memory_url_index_unittest.cc
+++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -7,6 +7,7 @@
 
 #include <algorithm>
 #include <fstream>
+#include <numeric>
 
 #include "base/auto_reset.h"
 #include "base/files/file_path.h"
@@ -738,15 +739,13 @@
   };
 
   auto GetHistoryIdsUpTo = [&](HistoryID max) {
-    HistoryIDSet res;
-    // All ids are inserted in the end so the implicit hint would work.
-    for (HistoryID id = kMinRowId; id < max; ++id)
-      res.insert(id);
+    HistoryIDVector res(max - kMinRowId);
+    std::iota(res.begin(), res.end(), kMinRowId);
     return res;
   };
 
   auto CountGroupElementsInIds = [](const ItemGroup& group,
-                                    const HistoryIDSet& ids) {
+                                    const HistoryIDVector& ids) {
     return std::count_if(ids.begin(), ids.end(), [&](history::URLID id) {
       return group.min_id <= id && id < group.max_id;
     });
diff --git a/components/omnibox/browser/scored_history_match.cc b/components/omnibox/browser/scored_history_match.cc
index 5dddb3f..f0424978 100644
--- a/components/omnibox/browser/scored_history_match.cc
+++ b/components/omnibox/browser/scored_history_match.cc
@@ -320,9 +320,12 @@
 
 ScoredHistoryMatch::ScoredHistoryMatch(const ScoredHistoryMatch& other) =
     default;
-
-ScoredHistoryMatch::~ScoredHistoryMatch() {
-}
+ScoredHistoryMatch::ScoredHistoryMatch(ScoredHistoryMatch&& other) = default;
+ScoredHistoryMatch& ScoredHistoryMatch::operator=(
+    const ScoredHistoryMatch& other) = default;
+ScoredHistoryMatch& ScoredHistoryMatch::operator=(ScoredHistoryMatch&& other) =
+    default;
+ScoredHistoryMatch::~ScoredHistoryMatch() = default;
 
 // Comparison function for sorting ScoredMatches by their scores with
 // intelligent tie-breaking.
diff --git a/components/omnibox/browser/scored_history_match.h b/components/omnibox/browser/scored_history_match.h
index 51d18835..f9c432a 100644
--- a/components/omnibox/browser/scored_history_match.h
+++ b/components/omnibox/browser/scored_history_match.h
@@ -37,6 +37,9 @@
   // Required for STL, we don't use this directly.
   ScoredHistoryMatch();
   ScoredHistoryMatch(const ScoredHistoryMatch& other);
+  ScoredHistoryMatch(ScoredHistoryMatch&& other);
+  ScoredHistoryMatch& operator=(const ScoredHistoryMatch& other);
+  ScoredHistoryMatch& operator=(ScoredHistoryMatch&& other);
 
   // Initializes the ScoredHistoryMatch with a raw score calculated for the
   // history item given in |row| with recent visits as indicated in |visits|. It
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 6556116c..e410239 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -37,6 +37,8 @@
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
 #endif
 
+namespace {
+
 using google::protobuf::RepeatedField;
 using google::protobuf::RepeatedPtrField;
 using in_memory_url_index::InMemoryURLIndexCacheItem;
@@ -77,6 +79,7 @@
   return string_a.length() > string_b.length();
 }
 
+}  // namespace
 
 // UpdateRecentVisitsFromHistoryDBTask -----------------------------------------
 
@@ -187,22 +190,20 @@
             net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
 
     // Extract individual 'words' (as opposed to 'terms'; see comment in
-    // HistoryIdSetToScoredMatches()) from the search string. When the user
-    // types "colspec=ID%20Mstone Release" we get four 'words': "colspec", "id",
+    // HistoryIdsToScoredMatches()) from the search string. When the user types
+    // "colspec=ID%20Mstone Release" we get four 'words': "colspec", "id",
     // "mstone" and "release".
     String16Vector lower_words(
         String16VectorFromString16(lower_unescaped_string, false, nullptr));
     if (lower_words.empty())
       continue;
-    HistoryIDSet history_id_set = HistoryIDSetFromWords(lower_words);
-    history_ids_were_trimmed |= TrimHistoryIdsPool(&history_id_set);
 
-    ScoredHistoryMatches temp_scored_items;
-    HistoryIdSetToScoredMatches(history_id_set, lower_raw_string,
-                                template_url_service, bookmark_model,
-                                &temp_scored_items);
-    scored_items.insert(scored_items.end(), temp_scored_items.begin(),
-                        temp_scored_items.end());
+    HistoryIDVector history_ids = HistoryIDsFromWords(lower_words);
+    history_ids_were_trimmed |= TrimHistoryIdsPool(&history_ids);
+
+    HistoryIdsToScoredMatches(std::move(history_ids), lower_raw_string,
+                              template_url_service, bookmark_model,
+                              &scored_items);
   }
   // Select and sort only the top |max_matches| results.
   if (scored_items.size() > max_matches) {
@@ -452,7 +453,7 @@
 void URLIndexPrivateData::Clear() {
   last_time_rebuilt_from_history_ = base::Time();
   word_list_.clear();
-  available_words_.clear();
+  available_words_ = std::stack<WordID>();
   word_map_.clear();
   char_word_map_.clear();
   word_id_history_map_.clear();
@@ -463,57 +464,56 @@
 
 URLIndexPrivateData::~URLIndexPrivateData() {}
 
-HistoryIDSet URLIndexPrivateData::HistoryIDSetFromWords(
+HistoryIDVector URLIndexPrivateData::HistoryIDsFromWords(
     const String16Vector& unsorted_words) {
+  // This histogram name reflects the historic name of this function.
   SCOPED_UMA_HISTOGRAM_TIMER("Omnibox.HistoryQuickHistoryIDSetFromWords");
   // Break the terms down into individual terms (words), get the candidate
   // set for each term, and intersect each to get a final candidate list.
   // Note that a single 'term' from the user's perspective might be
   // a string like "http://www.somewebsite.com" which, from our perspective,
   // is four words: 'http', 'www', 'somewebsite', and 'com'.
-  HistoryIDSet history_id_set;
+  HistoryIDVector history_ids;
   String16Vector words(unsorted_words);
   // Sort the words into the longest first as such are likely to narrow down
   // the results quicker. Also, single character words are the most expensive
   // to process so save them for last.
   std::sort(words.begin(), words.end(), LengthGreater);
+
+  // TODO(dyaroshev): write a generic algorithm(crbug.com/696167).
   for (String16Vector::iterator iter = words.begin(); iter != words.end();
        ++iter) {
     base::string16 uni_word = *iter;
     HistoryIDSet term_history_set = HistoryIDsForTerm(uni_word);
     if (term_history_set.empty()) {
-      history_id_set.clear();
+      history_ids.clear();
       break;
     }
     if (iter == words.begin()) {
-      history_id_set.swap(term_history_set);
+      history_ids = {term_history_set.begin(), term_history_set.end()};
     } else {
-      HistoryIDSet new_history_id_set = base::STLSetIntersection<HistoryIDSet>(
-          history_id_set, term_history_set);
-      history_id_set.swap(new_history_id_set);
+      history_ids = base::STLSetIntersection<HistoryIDVector>(history_ids,
+                                                              term_history_set);
     }
   }
-  return history_id_set;
+  return history_ids;
 }
 
 bool URLIndexPrivateData::TrimHistoryIdsPool(
-    HistoryIDSet* history_id_set) const {
+    HistoryIDVector* history_ids) const {
   constexpr size_t kItemsToScoreLimit = 500;
-  if (history_id_set->size() <= kItemsToScoreLimit)
+  if (history_ids->size() <= kItemsToScoreLimit)
     return false;
 
-  HistoryIDVector history_ids(history_id_set->begin(), history_id_set->end());
-
   // Trim down the set by sorting by typed-count, visit-count, and last
   // visit.
-  auto new_end = history_ids.begin() + kItemsToScoreLimit;
+  auto new_end = history_ids->begin() + kItemsToScoreLimit;
   HistoryItemFactorGreater item_factor_functor(history_info_map_);
 
-  std::nth_element(history_ids.begin(), new_end, history_ids.end(),
+  std::nth_element(history_ids->begin(), new_end, history_ids->end(),
                    item_factor_functor);
-  history_ids.erase(new_end, history_ids.end());
+  history_ids->erase(new_end, history_ids->end());
 
-  *history_id_set = {history_ids.begin(), history_ids.end()};
   return true;
 }
 
@@ -581,13 +581,9 @@
         return HistoryIDSet();
       }
       // Or there may not have been a prefix from which to start.
-      if (prefix_chars.empty()) {
-        word_id_set.swap(leftover_set);
-      } else {
-        WordIDSet new_word_id_set = base::STLSetIntersection<WordIDSet>(
-            word_id_set, leftover_set);
-        word_id_set.swap(new_word_id_set);
-      }
+      word_id_set = prefix_chars.empty() ? std::move(leftover_set)
+                                         : base::STLSetIntersection<WordIDSet>(
+                                               word_id_set, leftover_set);
     }
 
     // We must filter the word list because the resulting word set surely
@@ -606,16 +602,12 @@
   // If any words resulted then we can compose a set of history IDs by unioning
   // the sets from each word.
   HistoryIDSet history_id_set;
-  if (!word_id_set.empty()) {
-    for (WordIDSet::iterator word_id_iter = word_id_set.begin();
-         word_id_iter != word_id_set.end(); ++word_id_iter) {
-      WordID word_id = *word_id_iter;
-      WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id);
-      if (word_iter != word_id_history_map_.end()) {
-        HistoryIDSet& word_history_id_set(word_iter->second);
-        history_id_set.insert(word_history_id_set.begin(),
-                              word_history_id_set.end());
-      }
+  for (WordID word_id : word_id_set) {
+    WordIDHistoryMap::iterator word_iter = word_id_history_map_.find(word_id);
+    if (word_iter != word_id_history_map_.end()) {
+      HistoryIDSet& word_history_id_set(word_iter->second);
+      history_id_set.insert(word_history_id_set.begin(),
+                            word_history_id_set.end());
     }
   }
 
@@ -629,6 +621,8 @@
 
 WordIDSet URLIndexPrivateData::WordIDSetForTermChars(
     const Char16Set& term_chars) {
+  // TODO(dyaroshev): write a generic algorithm(crbug.com/696167).
+
   WordIDSet word_id_set;
   for (Char16Set::const_iterator c_iter = term_chars.begin();
        c_iter != term_chars.end(); ++c_iter) {
@@ -651,21 +645,20 @@
       word_id_set = char_word_id_set;
     } else {
       // Subsequent character results get intersected in.
-      WordIDSet new_word_id_set = base::STLSetIntersection<WordIDSet>(
-          word_id_set, char_word_id_set);
-      word_id_set.swap(new_word_id_set);
+      word_id_set =
+          base::STLSetIntersection<WordIDSet>(word_id_set, char_word_id_set);
     }
   }
   return word_id_set;
 }
 
-void URLIndexPrivateData::HistoryIdSetToScoredMatches(
-    HistoryIDSet history_id_set,
+void URLIndexPrivateData::HistoryIdsToScoredMatches(
+    HistoryIDVector history_ids,
     const base::string16& lower_raw_string,
     const TemplateURLService* template_url_service,
     bookmarks::BookmarkModel* bookmark_model,
     ScoredHistoryMatches* scored_items) const {
-  if (history_id_set.empty())
+  if (history_ids.empty())
     return;
 
   // Break up the raw search string (complete with escaped URL elements) into
@@ -693,41 +686,32 @@
                              &lower_terms_to_word_starts_offsets);
 
   // Filter bad matches and other matches we don't want to display.
-  for (auto it = history_id_set.begin();;) {
-    it = std::find_if(it, history_id_set.end(),
-                      [this, template_url_service](const HistoryID history_id) {
-                        return ShouldFilter(history_id, template_url_service);
-                      });
-    if (it == history_id_set.end())
-      break;
-    it = history_id_set.erase(it);
-  }
+  auto filter = [this, template_url_service](const HistoryID history_id) {
+    return ShouldFilter(history_id, template_url_service);
+  };
+  history_ids.erase(
+      std::remove_if(history_ids.begin(), history_ids.end(), filter),
+      history_ids.end());
 
   // Score the matches.
-  const size_t num_matches = history_id_set.size();
+  const size_t num_matches = history_ids.size();
   const base::Time now = base::Time::Now();
-  std::transform(
-      history_id_set.begin(), history_id_set.end(),
-      std::back_inserter(*scored_items), [&](const HistoryID history_id) {
-        auto hist_pos = history_info_map_.find(history_id);
-        const history::URLRow& hist_item = hist_pos->second.url_row;
-        auto starts_pos = word_starts_map_.find(history_id);
-        DCHECK(starts_pos != word_starts_map_.end());
-        return ScoredHistoryMatch(
-            hist_item, hist_pos->second.visits, lower_raw_string,
-            lower_raw_terms, lower_terms_to_word_starts_offsets,
-            starts_pos->second,
-            bookmark_model && bookmark_model->IsBookmarked(hist_item.url()),
-            num_matches, now);
-      });
 
-  // Filter all matches that ended up scoring 0.  (These are usually matches
-  // which didn't match the user's raw terms.)
-  scored_items->erase(std::remove_if(scored_items->begin(), scored_items->end(),
-                                     [](const ScoredHistoryMatch& match) {
-                                       return match.raw_score == 0;
-                                     }),
-                      scored_items->end());
+  for (HistoryID history_id : history_ids) {
+    auto hist_pos = history_info_map_.find(history_id);
+    const history::URLRow& hist_item = hist_pos->second.url_row;
+    auto starts_pos = word_starts_map_.find(history_id);
+    DCHECK(starts_pos != word_starts_map_.end());
+    ScoredHistoryMatch new_scored_match(
+        hist_item, hist_pos->second.visits, lower_raw_string, lower_raw_terms,
+        lower_terms_to_word_starts_offsets, starts_pos->second,
+        bookmark_model && bookmark_model->IsBookmarked(hist_item.url()),
+        num_matches, now);
+    // Filter new matches that ended up scoring 0. (These are usually matches
+    // which didn't match the user's raw terms.)
+    if (new_scored_match.raw_score != 0)
+      scored_items->push_back(std::move(new_scored_match));
+  }
 }
 
 // static
@@ -819,80 +803,44 @@
   const base::string16& title = bookmarks::CleanUpTitleForMatching(row.title());
   String16Set title_words = String16SetFromString16(title,
       word_starts ? &word_starts->title_word_starts_ : nullptr);
-  String16Set words = base::STLSetUnion<String16Set>(url_words, title_words);
-  for (String16Set::iterator word_iter = words.begin();
-       word_iter != words.end(); ++word_iter)
-    AddWordToIndex(*word_iter, history_id);
+  for (const auto& word :
+       base::STLSetUnion<String16Set>(url_words, title_words))
+    AddWordToIndex(word, history_id);
 
   search_term_cache_.clear();  // Invalidate the term cache.
 }
 
 void URLIndexPrivateData::AddWordToIndex(const base::string16& term,
                                          HistoryID history_id) {
-  WordMap::iterator word_pos = word_map_.find(term);
-  if (word_pos != word_map_.end())
-    UpdateWordHistory(word_pos->second, history_id);
-  else
-    AddWordHistory(term, history_id);
+  WordMap::iterator word_pos;
+  bool is_new;
+  std::tie(word_pos, is_new) = word_map_.insert(std::make_pair(term, WordID()));
+
+  // Adding a new word (i.e. a word that is not already in the word index).
+  if (is_new) {
+    word_pos->second = AddNewWordToWordList(term);
+
+    // For each character in the newly added word add the word to the character
+    // index.
+    for (base::char16 uni_char : Char16SetFromString16(term))
+      char_word_map_[uni_char].insert(word_pos->second);
+  }
+
+  word_id_history_map_[word_pos->second].insert(history_id);
+  history_id_word_map_[history_id].insert(word_pos->second);
 }
 
-void URLIndexPrivateData::AddWordHistory(const base::string16& term,
-                                         HistoryID history_id) {
+WordID URLIndexPrivateData::AddNewWordToWordList(const base::string16& term) {
   WordID word_id = word_list_.size();
   if (available_words_.empty()) {
     word_list_.push_back(term);
-  } else {
-    word_id = *(available_words_.begin());
-    word_list_[word_id] = term;
-    available_words_.erase(word_id);
+    return word_id;
   }
-  word_map_[term] = word_id;
 
-  HistoryIDSet history_id_set;
-  history_id_set.insert(history_id);
-  word_id_history_map_[word_id] = history_id_set;
-  AddToHistoryIDWordMap(history_id, word_id);
-
-  // For each character in the newly added word (i.e. a word that is not
-  // already in the word index), add the word to the character index.
-  Char16Set characters = Char16SetFromString16(term);
-  for (Char16Set::iterator uni_char_iter = characters.begin();
-       uni_char_iter != characters.end(); ++uni_char_iter) {
-    base::char16 uni_char = *uni_char_iter;
-    CharWordIDMap::iterator char_iter = char_word_map_.find(uni_char);
-    if (char_iter != char_word_map_.end()) {
-      // Update existing entry in the char/word index.
-      WordIDSet& word_id_set(char_iter->second);
-      word_id_set.insert(word_id);
-    } else {
-      // Create a new entry in the char/word index.
-      WordIDSet word_id_set;
-      word_id_set.insert(word_id);
-      char_word_map_[uni_char] = word_id_set;
-    }
-  }
-}
-
-void URLIndexPrivateData::UpdateWordHistory(WordID word_id,
-                                            HistoryID history_id) {
-  WordIDHistoryMap::iterator history_pos = word_id_history_map_.find(word_id);
-  DCHECK(history_pos != word_id_history_map_.end());
-  HistoryIDSet& history_id_set(history_pos->second);
-  history_id_set.insert(history_id);
-  AddToHistoryIDWordMap(history_id, word_id);
-}
-
-void URLIndexPrivateData::AddToHistoryIDWordMap(HistoryID history_id,
-                                                WordID word_id) {
-  HistoryIDWordMap::iterator iter = history_id_word_map_.find(history_id);
-  if (iter != history_id_word_map_.end()) {
-    WordIDSet& word_id_set(iter->second);
-    word_id_set.insert(word_id);
-  } else {
-    WordIDSet word_id_set;
-    word_id_set.insert(word_id);
-    history_id_word_map_[history_id] = word_id_set;
-  }
+  word_id = available_words_.top();
+  available_words_.pop();
+  word_list_[word_id] = term;
+  return word_id;
 }
 
 void URLIndexPrivateData::RemoveRowFromIndex(const history::URLRow& row) {
@@ -910,36 +858,34 @@
   history_id_word_map_.erase(history_id);
 
   // Reconcile any changes to word usage.
-  for (WordIDSet::iterator word_id_iter = word_id_set.begin();
-       word_id_iter != word_id_set.end(); ++word_id_iter) {
-    WordID word_id = *word_id_iter;
-    word_id_history_map_[word_id].erase(history_id);
-    if (!word_id_history_map_[word_id].empty())
-      continue;  // The word is still in use.
+  for (WordID word_id : word_id_set) {
+    auto word_id_history_map_iter = word_id_history_map_.find(word_id);
+    DCHECK(word_id_history_map_iter != word_id_history_map_.end());
+
+    word_id_history_map_iter->second.erase(history_id);
+    if (!word_id_history_map_iter->second.empty())
+      continue;
 
     // The word is no longer in use. Reconcile any changes to character usage.
     base::string16 word = word_list_[word_id];
-    Char16Set characters = Char16SetFromString16(word);
-    for (Char16Set::iterator uni_char_iter = characters.begin();
-         uni_char_iter != characters.end(); ++uni_char_iter) {
-      base::char16 uni_char = *uni_char_iter;
-      char_word_map_[uni_char].erase(word_id);
-      if (char_word_map_[uni_char].empty())
-        char_word_map_.erase(uni_char);  // No longer in use.
+    for (base::char16 uni_char : Char16SetFromString16(word)) {
+      auto char_word_map_iter = char_word_map_.find(uni_char);
+      char_word_map_iter->second.erase(word_id);
+      if (char_word_map_iter->second.empty())
+        char_word_map_.erase(char_word_map_iter);
     }
 
     // Complete the removal of references to the word.
-    word_id_history_map_.erase(word_id);
+    word_id_history_map_.erase(word_id_history_map_iter);
     word_map_.erase(word);
     word_list_[word_id] = base::string16();
-    available_words_.insert(word_id);
+    available_words_.push(word_id);
   }
 }
 
 void URLIndexPrivateData::ResetSearchTermCache() {
-  for (SearchTermCacheMap::iterator iter = search_term_cache_.begin();
-       iter != search_term_cache_.end(); ++iter)
-    iter->second.used_ = false;
+  for (auto& item : search_term_cache_)
+    item.second.used_ = false;
 }
 
 bool URLIndexPrivateData::SaveToFile(const base::FilePath& file_path) {
@@ -984,9 +930,8 @@
     return;
   WordListItem* list_item = cache->mutable_word_list();
   list_item->set_word_count(word_list_.size());
-  for (String16Vector::const_iterator iter = word_list_.begin();
-       iter != word_list_.end(); ++iter)
-    list_item->add_word(base::UTF16ToUTF8(*iter));
+  for (const base::string16& word : word_list_)
+    list_item->add_word(base::UTF16ToUTF8(word));
 }
 
 void URLIndexPrivateData::SaveWordMap(InMemoryURLIndexCacheItem* cache) const {
@@ -994,11 +939,10 @@
     return;
   WordMapItem* map_item = cache->mutable_word_map();
   map_item->set_item_count(word_map_.size());
-  for (WordMap::const_iterator iter = word_map_.begin();
-       iter != word_map_.end(); ++iter) {
+  for (const auto& elem : word_map_) {
     WordMapEntry* map_entry = map_item->add_word_map_entry();
-    map_entry->set_word(base::UTF16ToUTF8(iter->first));
-    map_entry->set_word_id(iter->second);
+    map_entry->set_word(base::UTF16ToUTF8(elem.first));
+    map_entry->set_word_id(elem.second);
   }
 }
 
@@ -1008,15 +952,13 @@
     return;
   CharWordMapItem* map_item = cache->mutable_char_word_map();
   map_item->set_item_count(char_word_map_.size());
-  for (CharWordIDMap::const_iterator iter = char_word_map_.begin();
-       iter != char_word_map_.end(); ++iter) {
+  for (const auto& entry : char_word_map_) {
     CharWordMapEntry* map_entry = map_item->add_char_word_map_entry();
-    map_entry->set_char_16(iter->first);
-    const WordIDSet& word_id_set(iter->second);
+    map_entry->set_char_16(entry.first);
+    const WordIDSet& word_id_set = entry.second;
     map_entry->set_item_count(word_id_set.size());
-    for (WordIDSet::const_iterator set_iter = word_id_set.begin();
-         set_iter != word_id_set.end(); ++set_iter)
-      map_entry->add_word_id(*set_iter);
+    for (WordID word_id : word_id_set)
+      map_entry->add_word_id(word_id);
   }
 }
 
@@ -1026,16 +968,14 @@
     return;
   WordIDHistoryMapItem* map_item = cache->mutable_word_id_history_map();
   map_item->set_item_count(word_id_history_map_.size());
-  for (WordIDHistoryMap::const_iterator iter = word_id_history_map_.begin();
-       iter != word_id_history_map_.end(); ++iter) {
+  for (const auto& entry : word_id_history_map_) {
     WordIDHistoryMapEntry* map_entry =
         map_item->add_word_id_history_map_entry();
-    map_entry->set_word_id(iter->first);
-    const HistoryIDSet& history_id_set(iter->second);
+    map_entry->set_word_id(entry.first);
+    const HistoryIDSet& history_id_set = entry.second;
     map_entry->set_item_count(history_id_set.size());
-    for (HistoryIDSet::const_iterator set_iter = history_id_set.begin();
-         set_iter != history_id_set.end(); ++set_iter)
-      map_entry->add_history_id(*set_iter);
+    for (HistoryID history_id : history_id_set)
+      map_entry->add_history_id(history_id);
   }
 }
 
@@ -1045,11 +985,10 @@
     return;
   HistoryInfoMapItem* map_item = cache->mutable_history_info_map();
   map_item->set_item_count(history_info_map_.size());
-  for (HistoryInfoMap::const_iterator iter = history_info_map_.begin();
-       iter != history_info_map_.end(); ++iter) {
+  for (const auto& entry : history_info_map_) {
     HistoryInfoMapEntry* map_entry = map_item->add_history_info_map_entry();
-    map_entry->set_history_id(iter->first);
-    const history::URLRow& url_row(iter->second.url_row);
+    map_entry->set_history_id(entry.first);
+    const history::URLRow& url_row = entry.second.url_row;
     // Note: We only save information that contributes to the index so there
     // is no need to save search_term_cache_ (not persistent).
     map_entry->set_visit_count(url_row.visit_count());
@@ -1057,12 +996,10 @@
     map_entry->set_last_visit(url_row.last_visit().ToInternalValue());
     map_entry->set_url(url_row.url().spec());
     map_entry->set_title(base::UTF16ToUTF8(url_row.title()));
-    const VisitInfoVector& visits(iter->second.visits);
-    for (VisitInfoVector::const_iterator visit_iter = visits.begin();
-         visit_iter != visits.end(); ++visit_iter) {
+    for (const auto& visit : entry.second.visits) {
       HistoryInfoMapEntry_VisitInfo* visit_info = map_entry->add_visits();
-      visit_info->set_visit_time(visit_iter->first.ToInternalValue());
-      visit_info->set_transition_type(visit_iter->second);
+      visit_info->set_visit_time(visit.first.ToInternalValue());
+      visit_info->set_transition_type(visit.second);
     }
   }
 }
@@ -1081,17 +1018,14 @@
 
   WordStartsMapItem* map_item = cache->mutable_word_starts_map();
   map_item->set_item_count(word_starts_map_.size());
-  for (WordStartsMap::const_iterator iter = word_starts_map_.begin();
-       iter != word_starts_map_.end(); ++iter) {
+  for (const auto& entry : word_starts_map_) {
     WordStartsMapEntry* map_entry = map_item->add_word_starts_map_entry();
-    map_entry->set_history_id(iter->first);
-    const RowWordStarts& word_starts(iter->second);
-    for (WordStarts::const_iterator i = word_starts.url_word_starts_.begin();
-         i != word_starts.url_word_starts_.end(); ++i)
-      map_entry->add_url_word_starts(*i);
-    for (WordStarts::const_iterator i = word_starts.title_word_starts_.begin();
-         i != word_starts.title_word_starts_.end(); ++i)
-      map_entry->add_title_word_starts(*i);
+    map_entry->set_history_id(entry.first);
+    const RowWordStarts& word_starts = entry.second;
+    for (auto url_word_start : word_starts.url_word_starts_)
+      map_entry->add_url_word_starts(url_word_start);
+    for (auto title_word_start : word_starts.title_word_starts_)
+      map_entry->add_title_word_starts(title_word_start);
   }
 }
 
@@ -1133,10 +1067,11 @@
   uint32_t actual_item_count = list_item.word_size();
   if (actual_item_count == 0 || actual_item_count != expected_item_count)
     return false;
-  const RepeatedPtrField<std::string>& words(list_item.word());
-  for (RepeatedPtrField<std::string>::const_iterator iter = words.begin();
-       iter != words.end(); ++iter)
-    word_list_.push_back(base::UTF8ToUTF16(*iter));
+  const RepeatedPtrField<std::string>& words = list_item.word();
+  word_list_.reserve(words.size());
+  std::transform(
+      words.begin(), words.end(), std::back_inserter(word_list_),
+      [](const std::string& word) { return base::UTF8ToUTF16(word); });
   return true;
 }
 
@@ -1144,15 +1079,14 @@
     const InMemoryURLIndexCacheItem& cache) {
   if (!cache.has_word_map())
     return false;
-  const WordMapItem& list_item(cache.word_map());
+  const WordMapItem& list_item = cache.word_map();
   uint32_t expected_item_count = list_item.item_count();
   uint32_t actual_item_count = list_item.word_map_entry_size();
   if (actual_item_count == 0 || actual_item_count != expected_item_count)
     return false;
-  const RepeatedPtrField<WordMapEntry>& entries(list_item.word_map_entry());
-  for (RepeatedPtrField<WordMapEntry>::const_iterator iter = entries.begin();
-       iter != entries.end(); ++iter)
-    word_map_[base::UTF8ToUTF16(iter->word())] = iter->word_id();
+  for (const auto& entry : list_item.word_map_entry())
+    word_map_[base::UTF8ToUTF16(entry.word())] = entry.word_id();
+
   return true;
 }
 
@@ -1165,21 +1099,15 @@
   uint32_t actual_item_count = list_item.char_word_map_entry_size();
   if (actual_item_count == 0 || actual_item_count != expected_item_count)
     return false;
-  const RepeatedPtrField<CharWordMapEntry>&
-      entries(list_item.char_word_map_entry());
-  for (RepeatedPtrField<CharWordMapEntry>::const_iterator iter =
-       entries.begin(); iter != entries.end(); ++iter) {
-    expected_item_count = iter->item_count();
-    actual_item_count = iter->word_id_size();
+
+  for (const auto& entry : list_item.char_word_map_entry()) {
+    expected_item_count = entry.item_count();
+    actual_item_count = entry.word_id_size();
     if (actual_item_count == 0 || actual_item_count != expected_item_count)
       return false;
-    base::char16 uni_char = static_cast<base::char16>(iter->char_16());
-    WordIDSet word_id_set;
-    const RepeatedField<int32_t>& word_ids(iter->word_id());
-    for (RepeatedField<int32_t>::const_iterator jiter = word_ids.begin();
-         jiter != word_ids.end(); ++jiter)
-      word_id_set.insert(*jiter);
-    char_word_map_[uni_char] = word_id_set;
+    base::char16 uni_char = static_cast<base::char16>(entry.char_16());
+    const RepeatedField<int32_t>& word_ids = entry.word_id();
+    char_word_map_[uni_char] = {word_ids.begin(), word_ids.end()};
   }
   return true;
 }
@@ -1193,23 +1121,16 @@
   uint32_t actual_item_count = list_item.word_id_history_map_entry_size();
   if (actual_item_count == 0 || actual_item_count != expected_item_count)
     return false;
-  const RepeatedPtrField<WordIDHistoryMapEntry>&
-      entries(list_item.word_id_history_map_entry());
-  for (RepeatedPtrField<WordIDHistoryMapEntry>::const_iterator iter =
-       entries.begin(); iter != entries.end(); ++iter) {
-    expected_item_count = iter->item_count();
-    actual_item_count = iter->history_id_size();
+  for (const auto& entry : list_item.word_id_history_map_entry()) {
+    expected_item_count = entry.item_count();
+    actual_item_count = entry.history_id_size();
     if (actual_item_count == 0 || actual_item_count != expected_item_count)
       return false;
-    WordID word_id = iter->word_id();
-    HistoryIDSet history_id_set;
-    const RepeatedField<int64_t>& history_ids(iter->history_id());
-    for (RepeatedField<int64_t>::const_iterator jiter = history_ids.begin();
-         jiter != history_ids.end(); ++jiter) {
-      history_id_set.insert(*jiter);
-      AddToHistoryIDWordMap(*jiter, word_id);
-    }
-    word_id_history_map_[word_id] = history_id_set;
+    WordID word_id = entry.word_id();
+    const RepeatedField<int64_t>& history_ids = entry.history_id();
+    word_id_history_map_[word_id] = {history_ids.begin(), history_ids.end()};
+    for (HistoryID history_id : history_ids)
+      history_id_word_map_[history_id].insert(word_id);
   }
   return true;
 }
@@ -1223,31 +1144,26 @@
   uint32_t actual_item_count = list_item.history_info_map_entry_size();
   if (actual_item_count == 0 || actual_item_count != expected_item_count)
     return false;
-  const RepeatedPtrField<HistoryInfoMapEntry>&
-      entries(list_item.history_info_map_entry());
-  for (RepeatedPtrField<HistoryInfoMapEntry>::const_iterator iter =
-       entries.begin(); iter != entries.end(); ++iter) {
-    HistoryID history_id = iter->history_id();
-    GURL url(iter->url());
-    history::URLRow url_row(url, history_id);
-    url_row.set_visit_count(iter->visit_count());
-    url_row.set_typed_count(iter->typed_count());
-    url_row.set_last_visit(base::Time::FromInternalValue(iter->last_visit()));
-    if (iter->has_title()) {
-      base::string16 title(base::UTF8ToUTF16(iter->title()));
-      url_row.set_title(title);
-    }
-    history_info_map_[history_id].url_row = url_row;
+
+  for (const auto& entry : list_item.history_info_map_entry()) {
+    HistoryID history_id = entry.history_id();
+    history::URLRow url_row(GURL(entry.url()), history_id);
+    url_row.set_visit_count(entry.visit_count());
+    url_row.set_typed_count(entry.typed_count());
+    url_row.set_last_visit(base::Time::FromInternalValue(entry.last_visit()));
+    if (entry.has_title())
+      url_row.set_title(base::UTF8ToUTF16(entry.title()));
+    history_info_map_[history_id].url_row = std::move(url_row);
 
     // Restore visits list.
     VisitInfoVector visits;
-    visits.reserve(iter->visits_size());
-    for (int i = 0; i < iter->visits_size(); ++i) {
-      visits.push_back(std::make_pair(
-          base::Time::FromInternalValue(iter->visits(i).visit_time()),
-          ui::PageTransitionFromInt(iter->visits(i).transition_type())));
+    visits.reserve(entry.visits_size());
+    for (const auto& entry_visit : entry.visits()) {
+      visits.emplace_back(
+          base::Time::FromInternalValue(entry_visit.visit_time()),
+          ui::PageTransitionFromInt(entry_visit.transition_type()));
     }
-    history_info_map_[history_id].visits = visits;
+    history_info_map_[history_id].visits = std::move(visits);
   }
   return true;
 }
@@ -1263,38 +1179,33 @@
     uint32_t actual_item_count = list_item.word_starts_map_entry_size();
     if (actual_item_count == 0 || actual_item_count != expected_item_count)
       return false;
-    const RepeatedPtrField<WordStartsMapEntry>&
-        entries(list_item.word_starts_map_entry());
-    for (RepeatedPtrField<WordStartsMapEntry>::const_iterator iter =
-         entries.begin(); iter != entries.end(); ++iter) {
-      HistoryID history_id = iter->history_id();
+    for (const auto& entry : list_item.word_starts_map_entry()) {
+      HistoryID history_id = entry.history_id();
       RowWordStarts word_starts;
       // Restore the URL word starts.
-      const RepeatedField<int32_t>& url_starts(iter->url_word_starts());
-      for (RepeatedField<int32_t>::const_iterator jiter = url_starts.begin();
-           jiter != url_starts.end(); ++jiter)
-        word_starts.url_word_starts_.push_back(*jiter);
+      const RepeatedField<int32_t>& url_starts = entry.url_word_starts();
+      word_starts.url_word_starts_ = {url_starts.begin(), url_starts.end()};
+
       // Restore the page title word starts.
-      const RepeatedField<int32_t>& title_starts(iter->title_word_starts());
-      for (RepeatedField<int32_t>::const_iterator jiter = title_starts.begin();
-           jiter != title_starts.end(); ++jiter)
-        word_starts.title_word_starts_.push_back(*jiter);
-      word_starts_map_[history_id] = word_starts;
+      const RepeatedField<int32_t>& title_starts = entry.title_word_starts();
+      word_starts.title_word_starts_ = {title_starts.begin(),
+                                        title_starts.end()};
+
+      word_starts_map_[history_id] = std::move(word_starts);
     }
   } else {
     // Since the cache did not contain any word starts we must rebuild then from
     // the URL and page titles.
-    for (HistoryInfoMap::const_iterator iter = history_info_map_.begin();
-         iter != history_info_map_.end(); ++iter) {
+    for (const auto& entry : history_info_map_) {
       RowWordStarts word_starts;
-      const history::URLRow& row(iter->second.url_row);
+      const history::URLRow& row = entry.second.url_row;
       const base::string16& url =
           bookmarks::CleanUpUrlForMatching(row.url(), nullptr);
       String16VectorFromString16(url, false, &word_starts.url_word_starts_);
       const base::string16& title =
           bookmarks::CleanUpTitleForMatching(row.title());
       String16VectorFromString16(title, false, &word_starts.title_word_starts_);
-      word_starts_map_[iter->first] = word_starts;
+      word_starts_map_[entry.first] = std::move(word_starts);
     }
   }
   return true;
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index 4eb77e5..9054ba7 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <set>
+#include <stack>
 #include <string>
 
 #include "base/files/file_path.h"
@@ -205,9 +206,9 @@
 
   // URL History indexing support functions.
 
-  // Composes a set of history item IDs by intersecting the set for each word
+  // Composes a vector of history item IDs by intersecting the set for each word
   // in |unsorted_words|.
-  HistoryIDSet HistoryIDSetFromWords(const String16Vector& unsorted_words);
+  HistoryIDVector HistoryIDsFromWords(const String16Vector& unsorted_words);
 
   // Trims the candidate pool in advance of doing proper substring searching, to
   // cap the cost of such searching. Discards the least-relevant items (based on
@@ -215,7 +216,7 @@
   // minimize the risk of discarding a valuable URL, the candidate pool is still
   // left two orders of magnitude larger than the final number of results
   // returned from the HQP. Returns whether anything was trimmed.
-  bool TrimHistoryIdsPool(HistoryIDSet* history_id_set) const;
+  bool TrimHistoryIdsPool(HistoryIDVector* history_ids) const;
 
   // Helper function to HistoryIDSetFromWords which composes a set of history
   // ids for the given term given in |term|.
@@ -225,13 +226,12 @@
   WordIDSet WordIDSetForTermChars(const Char16Set& term_chars);
 
   // Helper function for HistoryItemsForTerms().  Fills in |scored_items| from
-  // the matches listed in |history_id_set|.
-  void HistoryIdSetToScoredMatches(
-      HistoryIDSet history_id_set,
-      const base::string16& lower_raw_string,
-      const TemplateURLService* template_url_service,
-      bookmarks::BookmarkModel* bookmark_model,
-      ScoredHistoryMatches* scored_items) const;
+  // the matches listed in |history_ids|.
+  void HistoryIdsToScoredMatches(HistoryIDVector history_ids,
+                                 const base::string16& lower_raw_string,
+                                 const TemplateURLService* template_url_service,
+                                 bookmarks::BookmarkModel* bookmark_model,
+                                 ScoredHistoryMatches* scored_items) const;
 
   // Fills in |terms_to_word_starts_offsets| according to where the word starts
   // in each term.  For example, in the term "-foo" the word starts at offset 1.
@@ -262,17 +262,9 @@
   // history item identified by |history_id| to the index.
   void AddWordToIndex(const base::string16& uni_word, HistoryID history_id);
 
-  // Creates a new entry in the word/history map for |word_id| and add
-  // |history_id| as the initial element of the word's set.
-  void AddWordHistory(const base::string16& uni_word, HistoryID history_id);
-
-  // Updates an existing entry in the word/history index by adding the
-  // |history_id| to set for |word_id| in the word_id_history_map_.
-  void UpdateWordHistory(WordID word_id, HistoryID history_id);
-
-  // Adds |word_id| to |history_id|'s entry in the history/word map,
-  // creating a new entry if one does not already exist.
-  void AddToHistoryIDWordMap(HistoryID history_id, WordID word_id);
+  // Adds a new entry to |word_list_|. Uses previously freed positions if
+  // available.
+  WordID AddNewWordToWordList(const base::string16& term);
 
   // Removes |row| and all associated words and characters from the index.
   void RemoveRowFromIndex(const history::URLRow& row);
@@ -353,9 +345,9 @@
   // the index, in which case any available words are used, if any, and then
   // words are added to the end of the word_list_. When URL visits are
   // modified or deleted old words may be removed from the index, in which
-  // case the slots for those words are added to available_words_ for resuse
+  // case the slots for those words are added to available_words_ for reuse
   // by future URL updates.
-  WordIDSet available_words_;
+  std::stack<WordID> available_words_;
 
   // A one-to-one mapping from the a word string to its slot number (i.e.
   // WordID) in the |word_list_|.
diff --git a/components/payments/payment_request.h b/components/payments/payment_request.h
index 0207c6b1..551d8ffe 100644
--- a/components/payments/payment_request.h
+++ b/components/payments/payment_request.h
@@ -100,6 +100,10 @@
   // card.
   autofill::CreditCard* selected_credit_card() { return selected_credit_card_; }
 
+  void set_selected_credit_card(autofill::CreditCard* credit_card) {
+    selected_credit_card_ = credit_card;
+  }
+
   autofill::PersonalDataManager* personal_data_manager() {
     return delegate_->GetPersonalDataManager();
   }
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn
index deab4a6..6608413 100644
--- a/components/tracing/BUILD.gn
+++ b/components/tracing/BUILD.gn
@@ -7,8 +7,6 @@
 
 component("tracing") {
   sources = [
-    "child/child_memory_dump_manager_delegate_impl.cc",
-    "child/child_memory_dump_manager_delegate_impl.h",
     "child/child_trace_message_filter.cc",
     "child/child_trace_message_filter.h",
     "common/graphics_memory_dump_provider_android.cc",
diff --git a/components/tracing/child/child_memory_dump_manager_delegate_impl.cc b/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
deleted file mode 100644
index f0c4517b..0000000
--- a/components/tracing/child/child_memory_dump_manager_delegate_impl.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h"
-
-#include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
-#include "components/tracing/child/child_trace_message_filter.h"
-#include "components/tracing/common/process_metrics_memory_dump_provider.h"
-
-namespace tracing {
-
-namespace {
-void AbortDumpRequest(const base::trace_event::MemoryDumpRequestArgs& args,
-                      const base::trace_event::MemoryDumpCallback& callback) {
-  if (!callback.is_null())
-    callback.Run(args.dump_guid, false /* success */);
-}
-}  // namespace
-
-// static
-ChildMemoryDumpManagerDelegateImpl*
-ChildMemoryDumpManagerDelegateImpl::GetInstance() {
-  return base::Singleton<
-      ChildMemoryDumpManagerDelegateImpl,
-      base::LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get();
-}
-
-ChildMemoryDumpManagerDelegateImpl::ChildMemoryDumpManagerDelegateImpl()
-    : ctmf_(nullptr),
-      tracing_process_id_(
-          base::trace_event::MemoryDumpManager::kInvalidTracingProcessId) {
-}
-
-ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {}
-
-void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter(
-    ChildTraceMessageFilter* ctmf) {
-  auto* task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
-  // Check that we are either registering the CTMF or tearing it down, but not
-  // replacing a valid instance with another one (should never happen).
-  DCHECK(!ctmf_ || (!ctmf && ctmf_task_runner_));
-  ctmf_ = ctmf;
-
-  {
-    base::AutoLock lock(lock_);
-    ctmf_task_runner_ = task_runner;
-  }
-
-  if (ctmf) {
-    base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
-      this /* delegate */, false /* is_coordinator */);
-
-#if !defined(OS_LINUX) && !defined(OS_NACL)
-    // On linux the browser process takes care of dumping process metrics.
-    // The child process is not allowed to do so due to BPF sandbox.
-    tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
-        base::kNullProcessId);
-#endif
-  }
-}
-
-// Invoked in child processes by the MemoryDumpManager.
-void ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::trace_event::MemoryDumpCallback& callback) {
-  // RequestGlobalMemoryDump can be called on any thread, cannot access
-  // ctmf_task_runner_ as it could be racy.
-  scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner;
-  {
-    base::AutoLock lock(lock_);
-    ctmf_task_runner = ctmf_task_runner_;
-  }
-
-  // Bail out if we receive a dump request from the manager before the
-  // ChildTraceMessageFilter has been initialized.
-  if (!ctmf_task_runner) {
-    VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
-            << " failed because child trace message filter hasn't been"
-            << " initialized";
-    return AbortDumpRequest(args, callback);
-  }
-
-  // Make sure we access |ctmf_| only on the thread where it lives to avoid
-  // races on shutdown.
-  if (!ctmf_task_runner->BelongsToCurrentThread()) {
-    const bool did_post_task = ctmf_task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(&ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump,
-                   base::Unretained(this), args, callback));
-    if (!did_post_task)
-      return AbortDumpRequest(args, callback);
-    return;
-  }
-
-  // The ChildTraceMessageFilter could have been destroyed while hopping on the
-  // right thread. If this is the case, bail out.
-  if (!ctmf_) {
-    VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
-            << " failed because child trace message filter was"
-            << " destroyed while switching threads";
-    return AbortDumpRequest(args, callback);
-  }
-
-  // Send the request up to the browser process' MessageDumpmanager.
-  ctmf_->SendGlobalMemoryDumpRequest(args, callback);
-}
-
-uint64_t ChildMemoryDumpManagerDelegateImpl::GetTracingProcessId() const {
-  return tracing_process_id_;
-}
-
-}  // namespace tracing
diff --git a/components/tracing/child/child_memory_dump_manager_delegate_impl.h b/components/tracing/child/child_memory_dump_manager_delegate_impl.h
deleted file mode 100644
index fc27d96..0000000
--- a/components/tracing/child/child_memory_dump_manager_delegate_impl.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
-#define COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
-
-#include "base/trace_event/memory_dump_manager.h"
-
-#include <stdint.h>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/singleton.h"
-#include "base/synchronization/lock.h"
-#include "components/tracing/tracing_export.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
-namespace tracing {
-
-class ChildTraceMessageFilter;
-
-// This class is a simple proxy class between the MemoryDumpManager and the
-// ChildTraceMessageFilter. It's only purpose is to adapt the lifetime of
-// CTMF to the demands of MDM, which expects the delegate to be thread-safe
-// and long lived. CTMF, instead, can be torn down during browser shutdown.
-// This class is registered as MDM delegate in child processes and handles
-// gracefully (and thread-safely) failures in the case of a lack of the CTMF.
-class TRACING_EXPORT ChildMemoryDumpManagerDelegateImpl
-    : public base::trace_event::MemoryDumpManagerDelegate {
- public:
-  static ChildMemoryDumpManagerDelegateImpl* GetInstance();
-
-  // base::trace_event::MemoryDumpManagerDelegate implementation.
-  void RequestGlobalMemoryDump(
-      const base::trace_event::MemoryDumpRequestArgs& args,
-      const base::trace_event::MemoryDumpCallback& callback) override;
-  uint64_t GetTracingProcessId() const override;
-
-  void SetChildTraceMessageFilter(ChildTraceMessageFilter* ctmf);
-
-  // Pass kInvalidTracingProcessId to invalidate the id.
-  void set_tracing_process_id(uint64_t id) {
-    DCHECK(tracing_process_id_ ==
-               base::trace_event::MemoryDumpManager::kInvalidTracingProcessId ||
-           id ==
-               base::trace_event::MemoryDumpManager::kInvalidTracingProcessId ||
-           id == tracing_process_id_);
-    tracing_process_id_ = id;
-  }
-
- protected:
-  // Make CreateProcessDump() visible to ChildTraceMessageFilter.
-  friend class ChildTraceMessageFilter;
-
- private:
-  friend struct base::DefaultSingletonTraits<
-      ChildMemoryDumpManagerDelegateImpl>;
-
-  ChildMemoryDumpManagerDelegateImpl();
-  ~ChildMemoryDumpManagerDelegateImpl() override;
-
-  ChildTraceMessageFilter* ctmf_;  // Not owned.
-
-  // The SingleThreadTaskRunner where the |ctmf_| lives.
-  // It is NULL iff |cmtf_| is NULL.
-  scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner_;
-
-  // Protects from concurrent access to |ctmf_task_runner_| to allow
-  // RequestGlobalMemoryDump to be called from arbitrary threads.
-  base::Lock lock_;
-
-  // The unique id of the child process, created for tracing and is expected to
-  // be valid only when tracing is enabled.
-  uint64_t tracing_process_id_;
-
-  DISALLOW_COPY_AND_ASSIGN(ChildMemoryDumpManagerDelegateImpl);
-};
-
-}  // namespace tracing
-
-#endif  // COMPONENTS_TRACING_CHILD_CHILD_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
diff --git a/components/tracing/child/child_trace_message_filter.cc b/components/tracing/child/child_trace_message_filter.cc
index ed2be875..6012a96a 100644
--- a/components/tracing/child/child_trace_message_filter.cc
+++ b/components/tracing/child/child_trace_message_filter.cc
@@ -8,11 +8,13 @@
 
 #include "base/memory/ref_counted_memory.h"
 #include "base/metrics/statistics_recorder.h"
+#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
-#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h"
+#include "components/tracing/common/process_metrics_memory_dump_provider.h"
 #include "components/tracing/common/tracing_messages.h"
 #include "ipc/ipc_channel.h"
 
+using base::trace_event::MemoryDumpManager;
 using base::trace_event::TraceLog;
 
 namespace tracing {
@@ -25,16 +27,18 @@
 
 ChildTraceMessageFilter::ChildTraceMessageFilter(
     base::SingleThreadTaskRunner* ipc_task_runner)
-    : sender_(NULL),
-      ipc_task_runner_(ipc_task_runner),
-      pending_memory_dump_guid_(0) {
-}
+    : sender_(NULL), ipc_task_runner_(ipc_task_runner) {}
 
 void ChildTraceMessageFilter::OnFilterAdded(IPC::Channel* channel) {
   sender_ = channel;
   sender_->Send(new TracingHostMsg_ChildSupportsTracing());
-  ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
-      this);
+
+#if !defined(OS_LINUX) && !defined(OS_NACL)
+  // On linux the browser process takes care of dumping process metrics.
+  // The child process is not allowed to do so due to BPF sandbox.
+  tracing::ProcessMetricsMemoryDumpProvider::RegisterForProcess(
+      base::kNullProcessId);
+#endif
 }
 
 void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) {
@@ -42,8 +46,6 @@
 }
 
 void ChildTraceMessageFilter::OnFilterRemoved() {
-  ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
-      nullptr);
   sender_ = NULL;
 }
 
@@ -54,10 +56,6 @@
     IPC_MESSAGE_HANDLER(TracingMsg_EndTracing, OnEndTracing)
     IPC_MESSAGE_HANDLER(TracingMsg_CancelTracing, OnCancelTracing)
     IPC_MESSAGE_HANDLER(TracingMsg_GetTraceLogStatus, OnGetTraceLogStatus)
-    IPC_MESSAGE_HANDLER(TracingMsg_ProcessMemoryDumpRequest,
-                        OnProcessMemoryDumpRequest)
-    IPC_MESSAGE_HANDLER(TracingMsg_GlobalMemoryDumpResponse,
-                        OnGlobalMemoryDumpResponse)
     IPC_MESSAGE_HANDLER(TracingMsg_SetUMACallback, OnSetUMACallback)
     IPC_MESSAGE_HANDLER(TracingMsg_ClearUMACallback, OnClearUMACallback)
     IPC_MESSAGE_UNHANDLED(handled = false)
@@ -78,8 +76,7 @@
   base::TimeDelta time_offset = base::TimeTicks::Now() - browser_time;
   TraceLog::GetInstance()->SetTimeOffset(time_offset);
 #endif
-  ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id(
-      tracing_process_id);
+  MemoryDumpManager::GetInstance()->set_tracing_process_id(tracing_process_id);
   TraceLog::GetInstance()->SetEnabled(
       base::trace_event::TraceConfig(trace_config_str),
       base::trace_event::TraceLog::RECORDING_MODE);
@@ -95,8 +92,8 @@
   TraceLog::GetInstance()->Flush(
       base::Bind(&ChildTraceMessageFilter::OnTraceDataCollected, this));
 
-  ChildMemoryDumpManagerDelegateImpl::GetInstance()->set_tracing_process_id(
-      base::trace_event::MemoryDumpManager::kInvalidTracingProcessId);
+  MemoryDumpManager::GetInstance()->set_tracing_process_id(
+      MemoryDumpManager::kInvalidTracingProcessId);
 }
 
 void ChildTraceMessageFilter::OnCancelTracing() {
@@ -129,52 +126,6 @@
   }
 }
 
-// Sent by the Browser's MemoryDumpManager when coordinating a global dump.
-void ChildTraceMessageFilter::OnProcessMemoryDumpRequest(
-    const base::trace_event::MemoryDumpRequestArgs& args) {
-  ChildMemoryDumpManagerDelegateImpl::GetInstance()->CreateProcessDump(
-      args,
-      base::Bind(&ChildTraceMessageFilter::OnProcessMemoryDumpDone, this));
-}
-
-void ChildTraceMessageFilter::OnProcessMemoryDumpDone(uint64_t dump_guid,
-                                                      bool success) {
-  sender_->Send(
-      new TracingHostMsg_ProcessMemoryDumpResponse(dump_guid, success));
-}
-
-// Initiates a dump request, asking the Browser's MemoryDumpManager to
-// coordinate a global memory dump. The Browser's MDM will answer back with a
-// MemoryDumpResponse when all the child processes (including this one) have
-// dumped, or with a NACK (|success| == false) if the dump failed (e.g., due to
-// a collision with a concurrent request from another child process).
-void ChildTraceMessageFilter::SendGlobalMemoryDumpRequest(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::trace_event::MemoryDumpCallback& callback) {
-  // If there is already another dump request pending from this child process,
-  // there is no point bothering the Browser's MemoryDumpManager.
-  if (pending_memory_dump_guid_) {
-    if (!callback.is_null())
-      callback.Run(args.dump_guid, false);
-    return;
-  }
-
-  pending_memory_dump_guid_ = args.dump_guid;
-  pending_memory_dump_callback_ = callback;
-  sender_->Send(new TracingHostMsg_GlobalMemoryDumpRequest(args));
-}
-
-// Sent by the Browser's MemoryDumpManager in response of a dump request
-// initiated by this child process.
-void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64_t dump_guid,
-                                                         bool success) {
-  DCHECK_NE(0U, pending_memory_dump_guid_);
-  pending_memory_dump_guid_ = 0;
-  if (pending_memory_dump_callback_.is_null())
-    return;
-  pending_memory_dump_callback_.Run(dump_guid, success);
-}
-
 void ChildTraceMessageFilter::OnHistogramChanged(
     const std::string& histogram_name,
     base::Histogram::Sample reference_lower_value,
diff --git a/components/tracing/child/child_trace_message_filter.h b/components/tracing/child/child_trace_message_filter.h
index 287abd35..619de78 100644
--- a/components/tracing/child/child_trace_message_filter.h
+++ b/components/tracing/child/child_trace_message_filter.h
@@ -12,7 +12,6 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
-#include "base/trace_event/memory_dump_request_args.h"
 #include "components/tracing/tracing_export.h"
 #include "ipc/message_filter.h"
 
@@ -33,10 +32,6 @@
   void OnFilterRemoved() override;
   bool OnMessageReceived(const IPC::Message& message) override;
 
-  void SendGlobalMemoryDumpRequest(
-      const base::trace_event::MemoryDumpRequestArgs& args,
-      const base::trace_event::MemoryDumpCallback& callback);
-
   base::SingleThreadTaskRunner* ipc_task_runner() const {
     return ipc_task_runner_;
   }
@@ -58,9 +53,6 @@
                        const std::string& event_name);
   void OnCancelWatchEvent();
   void OnWatchEventMatched();
-  void OnProcessMemoryDumpRequest(
-      const base::trace_event::MemoryDumpRequestArgs& args);
-  void OnGlobalMemoryDumpResponse(uint64_t dump_guid, bool success);
   void OnSetUMACallback(const std::string& histogram_name,
                         int histogram_lower_value,
                         int histogram_upper_value,
@@ -79,20 +71,11 @@
       const scoped_refptr<base::RefCountedString>& events_str_ptr,
       bool has_more_events);
 
-  void OnProcessMemoryDumpDone(uint64_t dump_guid, bool success);
-
   void SetSenderForTesting(IPC::Sender* sender);
 
   IPC::Sender* sender_;
   base::SingleThreadTaskRunner* ipc_task_runner_;
 
-  // guid of the outstanding request (to the Browser's MemoryDumpManager), if
-  // any. 0 if there is no request pending.
-  uint64_t pending_memory_dump_guid_;
-
-  // callback of the outstanding memory dump request, if any.
-  base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
-
   base::Time histogram_last_changed_;
 
   DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter);
diff --git a/components/tracing/child/child_trace_message_filter_browsertest.cc b/components/tracing/child/child_trace_message_filter_browsertest.cc
deleted file mode 100644
index d0d2d020..0000000
--- a/components/tracing/child/child_trace_message_filter_browsertest.cc
+++ /dev/null
@@ -1,326 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stdint.h>
-
-#include <memory>
-#include <tuple>
-
-#include "base/callback.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/memory_dump_manager.h"
-#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/trace_event.h"
-#include "components/tracing/child/child_memory_dump_manager_delegate_impl.h"
-#include "components/tracing/child/child_trace_message_filter.h"
-#include "components/tracing/common/tracing_messages.h"
-#include "content/public/test/render_view_test.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-using base::trace_event::MemoryDumpManager;
-using base::trace_event::MemoryDumpRequestArgs;
-using base::trace_event::MemoryDumpArgs;
-using base::trace_event::MemoryDumpLevelOfDetail;
-using base::trace_event::MemoryDumpType;
-using testing::_;
-using testing::Return;
-
-namespace tracing {
-
-// A mock dump provider, used to check that dump requests actually end up
-// creating memory dumps.
-class MockDumpProvider : public base::trace_event::MemoryDumpProvider {
- public:
-  MOCK_METHOD2(OnMemoryDump,
-               bool(const MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd));
-};
-
-class ChildTracingTest : public content::RenderViewTest, public IPC::Listener {
- public:
-  // Used as callback argument for MemoryDumpManager::RequestGlobalDump():
-  void OnMemoryDumpCallback(uint64_t dump_guid, bool status) {
-    last_callback_dump_guid_ = dump_guid;
-    last_callback_status_ = status;
-    ++callback_call_count_;
-  }
-
- protected:
-  void SetUp() override {
-    // RenderViewTest::SetUp causes additional registrations, so we first
-    // register the mock dump provider and ignore registrations from then on.
-    // In addition to the mock dump provider, the TraceLog has already
-    // registered itself by now; this cannot be prevented easily.
-    mock_dump_provider_.reset(new MockDumpProvider());
-    MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-        mock_dump_provider_.get(), "MockDumpProvider",
-        base::ThreadTaskRunnerHandle::Get());
-    MemoryDumpManager::GetInstance()
-        ->set_dumper_registrations_ignored_for_testing(true);
-
-    RenderViewTest::SetUp();
-
-    callback_call_count_ = 0;
-    last_callback_dump_guid_ = 0;
-    last_callback_status_ = false;
-    wait_for_ipc_message_type_ = 0;
-    callback_ = base::Bind(&ChildTracingTest::OnMemoryDumpCallback,
-                           base::Unretained(this));
-    task_runner_ = base::ThreadTaskRunnerHandle::Get();
-    ctmf_ = make_scoped_refptr(new ChildTraceMessageFilter(task_runner_.get()));
-    render_thread_->AddFilter(ctmf_.get());
-
-    // Add a filter to the TestSink which allows to WaitForIPCMessage() by
-    // posting a nested RunLoop closure when a given IPC Message is seen.
-    render_thread_->sink().AddFilter(this);
-
-    // Getting an instance of |ChildMemoryDumpManagerDelegateImpl| calls
-    // |MemoryDumpManager::Initialize| with the correct delegate.
-    ChildMemoryDumpManagerDelegateImpl::GetInstance();
-  }
-
-  void TearDown() override {
-    render_thread_->sink().RemoveFilter(this);
-    RenderViewTest::TearDown();
-    MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-        mock_dump_provider_.get());
-    mock_dump_provider_.reset();
-    ctmf_ = nullptr;
-    task_runner_ = nullptr;
-  }
-
-  // IPC::Filter implementation.
-  bool OnMessageReceived(const IPC::Message& message) override {
-    if (message.type() == wait_for_ipc_message_type_) {
-      DCHECK(!wait_for_ipc_closure_.is_null());
-      task_runner_->PostTask(FROM_HERE, wait_for_ipc_closure_);
-    }
-    // Always propagate messages to the sink, never consume them here.
-    return false;
-  }
-
-  const IPC::Message* WaitForIPCMessage(uint32_t message_type) {
-    base::RunLoop run_loop;
-    wait_for_ipc_message_type_ = message_type;
-    wait_for_ipc_closure_ = run_loop.QuitClosure();
-    run_loop.Run();
-    wait_for_ipc_message_type_ = 0;
-    wait_for_ipc_closure_.Reset();
-    return render_thread_->sink().GetUniqueMessageMatching(message_type);
-  }
-
-  // Simulates a synthetic browser -> child (this process) IPC message.
-  void SimulateSyntheticMessageFromBrowser(const IPC::Message& msg) {
-    ctmf_->OnMessageReceived(msg);
-  }
-
-  void EnableTracingWithMemoryDumps() {
-    // Re-enabling tracing could crash these tests https://crbug.com/656729 .
-    if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) {
-      FAIL() << "Tracing seems to be already enabled. "
-                "Very likely this is because the startup tracing file "
-                "has been leaked from a previous test.";
-    }
-
-    std::string category_filter = "-*,";  // Disable all other trace categories.
-    category_filter += MemoryDumpManager::kTraceCategory;
-    base::trace_event::TraceConfig trace_config(category_filter, "");
-    TracingMsg_BeginTracing msg(trace_config.ToString(), base::TimeTicks(), 0);
-    SimulateSyntheticMessageFromBrowser(msg);
-  }
-
-  void DisableTracing() {
-    SimulateSyntheticMessageFromBrowser(TracingMsg_EndTracing());
-  }
-
-  // Simulates a synthetic browser -> child process memory dump request and
-  // checks that the child actually sends a response to that.
-  void RequestProcessMemoryDumpAndCheckResponse(uint64_t dump_guid) {
-    SimulateSyntheticMessageFromBrowser(TracingMsg_ProcessMemoryDumpRequest(
-        {dump_guid, MemoryDumpType::EXPLICITLY_TRIGGERED,
-         MemoryDumpLevelOfDetail::DETAILED}));
-
-    // Check that a child -> browser response to the local dump request is sent.
-    const IPC::Message* msg =
-        WaitForIPCMessage(TracingHostMsg_ProcessMemoryDumpResponse::ID);
-    EXPECT_NE(nullptr, msg);
-
-    // Check that the |dump_guid| and the |success| fields are properly set.
-    TracingHostMsg_ProcessMemoryDumpResponse::Param params;
-    TracingHostMsg_ProcessMemoryDumpResponse::Read(msg, &params);
-    const uint64_t resp_guid = std::get<0>(params);
-    const bool resp_success = std::get<1>(params);
-    EXPECT_EQ(dump_guid, resp_guid);
-    EXPECT_TRUE(resp_success);
-  }
-
-  // Retrieves the MemoryDumpRequestArgs of the global memory dump request that
-  // this child process tried to send to the browser. Fails if either none or
-  // multiple requests were sent.
-  MemoryDumpRequestArgs GetInterceptedGlobalMemoryDumpRequest() {
-    const IPC::Message* msg = render_thread_->sink().GetUniqueMessageMatching(
-        TracingHostMsg_GlobalMemoryDumpRequest::ID);
-    EXPECT_NE(nullptr, msg);
-    TracingHostMsg_GlobalMemoryDumpRequest::Param params;
-    TracingHostMsg_GlobalMemoryDumpRequest::Read(msg, &params);
-    MemoryDumpRequestArgs args = std::get<0>(params);
-    EXPECT_NE(0U, args.dump_guid);
-    return args;
-  }
-
-  scoped_refptr<ChildTraceMessageFilter> ctmf_;
-  std::unique_ptr<MockDumpProvider> mock_dump_provider_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  base::trace_event::MemoryDumpCallback callback_;
-  uint32_t wait_for_ipc_message_type_;
-  base::Closure wait_for_ipc_closure_;
-  uint32_t callback_call_count_;
-  uint64_t last_callback_dump_guid_;
-  bool last_callback_status_;
-};
-
-// Covers the case of some browser-initiated memory dumps.
-#if defined(OS_ANDROID)
-// Flaky on Android. http://crbug.com/620734.
-#define MAYBE_BrowserInitiatedMemoryDumps DISABLED_BrowserInitiatedMemoryDumps
-#else
-#define MAYBE_BrowserInitiatedMemoryDumps BrowserInitiatedMemoryDumps
-#endif
-TEST_F(ChildTracingTest, MAYBE_BrowserInitiatedMemoryDumps) {
-  const uint32_t kNumDumps = 3;
-
-  EnableTracingWithMemoryDumps();
-  EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
-      .Times(kNumDumps)
-      .WillRepeatedly(Return(true));
-
-  for (uint32_t i = 0; i < kNumDumps; ++i) {
-    render_thread_->sink().ClearMessages();
-    RequestProcessMemoryDumpAndCheckResponse(i + 1);
-  }
-
-  DisableTracing();
-}
-
-// Covers the case of one simple child-initiated memory dump without callback,
-// simulating a global memory dump request to the browser (+ response).
-TEST_F(ChildTracingTest, SingleChildInitiatedMemoryDump) {
-  EnableTracingWithMemoryDumps();
-
-  // Expect that our mock dump provider is called when the emulated memory dump
-  // request (browser -> child) is sent.
-  EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
-      .Times(1)
-      .WillRepeatedly(Return(true));
-
-  // Send the global memory dump request to the browser.
-  render_thread_->sink().ClearMessages();
-  MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED);
-  base::RunLoop().RunUntilIdle();
-
-  // Check that the child -> browser global dump request IPC is actually sent.
-  MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
-  EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type);
-
-  // Emulate a browser -> child process dump request and corresponding response.
-  RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
-  // Send a synthetic browser -> child global memory dump response.
-  SimulateSyntheticMessageFromBrowser(
-      TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true));
-
-  DisableTracing();
-}
-
-// Covers the case of a global memory dump being requested while another one is
-// in progress and has not been acknowledged by the browser. The second request
-// is expected to fail immediately, while the first one is expected to suceed.
-TEST_F(ChildTracingTest, OverlappingChildInitiatedMemoryDumps) {
-  EnableTracingWithMemoryDumps();
-
-  // Expect that our mock dump provider is called only once.
-  EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
-      .Times(1)
-      .WillRepeatedly(Return(true));
-
-  // Send the global memory dump request to the browser.
-  render_thread_->sink().ClearMessages();
-  MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
-      callback_);
-  base::RunLoop().RunUntilIdle();
-
-  // Check that the child -> browser global dump request IPC is actually sent.
-  MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
-  EXPECT_EQ(MemoryDumpType::EXPLICITLY_TRIGGERED, args.dump_type);
-
-  // Emulate a browser -> child process dump request and corresponding response.
-  RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
-  // Before the response for the first global dump is sent, send another one,
-  // and expect that to fail.
-  render_thread_->sink().ClearMessages();
-  MemoryDumpManager::GetInstance()->RequestGlobalDump(
-      MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::DETAILED,
-      callback_);
-  base::RunLoop().RunUntilIdle();
-
-  EXPECT_EQ(1u, callback_call_count_);
-  EXPECT_FALSE(last_callback_status_);
-  // Whatever the guid of the second failing request is, it cannot possibly be
-  // equal to the guid of the first request.
-  EXPECT_NE(args.dump_guid, last_callback_dump_guid_);
-
-  // Also, check that no request has been forwarded to the browser (because the
-  // first request is still outstanding and has not received any response yet).
-  EXPECT_EQ(nullptr, render_thread_->sink().GetUniqueMessageMatching(
-                         TracingHostMsg_GlobalMemoryDumpRequest::ID));
-
-  // Now send a synthetic browser -> child response to the first request.
-  SimulateSyntheticMessageFromBrowser(
-      TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, true));
-
-  // Verify that the the callback for the first request is finally called.
-  EXPECT_EQ(2u, callback_call_count_);
-  EXPECT_EQ(args.dump_guid, last_callback_dump_guid_);
-  EXPECT_TRUE(last_callback_status_);
-
-  DisableTracing();
-}
-
-// Covers the case of five child-initiated global memory dumps. Each global dump
-// request has a callback, which is expected to fail for 3 out of 5 cases.
-TEST_F(ChildTracingTest, MultipleChildInitiatedMemoryDumpWithFailures) {
-  const uint32_t kNumRequests = 5;
-  MemoryDumpType kDumpType = MemoryDumpType::EXPLICITLY_TRIGGERED;
-
-  EnableTracingWithMemoryDumps();
-  EXPECT_CALL(*mock_dump_provider_, OnMemoryDump(_, _))
-      .Times(kNumRequests)
-      .WillRepeatedly(Return(true));
-
-  for (uint32_t i = 0; i < kNumRequests; ++i) {
-    render_thread_->sink().ClearMessages();
-    MemoryDumpManager::GetInstance()->RequestGlobalDump(
-        kDumpType, MemoryDumpLevelOfDetail::DETAILED, callback_);
-    base::RunLoop().RunUntilIdle();
-
-    MemoryDumpRequestArgs args = GetInterceptedGlobalMemoryDumpRequest();
-    EXPECT_EQ(kDumpType, args.dump_type);
-    RequestProcessMemoryDumpAndCheckResponse(args.dump_guid);
-
-    const bool success = (i & 1) ? true : false;
-    SimulateSyntheticMessageFromBrowser(
-        TracingMsg_GlobalMemoryDumpResponse(args.dump_guid, success));
-    EXPECT_EQ(i + 1, callback_call_count_);
-    EXPECT_EQ(args.dump_guid, last_callback_dump_guid_);
-    EXPECT_EQ(success, last_callback_status_);
-  }
-
-  DisableTracing();
-}
-
-}  // namespace tracing
diff --git a/components/translate/ios/browser/language_detection_controller.h b/components/translate/ios/browser/language_detection_controller.h
index 72a3d5bc..c3271e82 100644
--- a/components/translate/ios/browser/language_detection_controller.h
+++ b/components/translate/ios/browser/language_detection_controller.h
@@ -25,6 +25,7 @@
 }
 
 namespace web {
+class NavigationContext;
 class WebState;
 }
 
@@ -78,8 +79,7 @@
   // web::WebStateObserver implementation:
   void PageLoaded(
       web::PageLoadCompletionStatus load_completion_status) override;
-  void UrlHashChanged() override;
-  void HistoryStateChanged() override;
+  void DidFinishNavigation(web::NavigationContext* navigation_context) override;
   void WebStateDestroyed() override;
 
   CallbackList language_detection_callbacks_;
diff --git a/components/translate/ios/browser/language_detection_controller.mm b/components/translate/ios/browser/language_detection_controller.mm
index 4292261..53fda593 100644
--- a/components/translate/ios/browser/language_detection_controller.mm
+++ b/components/translate/ios/browser/language_detection_controller.mm
@@ -16,6 +16,7 @@
 #import "components/translate/ios/browser/js_language_detection_manager.h"
 #include "components/translate/ios/browser/string_clipping_util.h"
 #import "ios/web/public/url_scheme_util.h"
+#include "ios/web/public/web_state/navigation_context.h"
 #include "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -137,12 +138,10 @@
     StartLanguageDetection();
 }
 
-void LanguageDetectionController::UrlHashChanged() {
-  StartLanguageDetection();
-}
-
-void LanguageDetectionController::HistoryStateChanged() {
-  StartLanguageDetection();
+void LanguageDetectionController::DidFinishNavigation(
+    web::NavigationContext* navigation_context) {
+  if (navigation_context->IsSamePage())
+    StartLanguageDetection();
 }
 
 void LanguageDetectionController::WebStateDestroyed() {
diff --git a/content/browser/browser_main.cc b/content/browser/browser_main.cc
index 772010c..5625a020 100644
--- a/content/browser/browser_main.cc
+++ b/content/browser/browser_main.cc
@@ -6,7 +6,9 @@
 
 #include <memory>
 
+#include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
+#include "content/common/child_process_host_impl.h"
 #include "content/common/content_constants_internal.h"
 #include "content/public/browser/browser_main_runner.h"
 
@@ -36,7 +38,8 @@
   base::trace_event::TraceLog::GetInstance()->SetProcessName("Browser");
   base::trace_event::TraceLog::GetInstance()->SetProcessSortIndex(
       kTraceEventBrowserProcessSortIndex);
-
+  base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id(
+      ChildProcessHost::kBrowserTracingProcessId);
   std::unique_ptr<BrowserMainRunner> main_runner(BrowserMainRunner::Create());
 
   int exit_code = main_runner->Initialize(parameters);
diff --git a/content/browser/tracing/memory_tracing_browsertest.cc b/content/browser/tracing/memory_tracing_browsertest.cc
index fe96666..3ef05bfd 100644
--- a/content/browser/tracing/memory_tracing_browsertest.cc
+++ b/content/browser/tracing/memory_tracing_browsertest.cc
@@ -20,6 +20,7 @@
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
+#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using base::trace_event::MemoryDumpArgs;
@@ -122,6 +123,9 @@
             GetTraceConfig_EmptyTriggers());
 
     base::RunLoop run_loop;
+    // Start the Coordinator service.
+    memory_instrumentation::CoordinatorImpl::GetInstance(
+        base::ThreadTaskRunnerHandle::Get().get());
     bool success = TracingController::GetInstance()->StartTracing(
       trace_config, run_loop.QuitClosure());
     EXPECT_TRUE(success);
diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc
index 70089d9..a0e97d1b3 100644
--- a/content/browser/tracing/trace_message_filter.cc
+++ b/content/browser/tracing/trace_message_filter.cc
@@ -46,10 +46,6 @@
                         OnTraceDataCollected)
     IPC_MESSAGE_HANDLER(TracingHostMsg_TraceLogStatusReply,
                         OnTraceLogStatusReply)
-    IPC_MESSAGE_HANDLER(TracingHostMsg_GlobalMemoryDumpRequest,
-                        OnGlobalMemoryDumpRequest)
-    IPC_MESSAGE_HANDLER(TracingHostMsg_ProcessMemoryDumpResponse,
-                        OnProcessMemoryDumpResponse)
     IPC_MESSAGE_HANDLER(TracingHostMsg_TriggerBackgroundTrace,
                         OnTriggerBackgroundTrace)
     IPC_MESSAGE_HANDLER(TracingHostMsg_AbortBackgroundTrace,
@@ -87,18 +83,6 @@
   Send(new TracingMsg_GetTraceLogStatus);
 }
 
-// Called by TracingControllerImpl, which handles the multiprocess coordination.
-void TraceMessageFilter::SendProcessMemoryDumpRequest(
-    const base::trace_event::MemoryDumpRequestArgs& args) {
-  Send(new TracingMsg_ProcessMemoryDumpRequest(args));
-}
-
-// Called by TracingControllerImpl, which handles the multiprocess coordination.
-void TraceMessageFilter::SendGlobalMemoryDumpResponse(uint64_t dump_guid,
-                                                      bool success) {
-  Send(new TracingMsg_GlobalMemoryDumpResponse(dump_guid, success));
-}
-
 void TraceMessageFilter::OnChildSupportsTracing() {
   has_child_ = true;
   TracingControllerImpl::GetInstance()->AddTraceMessageFilter(this);
@@ -133,19 +117,6 @@
   }
 }
 
-void TraceMessageFilter::OnGlobalMemoryDumpRequest(
-    const base::trace_event::MemoryDumpRequestArgs& args) {
-  TracingControllerImpl::GetInstance()->RequestGlobalMemoryDump(
-      args,
-      base::Bind(&TraceMessageFilter::SendGlobalMemoryDumpResponse, this));
-}
-
-void TraceMessageFilter::OnProcessMemoryDumpResponse(uint64_t dump_guid,
-                                                     bool success) {
-  TracingControllerImpl::GetInstance()->OnProcessMemoryDumpResponse(
-      this, dump_guid, success);
-}
-
 void TraceMessageFilter::OnTriggerBackgroundTrace(const std::string& name) {
   BackgroundTracingManagerImpl::GetInstance()->OnHistogramTrigger(name);
 }
diff --git a/content/browser/tracing/trace_message_filter.h b/content/browser/tracing/trace_message_filter.h
index 94c435e..97ae0a2 100644
--- a/content/browser/tracing/trace_message_filter.h
+++ b/content/browser/tracing/trace_message_filter.h
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/trace_event.h"
 #include "content/public/browser/browser_message_filter.h"
 
@@ -36,8 +35,6 @@
   void SendSetWatchEvent(const std::string& category_name,
                          const std::string& event_name);
   void SendCancelWatchEvent();
-  void SendProcessMemoryDumpRequest(
-      const base::trace_event::MemoryDumpRequestArgs& args);
 
  protected:
   ~TraceMessageFilter() override;
@@ -49,11 +46,6 @@
   void OnWatchEventMatched();
   void OnTraceLogStatusReply(const base::trace_event::TraceLogStatus& status);
   void OnTraceDataCollected(const std::string& data);
-  void OnGlobalMemoryDumpRequest(
-      const base::trace_event::MemoryDumpRequestArgs& args);
-  void OnProcessMemoryDumpResponse(uint64_t dump_guid, bool success);
-
-  void SendGlobalMemoryDumpResponse(uint64_t dump_guid, bool success);
   void OnTriggerBackgroundTrace(const std::string& histogram_name);
   void OnAbortBackgroundTrace();
 
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 5fc480346..54d1455 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -193,13 +193,8 @@
       pending_trace_log_status_ack_count_(0),
       maximum_trace_buffer_usage_(0),
       approximate_event_count_(0),
-      pending_memory_dump_ack_count_(0),
-      failed_memory_dump_count_(0),
       pending_clock_sync_ack_count_(0),
       is_tracing_(false) {
-  base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
-      this /* delegate */, true /* is_coordinator */);
-
   // Deliberately leaked, like this class.
   base::FileTracing::SetProvider(new FileTracingProviderImpl);
 }
@@ -536,20 +531,6 @@
                      base::trace_event::TraceLogStatus()));
     }
   }
-  if (pending_memory_dump_ack_count_ > 0) {
-    DCHECK(!queued_memory_dump_requests_.empty());
-    TraceMessageFilterSet::const_iterator it =
-        pending_memory_dump_filters_.find(trace_message_filter);
-    if (it != pending_memory_dump_filters_.end()) {
-      BrowserThread::PostTask(
-          BrowserThread::UI, FROM_HERE,
-          base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
-                     base::Unretained(this),
-                     base::RetainedRef(trace_message_filter),
-                     queued_memory_dump_requests_.front().args.dump_guid,
-                     false /* success */));
-    }
-  }
   trace_message_filters_.erase(trace_message_filter);
 }
 
@@ -896,87 +877,6 @@
   sink->AddMetadata(std::move(filtered_metadata));
 }
 
-void TracingControllerImpl::RequestGlobalMemoryDump(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::trace_event::MemoryDumpCallback& callback) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&TracingControllerImpl::RequestGlobalMemoryDump,
-                   base::Unretained(this), args, callback));
-    return;
-  }
-
-  bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
-
-  // If this is a periodic memory dump request and there already is another
-  // request in the queue with the same level of detail, there's no point in
-  // enqueuing this request.
-  if (another_dump_already_in_progress &&
-      args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) {
-    for (const auto& request : queued_memory_dump_requests_) {
-      if (request.args.level_of_detail == args.level_of_detail) {
-        VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " ("
-                << base::trace_event::MemoryDumpTypeToString(args.dump_type)
-                << ") skipped because another dump request with the same "
-                   "level of detail ("
-                << base::trace_event::MemoryDumpLevelOfDetailToString(
-                       args.level_of_detail)
-                << ") is already in the queue";
-        if (!callback.is_null())
-          callback.Run(args.dump_guid, false /* success */);
-        return;
-      }
-    }
-  }
-
-  queued_memory_dump_requests_.emplace_back(args, callback);
-
-  // If another dump is already in progress, this dump will automatically be
-  // scheduled when the other dump finishes.
-  if (another_dump_already_in_progress)
-    return;
-
-  PerformNextQueuedGlobalMemoryDump();
-}
-
-void TracingControllerImpl::PerformNextQueuedGlobalMemoryDump() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK(!queued_memory_dump_requests_.empty());
-  const base::trace_event::MemoryDumpRequestArgs& args =
-      queued_memory_dump_requests_.front().args;
-
-  // Count myself (local trace) in pending_memory_dump_ack_count_, acked by
-  // OnBrowserProcessMemoryDumpDone().
-  pending_memory_dump_ack_count_ = trace_message_filters_.size() + 1;
-  pending_memory_dump_filters_.clear();
-  failed_memory_dump_count_ = 0;
-
-  MemoryDumpManagerDelegate::CreateProcessDump(
-      args, base::Bind(&TracingControllerImpl::OnBrowserProcessMemoryDumpDone,
-                       base::Unretained(this)));
-
-  // If there are no child processes we are just done.
-  if (pending_memory_dump_ack_count_ == 1)
-    return;
-
-  pending_memory_dump_filters_ = trace_message_filters_;
-
-  for (const scoped_refptr<TraceMessageFilter>& tmf : trace_message_filters_)
-    tmf->SendProcessMemoryDumpRequest(args);
-}
-
-TracingControllerImpl::QueuedMemoryDumpRequest::QueuedMemoryDumpRequest(
-    const base::trace_event::MemoryDumpRequestArgs& args,
-    const base::trace_event::MemoryDumpCallback& callback)
-    : args(args), callback(callback) {}
-
-TracingControllerImpl::QueuedMemoryDumpRequest::~QueuedMemoryDumpRequest() {}
-
-uint64_t TracingControllerImpl::GetTracingProcessId() const {
-  return ChildProcessHost::kBrowserTracingProcessId;
-}
-
 void TracingControllerImpl::AddTraceMessageFilterObserver(
     TraceMessageFilterObserver* observer) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -995,76 +895,4 @@
     observer->OnTraceMessageFilterRemoved(filter.get());
 }
 
-void TracingControllerImpl::OnProcessMemoryDumpResponse(
-    TraceMessageFilter* trace_message_filter,
-    uint64_t dump_guid,
-    bool success) {
-  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&TracingControllerImpl::OnProcessMemoryDumpResponse,
-                   base::Unretained(this),
-                   base::RetainedRef(trace_message_filter), dump_guid,
-                   success));
-    return;
-  }
-
-  TraceMessageFilterSet::iterator it =
-      pending_memory_dump_filters_.find(trace_message_filter);
-
-  DCHECK(!queued_memory_dump_requests_.empty());
-  if (queued_memory_dump_requests_.front().args.dump_guid != dump_guid ||
-      it == pending_memory_dump_filters_.end()) {
-    DLOG(WARNING) << "Received unexpected memory dump response: " << dump_guid;
-    return;
-  }
-
-  DCHECK_GT(pending_memory_dump_ack_count_, 0);
-  --pending_memory_dump_ack_count_;
-  pending_memory_dump_filters_.erase(it);
-  if (!success) {
-    ++failed_memory_dump_count_;
-    VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
-            << " failed because of NACK from child "
-            << trace_message_filter->peer_pid();
-  }
-  FinalizeGlobalMemoryDumpIfAllProcessesReplied();
-}
-
-void TracingControllerImpl::OnBrowserProcessMemoryDumpDone(uint64_t dump_guid,
-                                                           bool success) {
-  DCHECK_GT(pending_memory_dump_ack_count_, 0);
-  --pending_memory_dump_ack_count_;
-  if (!success) {
-    ++failed_memory_dump_count_;
-    VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix
-            << " aborted on the current process";
-  }
-  FinalizeGlobalMemoryDumpIfAllProcessesReplied();
-}
-
-void TracingControllerImpl::FinalizeGlobalMemoryDumpIfAllProcessesReplied() {
-  if (pending_memory_dump_ack_count_ > 0)
-    return;
-
-  DCHECK(!queued_memory_dump_requests_.empty());
-  {
-    const auto& callback = queued_memory_dump_requests_.front().callback;
-    if (!callback.is_null()) {
-      const bool global_success = failed_memory_dump_count_ == 0;
-      callback.Run(queued_memory_dump_requests_.front().args.dump_guid,
-                   global_success);
-    }
-  }
-  queued_memory_dump_requests_.pop_front();
-
-  // Schedule the next queued dump (if applicable).
-  if (!queued_memory_dump_requests_.empty()) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::Bind(&TracingControllerImpl::PerformNextQueuedGlobalMemoryDump,
-                   base::Unretained(this)));
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h
index 0c7b8ea7..81ce092 100644
--- a/content/browser/tracing/tracing_controller_impl.h
+++ b/content/browser/tracing/tracing_controller_impl.h
@@ -47,7 +47,6 @@
 
 class TracingControllerImpl
     : public TracingController,
-      public base::trace_event::MemoryDumpManagerDelegate,
       public base::trace_event::TracingAgent {
  public:
   // Create an endpoint that may be supplied to any TraceDataSink to
@@ -88,12 +87,6 @@
       const std::string& sync_id,
       const RecordClockSyncMarkerCallback& callback) override;
 
-  // base::trace_event::MemoryDumpManagerDelegate implementation.
-  void RequestGlobalMemoryDump(
-      const base::trace_event::MemoryDumpRequestArgs& args,
-      const base::trace_event::MemoryDumpCallback& callback) override;
-  uint64_t GetTracingProcessId() const override;
-
   class TraceMessageFilterObserver {
    public:
     virtual void OnTraceMessageFilterAdded(TraceMessageFilter* filter) = 0;
@@ -106,16 +99,6 @@
   friend struct base::DefaultLazyInstanceTraits<TracingControllerImpl>;
   friend class TraceMessageFilter;
 
-  // The arguments and callback for an queued global memory dump request.
-  struct QueuedMemoryDumpRequest {
-    QueuedMemoryDumpRequest(
-        const base::trace_event::MemoryDumpRequestArgs& args,
-        const base::trace_event::MemoryDumpCallback& callback);
-    ~QueuedMemoryDumpRequest();
-    const base::trace_event::MemoryDumpRequestArgs args;
-    const base::trace_event::MemoryDumpCallback callback;
-  };
-
   TracingControllerImpl();
   ~TracingControllerImpl() override;
 
@@ -139,8 +122,6 @@
     return pending_trace_buffer_usage_callback_.is_null();
   }
 
-  void PerformNextQueuedGlobalMemoryDump();
-
   // Methods for use by TraceMessageFilter.
   void AddTraceMessageFilter(TraceMessageFilter* trace_message_filter);
   void RemoveTraceMessageFilter(TraceMessageFilter* trace_message_filter);
@@ -170,14 +151,6 @@
 
   void OnTraceLogStatusReply(TraceMessageFilter* trace_message_filter,
                              const base::trace_event::TraceLogStatus& status);
-  void OnProcessMemoryDumpResponse(TraceMessageFilter* trace_message_filter,
-                                   uint64_t dump_guid,
-                                   bool success);
-
-  // Callback of MemoryDumpManager::CreateProcessDump().
-  void OnBrowserProcessMemoryDumpDone(uint64_t dump_guid, bool success);
-
-  void FinalizeGlobalMemoryDumpIfAllProcessesReplied();
 
   void SetEnabledOnFileThread(
       const base::trace_event::TraceConfig& trace_config,
@@ -218,12 +191,6 @@
   float maximum_trace_buffer_usage_;
   size_t approximate_event_count_;
 
-  // Pending acks for memory RequestGlobalDumpPoint.
-  int pending_memory_dump_ack_count_;
-  int failed_memory_dump_count_;
-  TraceMessageFilterSet pending_memory_dump_filters_;
-  std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_;
-
   std::vector<base::trace_event::TracingAgent*> additional_tracing_agents_;
   int pending_clock_sync_ack_count_;
   base::OneShotTimer clock_sync_timer_;
diff --git a/content/child/BUILD.gn b/content/child/BUILD.gn
index da0aba5..4eb0e6b6 100644
--- a/content/child/BUILD.gn
+++ b/content/child/BUILD.gn
@@ -240,6 +240,7 @@
     "//net",
     "//services/device/public/cpp/power_monitor",
     "//services/device/public/interfaces:constants",
+    "//services/resource_coordinator/public/cpp",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/interfaces",
     "//services/service_manager/runner/common",
diff --git a/content/child/DEPS b/content/child/DEPS
index 3f315c9..3a07c1cb 100644
--- a/content/child/DEPS
+++ b/content/child/DEPS
@@ -11,6 +11,7 @@
   "+content/public/child",
   "+services/device/public/cpp/power_monitor",
   "+services/device/public/interfaces",
+  "+services/resource_coordinator",
   "+services/service_manager",
   "+services/service_manager",
   "+v8/include/v8.h"
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 0e42540..135a424 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -66,6 +66,7 @@
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h"
 #include "services/device/public/interfaces/constants.mojom.h"
+#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
@@ -502,6 +503,10 @@
     channel_->AddFilter(new tracing::ChildTraceMessageFilter(
         ChildProcess::current()->io_task_runner()));
     channel_->AddFilter(new ChildMemoryMessageFilter());
+
+    memory_instrumentation::MemoryDumpManagerDelegateImpl* delegate =
+        memory_instrumentation::MemoryDumpManagerDelegateImpl::GetInstance();
+    delegate->InitializeWithInterfaceProvider(GetRemoteInterfaces());
   }
 
   // In single process mode we may already have a power monitor,
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 5628eb4..89024675 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -4,6 +4,9 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
+        "gpu": [
+          "memory_instrumentation::mojom::Coordinator"
+        ],
         "plugin": [
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
           "ui::mojom::Gpu"
@@ -34,6 +37,7 @@
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
           "media::mojom::ImageCapture",
           "memory_coordinator::mojom::MemoryCoordinatorHandle",
+          "memory_instrumentation::mojom::Coordinator",
           "payments::mojom::PaymentAppManager",
           "shape_detection::mojom::BarcodeDetection",
           "shape_detection::mojom::FaceDetectionProvider",
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.cc b/content/renderer/media/media_stream_constraints_util_video_device.cc
index 3e2f3e80..84d415f 100644
--- a/content/renderer/media/media_stream_constraints_util_video_device.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_device.cc
@@ -21,8 +21,8 @@
 
 // Number of default settings to be used as final tie-breaking criteria for
 // settings that are equally good at satisfying constraints:
-// device ID, power-line frequency, resolution and frame rate.
-const int kNumDefaultDistanceEntries = 4;
+// device ID, power-line frequency, noise reduction, resolution and frame rate.
+const int kNumDefaultDistanceEntries = 5;
 
 // The default resolution to be preferred as tie-breaking criterion.
 const int kDefaultResolutionArea = MediaStreamVideoSource::kDefaultWidth *
@@ -60,11 +60,13 @@
       const std::string& device_id,
       const media::VideoCaptureFormat& format,
       ::mojom::FacingMode facing_mode,
-      media::PowerLineFrequency power_line_frequency)
+      media::PowerLineFrequency power_line_frequency,
+      const rtc::Optional<bool>& noise_reduction)
       : device_id_(device_id),
         format_(format),
         facing_mode_(facing_mode),
-        power_line_frequency_(power_line_frequency) {}
+        power_line_frequency_(power_line_frequency),
+        noise_reduction_(noise_reduction) {}
 
   VideoDeviceCaptureSourceSettings(
       const VideoDeviceCaptureSourceSettings& other) = default;
@@ -99,12 +101,16 @@
   media::PowerLineFrequency power_line_frequency() const {
     return power_line_frequency_;
   }
+  const rtc::Optional<bool>& noise_reduction() const {
+    return noise_reduction_;
+  }
 
  private:
   std::string device_id_;
   media::VideoCaptureFormat format_;
   ::mojom::FacingMode facing_mode_;
   media::PowerLineFrequency power_line_frequency_;
+  rtc::Optional<bool> noise_reduction_;
 };
 
 VideoDeviceCaptureSourceSelectionResult ResultFromSettings(
@@ -114,6 +120,7 @@
   result.capture_params.requested_format = settings.format();
   result.device_id = settings.device_id();
   result.facing_mode = settings.facing_mode();
+  result.noise_reduction = settings.noise_reduction();
   result.failed_constraint_name = nullptr;
 
   return result;
@@ -324,6 +331,25 @@
   return 0.0;
 }
 
+// Returns a custom distance function suitable for the googNoiseReduction
+// constraint, given  a |constraint| and a candidate value |value|.
+// The distance is HUGE_VAL if |candidate_value| cannot satisfy |constraint|.
+// Otherwise, the distance is zero.
+double NoiseReductionConstraintSourceDistance(
+    const blink::BooleanConstraint& constraint,
+    const rtc::Optional<bool>& value,
+    const char** failed_constraint_name) {
+  if (!constraint.hasExact())
+    return 0.0;
+
+  if (value && *value == constraint.exact())
+    return 0.0;
+
+  if (failed_constraint_name)
+    *failed_constraint_name = constraint.name();
+  return HUGE_VAL;
+}
+
 // Returns a custom distance for constraints that depend on the device
 // characteristics that have a fixed value.
 double DeviceSourceDistance(
@@ -379,7 +405,10 @@
                               failed_constraint_name) +
          PowerLineFrequencyConstraintSourceDistance(
              constraint_set.googPowerLineFrequency,
-             candidate.power_line_frequency(), failed_constraint_name);
+             candidate.power_line_frequency(), failed_constraint_name) +
+         NoiseReductionConstraintSourceDistance(
+             constraint_set.googNoiseReduction, candidate.noise_reduction(),
+             failed_constraint_name);
 }
 
 // Returns the fitness distance between |value| and |constraint|.
@@ -511,6 +540,21 @@
   return 1.0;
 }
 
+// Returns the fitness distance between |value| and |constraint| for the
+// googNoiseReduction constraint.
+// Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance.
+double NoiseReductionConstraintFitnessDistance(
+    const rtc::Optional<bool>& value,
+    const blink::BooleanConstraint& constraint) {
+  if (!constraint.hasIdeal())
+    return 0.0;
+
+  if (value && value == constraint.ideal())
+    return 0.0;
+
+  return 1.0;
+}
+
 // Returns the fitness distance between a settings candidate and a constraint
 // set. The returned value is the sum of the fitness distances between each
 // setting in |candidate| and the corresponding constraint in |constraint_set|.
@@ -534,6 +578,8 @@
                                              constraint_set.videoKind);
   fitness += PowerLineFrequencyConstraintFitnessDistance(
       candidate.GetPowerLineFrequency(), constraint_set.googPowerLineFrequency);
+  fitness += NoiseReductionConstraintFitnessDistance(
+      candidate.noise_reduction(), constraint_set.googNoiseReduction);
   fitness += ResolutionConstraintFitnessDistance(candidate.GetHeight(),
                                                  constraint_set.height);
   fitness += ResolutionConstraintFitnessDistance(candidate.GetWidth(),
@@ -591,6 +637,12 @@
           : HUGE_VAL;
   distance_vector->push_back(power_line_frequency_distance);
 
+  // Prefer not having a specific noise-reduction value and let the lower-layers
+  // implementation choose a noise-reduction strategy.
+  double noise_reduction_distance =
+      candidate.noise_reduction() ? HUGE_VAL : 0.0;
+  distance_vector->push_back(noise_reduction_distance);
+
   // Prefer a resolution with area close to the default.
   int candidate_area = candidate.format().frame_size.GetArea();
   double resolution_distance =
@@ -692,52 +744,63 @@
         if (!std::isfinite(basic_power_line_frequency_distance))
           continue;
 
-        // The candidate satisfies the basic constraint set.
-        double candidate_basic_custom_distance =
-            basic_device_distance + basic_format_distance +
-            basic_power_line_frequency_distance;
-        DCHECK(std::isfinite(candidate_basic_custom_distance));
+        for (auto& noise_reduction :
+             capabilities.noise_reduction_capabilities) {
+          double basic_noise_reduction_distance =
+              NoiseReductionConstraintSourceDistance(
+                  constraints.basic().googNoiseReduction, noise_reduction,
+                  &failed_constraint_name);
+          if (!std::isfinite(basic_noise_reduction_distance))
+            continue;
 
-        // Temporary vector to save custom distances for advanced constraints.
-        // Custom distances must be added to the candidate distance vector after
-        // all the spec-mandated values.
-        DistanceVector advanced_custom_distance_vector;
-        VideoDeviceCaptureSourceSettings candidate(device->device_id, format,
-                                                   device->facing_mode,
-                                                   power_line_frequency);
-        DistanceVector candidate_distance_vector;
-        // First criteria for valid candidates is satisfaction of advanced
-        // constraint sets.
-        for (const auto& advanced : constraints.advanced()) {
-          double custom_distance =
-              CandidateSourceDistance(candidate, advanced, nullptr);
-          advanced_custom_distance_vector.push_back(custom_distance);
-          double spec_distance = std::isfinite(custom_distance) ? 0 : 1;
-          candidate_distance_vector.push_back(spec_distance);
-        }
+          // The candidate satisfies the basic constraint set.
+          double candidate_basic_custom_distance =
+              basic_device_distance + basic_format_distance +
+              basic_power_line_frequency_distance +
+              basic_noise_reduction_distance;
+          DCHECK(std::isfinite(candidate_basic_custom_distance));
 
-        // Second criterion is fitness distance.
-        candidate_distance_vector.push_back(
-            CandidateFitnessDistance(candidate, constraints.basic()));
+          // Temporary vector to save custom distances for advanced constraints.
+          // Custom distances must be added to the candidate distance vector
+          // after all the spec-mandated values.
+          DistanceVector advanced_custom_distance_vector;
+          VideoDeviceCaptureSourceSettings candidate(
+              device->device_id, format, device->facing_mode,
+              power_line_frequency, noise_reduction);
+          DistanceVector candidate_distance_vector;
+          // First criteria for valid candidates is satisfaction of advanced
+          // constraint sets.
+          for (const auto& advanced : constraints.advanced()) {
+            double custom_distance =
+                CandidateSourceDistance(candidate, advanced, nullptr);
+            advanced_custom_distance_vector.push_back(custom_distance);
+            double spec_distance = std::isfinite(custom_distance) ? 0 : 1;
+            candidate_distance_vector.push_back(spec_distance);
+          }
 
-        // Third criteria are custom distances to constraint sets.
-        candidate_distance_vector.push_back(candidate_basic_custom_distance);
-        std::copy(advanced_custom_distance_vector.begin(),
-                  advanced_custom_distance_vector.end(),
-                  std::back_inserter(candidate_distance_vector));
+          // Second criterion is fitness distance.
+          candidate_distance_vector.push_back(
+              CandidateFitnessDistance(candidate, constraints.basic()));
 
-        // Fourth criteria is native fitness distance.
-        candidate_distance_vector.push_back(
-            CandidateNativeFitnessDistance(candidate, constraints.basic()));
+          // Third criteria are custom distances to constraint sets.
+          candidate_distance_vector.push_back(candidate_basic_custom_distance);
+          std::copy(advanced_custom_distance_vector.begin(),
+                    advanced_custom_distance_vector.end(),
+                    std::back_inserter(candidate_distance_vector));
 
-        // Final criteria are custom distances to default settings.
-        AppendDistanceFromDefault(candidate, capabilities,
-                                  &candidate_distance_vector);
+          // Fourth criteria is native fitness distance.
+          candidate_distance_vector.push_back(
+              CandidateNativeFitnessDistance(candidate, constraints.basic()));
 
-        DCHECK_EQ(best_distance.size(), candidate_distance_vector.size());
-        if (candidate_distance_vector < best_distance) {
-          best_distance = candidate_distance_vector;
-          result = ResultFromSettings(candidate);
+          // Final criteria are custom distances to default settings.
+          AppendDistanceFromDefault(candidate, capabilities,
+                                    &candidate_distance_vector);
+
+          DCHECK_EQ(best_distance.size(), candidate_distance_vector.size());
+          if (candidate_distance_vector < best_distance) {
+            best_distance = candidate_distance_vector;
+            result = ResultFromSettings(candidate);
+          }
         }
       }
     }
diff --git a/content/renderer/media/media_stream_constraints_util_video_device.h b/content/renderer/media/media_stream_constraints_util_video_device.h
index af55fdc..71a1925 100644
--- a/content/renderer/media/media_stream_constraints_util_video_device.h
+++ b/content/renderer/media/media_stream_constraints_util_video_device.h
@@ -11,6 +11,7 @@
 #include "content/common/content_export.h"
 #include "content/common/media/media_devices.mojom.h"
 #include "media/capture/video_capture_types.h"
+#include "third_party/webrtc/base/optional.h"
 
 namespace blink {
 class WebString;
@@ -34,6 +35,7 @@
   // Each field is independent of each other.
   std::vector<::mojom::VideoInputDeviceCapabilitiesPtr> device_capabilities;
   std::vector<media::PowerLineFrequency> power_line_capabilities;
+  std::vector<rtc::Optional<bool>> noise_reduction_capabilities;
 };
 
 struct CONTENT_EXPORT VideoDeviceCaptureSourceSelectionResult {
@@ -69,6 +71,7 @@
   std::string device_id;
   ::mojom::FacingMode facing_mode;
   media::VideoCaptureParams capture_params;
+  rtc::Optional<bool> noise_reduction;
 };
 
 // This function performs source and source-settings selection based on
@@ -130,9 +133,9 @@
 //    ideal value and thus has worse fitness according to step 2, even if C3's
 //    native fitness is better than C1's and C2's.
 // 5. C1 is better than C2 if its settings are closer to certain default
-//    settings that include the device ID, power-line frequency, resolution, and
-//    frame rate, in that order. Note that there is no default facing mode or
-//    aspect ratio.
+//    settings that include the device ID, power-line frequency, noise
+//    reduction, resolution, and frame rate, in that order. Note that there is
+//    no default facing mode or aspect ratio.
 VideoDeviceCaptureSourceSelectionResult CONTENT_EXPORT
 SelectVideoDeviceCaptureSourceSettings(
     const VideoDeviceCaptureCapabilities& capabilities,
diff --git a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
index 5247f39..beac59c 100644
--- a/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
@@ -100,6 +100,11 @@
         media::PowerLineFrequency::FREQUENCY_60HZ,
     };
 
+    capabilities_.noise_reduction_capabilities = {
+        rtc::Optional<bool>(), rtc::Optional<bool>(true),
+        rtc::Optional<bool>(false),
+    };
+
     default_device_ = capabilities_.device_capabilities[0].get();
     low_res_device_ = capabilities_.device_capabilities[1].get();
     high_res_device_ = capabilities_.device_capabilities[2].get();
@@ -138,6 +143,10 @@
   EXPECT_EQ(default_device_->device_id, result.device_id);
   EXPECT_EQ(default_device_->facing_mode, result.facing_mode);
   EXPECT_EQ(*default_closest_format_, result.Format());
+  // Should select default settings for other constraints.
+  EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
+            result.PowerLineFrequency());
+  EXPECT_EQ(rtc::Optional<bool>(), result.noise_reduction);
 }
 
 // The "Overconstrained" tests verify that failure of any single required
@@ -293,6 +302,34 @@
             result.failed_constraint_name);
 }
 
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
+       OverconstrainedOnNoiseReduction) {
+  // Simulate a system that does not support noise reduction.
+  // Manually adding device capabilities because VideoDeviceCaptureCapabilities
+  // is move only.
+  VideoDeviceCaptureCapabilities capabilities;
+  ::mojom::VideoInputDeviceCapabilitiesPtr device =
+      ::mojom::VideoInputDeviceCapabilities::New();
+  device->device_id = kDeviceID1;
+  device->facing_mode = ::mojom::FacingMode::NONE;
+  device->formats = {
+      media::VideoCaptureFormat(gfx::Size(200, 200), 40.0f,
+                                media::PIXEL_FORMAT_I420),
+  };
+  capabilities.device_capabilities.push_back(std::move(device));
+  capabilities.power_line_capabilities = capabilities_.power_line_capabilities;
+  capabilities.noise_reduction_capabilities = {rtc::Optional<bool>(false)};
+
+  constraint_factory_.Reset();
+  constraint_factory_.basic().googNoiseReduction.setExact(true);
+  auto constraints = constraint_factory_.CreateWebMediaConstraints();
+  auto result =
+      SelectVideoDeviceCaptureSourceSettings(capabilities, constraints);
+  EXPECT_FALSE(result.HasValue());
+  EXPECT_EQ(constraint_factory_.basic().googNoiseReduction.name(),
+            result.failed_constraint_name);
+}
+
 // The "Mandatory" and "Ideal" tests check that various selection criteria work
 // for each individual constraint in the basic constraint set.
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryDeviceID) {
@@ -385,6 +422,22 @@
   }
 }
 
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryNoiseReduction) {
+  constraint_factory_.Reset();
+  const bool kNoiseReductionValues[] = {true, false};
+  for (auto noise_reduction : kNoiseReductionValues) {
+    constraint_factory_.basic().googNoiseReduction.setExact(noise_reduction);
+    auto result = SelectSettings();
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_EQ(noise_reduction, result.noise_reduction);
+    // The default device and settings closest to the default should be
+    // selected.
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(default_device_->facing_mode, result.facing_mode);
+    EXPECT_EQ(*default_closest_format_, result.Format());
+  }
+}
+
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactHeight) {
   constraint_factory_.Reset();
   const int kHeight = MediaStreamVideoSource::kDefaultHeight;
@@ -1192,99 +1245,161 @@
 // The "Advanced" tests check selection criteria involving advanced constraint
 // sets.
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedExactResolution) {
-  {
-    constraint_factory_.Reset();
-    blink::WebMediaTrackConstraintSet& advanced1 =
-        constraint_factory_.AddAdvanced();
-    advanced1.width.setExact(4000);
-    advanced1.height.setExact(4000);
-    blink::WebMediaTrackConstraintSet& advanced2 =
-        constraint_factory_.AddAdvanced();
-    advanced2.width.setExact(3000);
-    advanced2.height.setExact(3000);
-    auto result = SelectSettings();
-    // No device supports the advanced constraint sets.
-    // Tie-breaker rule that applies is closeness to default settings.
-    EXPECT_EQ(default_device_->device_id, result.device_id);
-    EXPECT_EQ(*default_closest_format_, result.Format());
+  constraint_factory_.Reset();
+  blink::WebMediaTrackConstraintSet& advanced1 =
+      constraint_factory_.AddAdvanced();
+  advanced1.width.setExact(4000);
+  advanced1.height.setExact(4000);
+  blink::WebMediaTrackConstraintSet& advanced2 =
+      constraint_factory_.AddAdvanced();
+  advanced2.width.setExact(3000);
+  advanced2.height.setExact(3000);
+  auto result = SelectSettings();
+  // No device supports the advanced constraint sets.
+  // Tie-breaker rule that applies is closeness to default settings.
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
-    blink::WebMediaTrackConstraintSet& advanced3 =
-        constraint_factory_.AddAdvanced();
-    advanced3.width.setExact(1920);
-    advanced3.height.setExact(1080);
-    result = SelectSettings();
-    EXPECT_TRUE(result.HasValue());
-    // The high-res device natively supports the third advanced constraint set
-    // and should be selected.
-    // First tie-breaker rule that applies is support for advanced constraints
-    // that appear first. Second tie-breaker rule is custom distance to advanced
-    // constraint sets that appear first.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id);
-    EXPECT_EQ(1920, result.Width());
-    EXPECT_EQ(1080, result.Height());
+  blink::WebMediaTrackConstraintSet& advanced3 =
+      constraint_factory_.AddAdvanced();
+  advanced3.width.setExact(1920);
+  advanced3.height.setExact(1080);
+  result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  // The high-res device natively supports the third advanced constraint set
+  // and should be selected.
+  // First tie-breaker rule that applies is support for advanced constraints
+  // that appear first. Second tie-breaker rule is custom distance to advanced
+  // constraint sets that appear first.
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1920, result.Width());
+  EXPECT_EQ(1080, result.Height());
 
-    blink::WebMediaTrackConstraintSet& advanced4 =
-        constraint_factory_.AddAdvanced();
-    advanced4.width.setExact(640);
-    advanced4.height.setExact(480);
-    result = SelectSettings();
-    EXPECT_TRUE(result.HasValue());
-    // First tie-breaker rule that applies is support for advanced constraints
-    // that appear first, which leaves out configurations that only support the
-    // fourth advanced constraint set in favor of configurations that support
-    // the third set.
-    // Second tie-breaker rule is custom distance to advanced constraint sets
-    // that appear first.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id);
-    EXPECT_EQ(1920, result.Width());
-    EXPECT_EQ(1080, result.Height());
+  blink::WebMediaTrackConstraintSet& advanced4 =
+      constraint_factory_.AddAdvanced();
+  advanced4.width.setExact(640);
+  advanced4.height.setExact(480);
+  result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  // First tie-breaker rule that applies is support for advanced constraints
+  // that appear first, which leaves out configurations that only support the
+  // fourth advanced constraint set in favor of configurations that support
+  // the third set.
+  // Second tie-breaker rule is custom distance to advanced constraint sets
+  // that appear first.
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1920, result.Width());
+  EXPECT_EQ(1080, result.Height());
 
-    constraint_factory_.basic().width.setIdeal(800);
-    constraint_factory_.basic().height.setIdeal(600);
-    result = SelectSettings();
-    EXPECT_TRUE(result.HasValue());
-    // The ideal value is supported by the same configuration, so nothing
-    // changes.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id);
-    EXPECT_EQ(1920, result.Width());
-    EXPECT_EQ(1080, result.Height());
+  constraint_factory_.basic().width.setIdeal(800);
+  constraint_factory_.basic().height.setIdeal(600);
+  result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  // The ideal value is supported by the same configuration, so nothing
+  // changes.
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1920, result.Width());
+  EXPECT_EQ(1080, result.Height());
 
-    constraint_factory_.basic().width.setIdeal(2000);
-    constraint_factory_.basic().height.setIdeal(1500);
-    result = SelectSettings();
-    EXPECT_TRUE(result.HasValue());
-    // The closest configuration to the ideal resolution is the high-res device
-    // at the highest resolution.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id);
-    EXPECT_EQ(*high_res_highest_format_, result.Format());
-  }
+  constraint_factory_.basic().width.setIdeal(2000);
+  constraint_factory_.basic().height.setIdeal(1500);
+  result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  // The closest configuration to the ideal resolution is the high-res device
+  // at the highest resolution.
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_highest_format_, result.Format());
 }
 
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
        AdvancedResolutionAndFrameRate) {
+  constraint_factory_.Reset();
+  blink::WebMediaTrackConstraintSet& advanced1 =
+      constraint_factory_.AddAdvanced();
+  advanced1.width.setExact(1920);
+  advanced1.height.setExact(1080);
+  blink::WebMediaTrackConstraintSet& advanced2 =
+      constraint_factory_.AddAdvanced();
+  advanced2.frameRate.setExact(60.0);
+  blink::WebMediaTrackConstraintSet& advanced3 =
+      constraint_factory_.AddAdvanced();
+  advanced3.width.setExact(2304);
+  advanced3.height.setExact(1536);
+  auto result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  // The high-res device is the only one that satisfies the first advanced
+  // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0
+  // satisfies sets 1, and 2. The latter must be selected, regardless of
+  // any other criteria.
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1920, result.Width());
+  EXPECT_EQ(1080, result.Height());
+  EXPECT_EQ(60.0, result.FrameRate());
+}
+
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedNoiseReduction) {
+  constraint_factory_.Reset();
+  blink::WebMediaTrackConstraintSet& advanced1 =
+      constraint_factory_.AddAdvanced();
+  advanced1.width.setExact(640);
+  advanced1.height.setExact(480);
+  blink::WebMediaTrackConstraintSet& advanced2 =
+      constraint_factory_.AddAdvanced();
+  advanced2.width.setExact(1920);
+  advanced2.height.setExact(1080);
+  advanced2.googNoiseReduction.setExact(false);
+  auto result = SelectSettings();
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1920, result.Width());
+  EXPECT_EQ(1080, result.Height());
+  EXPECT_TRUE(result.noise_reduction && !*result.noise_reduction);
+}
+
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
+       AdvancedContradictoryNoiseReduction) {
   {
     constraint_factory_.Reset();
     blink::WebMediaTrackConstraintSet& advanced1 =
         constraint_factory_.AddAdvanced();
-    advanced1.width.setExact(1920);
-    advanced1.height.setExact(1080);
+    advanced1.width.setMin(640);
+    advanced1.height.setMin(480);
+    advanced1.googNoiseReduction.setExact(true);
     blink::WebMediaTrackConstraintSet& advanced2 =
         constraint_factory_.AddAdvanced();
-    advanced2.frameRate.setExact(60.0);
-    blink::WebMediaTrackConstraintSet& advanced3 =
-        constraint_factory_.AddAdvanced();
-    advanced3.width.setExact(2304);
-    advanced3.height.setExact(1536);
+    advanced2.width.setMin(1920);
+    advanced2.height.setMin(1080);
+    advanced2.googNoiseReduction.setExact(false);
     auto result = SelectSettings();
     EXPECT_TRUE(result.HasValue());
-    // The high-res device is the only one that satisfies the first advanced
-    // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0
-    // satisfies sets 1, and 2. The latter must be selected, regardless of
-    // any other criteria.
+    // The second advanced set cannot be satisfied because it contradicts the
+    // first set. The default device supports the first set and should be
+    // selected.
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_LE(640, result.Width());
+    EXPECT_LE(480, result.Height());
+    EXPECT_TRUE(result.noise_reduction && *result.noise_reduction);
+  }
+
+  // Same test without noise reduction
+  {
+    constraint_factory_.Reset();
+    blink::WebMediaTrackConstraintSet& advanced1 =
+        constraint_factory_.AddAdvanced();
+    advanced1.width.setMin(640);
+    advanced1.height.setMin(480);
+    blink::WebMediaTrackConstraintSet& advanced2 =
+        constraint_factory_.AddAdvanced();
+    advanced2.width.setMin(1920);
+    advanced2.height.setMin(1080);
+    auto result = SelectSettings();
+    EXPECT_TRUE(result.HasValue());
+    // Only the high-res device can satisfy the second advanced set.
     EXPECT_EQ(high_res_device_->device_id, result.device_id);
-    EXPECT_EQ(1920, result.Width());
-    EXPECT_EQ(1080, result.Height());
-    EXPECT_EQ(60.0, result.FrameRate());
+    EXPECT_LE(1920, result.Width());
+    EXPECT_LE(1080, result.Height());
+    // Should select default noise reduction setting.
+    EXPECT_TRUE(!result.noise_reduction);
   }
 }
 
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index d8cc904..439e0af 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -372,6 +372,9 @@
       media::PowerLineFrequency::FREQUENCY_DEFAULT,
       media::PowerLineFrequency::FREQUENCY_50HZ,
       media::PowerLineFrequency::FREQUENCY_60HZ};
+  capabilities.noise_reduction_capabilities = {rtc::Optional<bool>(),
+                                               rtc::Optional<bool>(true),
+                                               rtc::Optional<bool>(false)};
 
   base::PostTaskAndReplyWithResult(
       worker_task_runner_.get(), FROM_HERE,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 9d993b3..ee8ec0b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -738,6 +738,7 @@
     "//net:test_support",
     "//ppapi/features",
     "//services/catalog:lib",
+    "//services/resource_coordinator:lib",
     "//services/service_manager/public/cpp",
     "//services/ui/public/cpp/gpu",
     "//storage/browser",
diff --git a/extensions/shell/OWNERS b/extensions/shell/OWNERS
index 047582d..420da75e4 100644
--- a/extensions/shell/OWNERS
+++ b/extensions/shell/OWNERS
@@ -1,3 +1,6 @@
 derat@chromium.org
 jamescook@chromium.org
 steel@chromium.org
+
+# TEAM: extensions-dev@chromium.org
+# COMPONENT: Platform>Extensions
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 5d7e214..3eaf1adc7 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -110,6 +110,98 @@
     GLint orig_binding_;
 };
 
+bool IsWebGLDrawBuffersSupported(GLenum depth_texture_internal_format,
+                                 GLenum depth_stencil_texture_internal_format) {
+  // This is called after we make sure GL_EXT_draw_buffers is supported.
+  GLint max_draw_buffers = 0;
+  GLint max_color_attachments = 0;
+  glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
+  glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &max_color_attachments);
+  if (max_draw_buffers < 4 || max_color_attachments < 4) {
+    return false;
+  }
+
+  GLint fb_binding = 0;
+  GLint tex_binding = 0;
+  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fb_binding);
+  glGetIntegerv(GL_TEXTURE_BINDING_2D, &tex_binding);
+
+  GLuint fbo;
+  glGenFramebuffersEXT(1, &fbo);
+  glBindFramebufferEXT(GL_FRAMEBUFFER, fbo);
+
+  GLuint depth_stencil_texture = 0;
+  if (depth_stencil_texture_internal_format != GL_NONE) {
+    glGenTextures(1, &depth_stencil_texture);
+    glBindTexture(GL_TEXTURE_2D, depth_stencil_texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, depth_stencil_texture_internal_format, 1, 1,
+                 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
+  }
+
+  GLuint depth_texture = 0;
+  if (depth_texture_internal_format != GL_NONE) {
+    glGenTextures(1, &depth_texture);
+    glBindTexture(GL_TEXTURE_2D, depth_texture);
+    glTexImage2D(GL_TEXTURE_2D, 0, depth_texture_internal_format, 1, 1, 0,
+                 GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+  }
+
+  GLint max_allowed_buffers = std::min(max_draw_buffers, max_color_attachments);
+  std::vector<GLuint> colors(max_allowed_buffers, 0);
+  glGenTextures(max_allowed_buffers, colors.data());
+
+  bool result = true;
+  for (GLint i = 0; i < max_allowed_buffers; ++i) {
+    GLint color = colors[i];
+    glBindTexture(GL_TEXTURE_2D, color);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                 nullptr);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
+                              GL_TEXTURE_2D, color, 0);
+    if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) !=
+        GL_FRAMEBUFFER_COMPLETE) {
+      result = false;
+      break;
+    }
+    if (depth_texture != 0) {
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                GL_TEXTURE_2D, depth_texture, 0);
+      if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) !=
+          GL_FRAMEBUFFER_COMPLETE) {
+        result = false;
+        break;
+      }
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                GL_TEXTURE_2D, 0, 0);
+    }
+    if (depth_stencil_texture != 0) {
+      // For ES 2.0 contexts DEPTH_STENCIL is not available natively, so we
+      // emulate it at the command buffer level for WebGL contexts.
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                GL_TEXTURE_2D, depth_stencil_texture, 0);
+      if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER) !=
+          GL_FRAMEBUFFER_COMPLETE) {
+        result = false;
+        break;
+      }
+      glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
+                                GL_TEXTURE_2D, 0, 0);
+    }
+  }
+
+  glBindFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLuint>(fb_binding));
+  glDeleteFramebuffersEXT(1, &fbo);
+
+  glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(tex_binding));
+  glDeleteTextures(1, &depth_texture);
+  glDeleteTextures(1, &depth_stencil_texture);
+  glDeleteTextures(colors.size(), colors.data());
+
+  DCHECK(glGetError() == GL_NO_ERROR);
+
+  return result;
+}
+
 }  // anonymous namespace.
 
 FeatureInfo::FeatureFlags::FeatureFlags() {}
@@ -462,6 +554,7 @@
   // get rid of it.
   //
   bool enable_depth_texture = false;
+  GLenum depth_texture_format = GL_NONE;
   if (!workarounds_.disable_depth_texture &&
       (extensions.Contains("GL_ARB_depth_texture") ||
        extensions.Contains("GL_OES_depth_texture") ||
@@ -472,6 +565,7 @@
     // This is because depth textures are filterable under linear mode in
     // ES2 + extension, but not in core ES3.
     enable_depth_texture = true;
+    depth_texture_format = GL_DEPTH_COMPONENT;
     feature_flags_.angle_depth_texture =
         extensions.Contains("GL_ANGLE_depth_texture");
   }
@@ -487,6 +581,7 @@
         GL_DEPTH_COMPONENT);
   }
 
+  GLenum depth_stencil_texture_format = GL_NONE;
   if (extensions.Contains("GL_EXT_packed_depth_stencil") ||
       extensions.Contains("GL_OES_packed_depth_stencil") ||
       gl_version_info_->is_es3 ||
@@ -494,6 +589,11 @@
     AddExtensionString("GL_OES_packed_depth_stencil");
     feature_flags_.packed_depth24_stencil8 = true;
     if (enable_depth_texture) {
+      if (gl_version_info_->is_es3) {
+        depth_stencil_texture_format = GL_DEPTH24_STENCIL8;
+      } else {
+        depth_stencil_texture_format = GL_DEPTH_STENCIL;
+      }
       validators_.texture_internal_format.AddValue(GL_DEPTH_STENCIL);
       validators_.texture_format.AddValue(GL_DEPTH_STENCIL);
       validators_.pixel_type.AddValue(GL_UNSIGNED_INT_24_8);
@@ -998,10 +1098,14 @@
       extensions.Contains("GL_EXT_draw_buffers");
   bool can_emulate_es2_draw_buffers_on_es3_nv =
       gl_version_info_->is_es3 && extensions.Contains("GL_NV_draw_buffers");
-  bool have_es2_draw_buffers = !workarounds_.disable_ext_draw_buffers &&
-                               IsWebGL1OrES2Context() &&
-                               (have_es2_draw_buffers_vendor_agnostic ||
-                                can_emulate_es2_draw_buffers_on_es3_nv);
+  bool have_es2_draw_buffers =
+      !workarounds_.disable_ext_draw_buffers &&
+      (have_es2_draw_buffers_vendor_agnostic ||
+       can_emulate_es2_draw_buffers_on_es3_nv) &&
+      (context_type_ == CONTEXT_TYPE_OPENGLES2 ||
+       (context_type_ == CONTEXT_TYPE_WEBGL1 &&
+        IsWebGLDrawBuffersSupported(depth_texture_format,
+                                    depth_stencil_texture_format)));
   if (have_es2_draw_buffers) {
     AddExtensionString("GL_EXT_draw_buffers");
     feature_flags_.ext_draw_buffers = true;
diff --git a/ios/chrome/browser/find_in_page/BUILD.gn b/ios/chrome/browser/find_in_page/BUILD.gn
index 2ea3d5a..e13b876a 100644
--- a/ios/chrome/browser/find_in_page/BUILD.gn
+++ b/ios/chrome/browser/find_in_page/BUILD.gn
@@ -41,8 +41,27 @@
   ]
   deps = [
     ":find_in_page",
+    ":unit_tests_nonarc",
     "//base",
     "//ios/web",
     "//ios/web:test_support",
+    "//testing/gtest",
+  ]
+}
+
+source_set("unit_tests_nonarc") {
+  testonly = true
+  sources = [
+    "find_in_page_js_unittest.mm",
+    "js_findinpage_manager_unittest.mm",
+  ]
+  deps = [
+    ":find_in_page",
+    "//base",
+    "//base/test:test_support",
+    "//ios/chrome/browser/web:test_support",
+    "//ios/web",
+    "//ios/web:test_support",
+    "//testing/gtest",
   ]
 }
diff --git a/ios/chrome/browser/web/find_in_page_js_unittest.mm b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
similarity index 88%
rename from ios/chrome/browser/web/find_in_page_js_unittest.mm
rename to ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
index 89ee821..38cd267 100644
--- a/ios/chrome/browser/web/find_in_page_js_unittest.mm
+++ b/ios/chrome/browser/find_in_page/find_in_page_js_unittest.mm
@@ -4,16 +4,19 @@
 
 #import <UIKit/UIKit.h>
 
+#include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
-#import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
+#import "ios/chrome/browser/find_in_page/find_in_page_model.h"
+#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h"
 #import "ios/chrome/browser/web/chrome_web_test.h"
+#import "ios/web/public/web_state/crw_web_view_proxy.h"
+#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/web_state.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
 
-// Unit tests for the models/resources/find_in_page.js JavaScript file.
+// Unit tests for the find_in_page.js JavaScript file.
 
 namespace {
 
@@ -63,7 +66,11 @@
   // Loads the given HTML, then loads the |findInPage| JavaScript.
   void LoadHtml(NSString* html) {
     ChromeWebTest::LoadHtml(html);
-    [findInPageController_ initFindInPage];
+
+    // Inject and initialize the find in page javascript.
+    [findInPageJsManager_ inject];
+    CGRect frame = [web_state()->GetWebViewProxy() bounds];
+    [findInPageJsManager_ setWidth:frame.size.width height:frame.size.height];
   }
 
   // Runs the given JavaScript and asserts that the result matches the given
@@ -94,15 +101,15 @@
 
   void SetUp() override {
     ChromeWebTest::SetUp();
-    mockDelegate_.reset([[OCMockObject
-        niceMockForProtocol:@protocol(FindInPageControllerDelegate)] retain]);
-    findInPageController_.reset([[FindInPageController alloc]
-        initWithWebState:web_state()
-                delegate:mockDelegate_]);
+    findInPageModel_.reset([[FindInPageModel alloc] init]);
+    findInPageJsManager_.reset([base::mac::ObjCCastStrict<JsFindinpageManager>(
+        [web_state()->GetJSInjectionReceiver()
+            instanceOfClass:[JsFindinpageManager class]]) retain]);
+    findInPageJsManager_.get().findInPageModel = findInPageModel_;
   }
 
-  base::scoped_nsobject<FindInPageController> findInPageController_;
-  base::scoped_nsobject<id> mockDelegate_;
+  base::scoped_nsobject<FindInPageModel> findInPageModel_;
+  base::scoped_nsobject<JsFindinpageManager> findInPageJsManager_;
 };
 
 // Performs a search, then calls |incrementIndex| to loop through the
diff --git a/ios/chrome/browser/web/js_findinpage_manager_unittest.mm b/ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm
similarity index 99%
rename from ios/chrome/browser/web/js_findinpage_manager_unittest.mm
rename to ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm
index cd914d7e..ec13bec 100644
--- a/ios/chrome/browser/web/js_findinpage_manager_unittest.mm
+++ b/ios/chrome/browser/find_in_page/js_findinpage_manager_unittest.mm
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h"
+
 #import <Foundation/Foundation.h>
 
 #import "base/test/ios/wait_util.h"
-#import "ios/chrome/browser/find_in_page/js_findinpage_manager.h"
 #import "ios/chrome/browser/web/chrome_web_test.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/web_state.h"
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index d1ce428..8514df5b 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -225,8 +225,6 @@
     "chrome_web_client_unittest.mm",
     "error_page_generator_unittest.mm",
     "external_app_launcher_unittest.mm",
-    "find_in_page_js_unittest.mm",
-    "js_findinpage_manager_unittest.mm",
   ]
   deps = [
     ":test_support",
diff --git a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
index 792a6ab..305eac0 100644
--- a/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab/tab_container_view_controller.mm
@@ -17,7 +17,7 @@
 
 namespace {
 CGFloat kToolbarHeight = 44.0f;
-CGFloat kTabStripHeight = 200.0f;
+CGFloat kTabStripHeight = 90.0f;
 }
 
 @interface TabContainerViewController ()
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
index 6624402e..938f900 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -94,6 +94,10 @@
   return urlText;
 }
 
+- (NSInteger)indexOfActiveTab {
+  return static_cast<NSInteger>(_activeWebStateIndex);
+}
+
 #pragma mark - TabCommands
 
 - (void)showTabAtIndexPath:(NSIndexPath*)indexPath {
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h
index c42d8ed9..cc9dc5f 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h
@@ -11,12 +11,13 @@
 
 #import <UIKit/UIKit.h>
 
-// Placeholder cell implementation for use in the tab grid.
-// A square cell with rounded corners and a label placed in the center.
-@interface TabGridTabCell : UICollectionViewCell
+#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 
-// The label in the center of the tab cell.
-@property(nonatomic, readonly) UILabel* label;
+// Cell represents a tab for use in the tab grid. It has a title, favicon,
+// screenshot image, and close button. Cell selection is represented by a border
+// highlight in the tintColor.
+// PLACEHOLDER: Create custom implemementation rather than subclassing.
+@interface TabGridTabCell : TabSwitcherLocalSessionCell
 
 @end
 
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm
index 8e02a69e..abf9f5cb 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.mm
@@ -13,38 +13,22 @@
 #endif
 
 namespace {
-const CGFloat kCornerRadius = 4.0;
-const CGFloat kSelectedBorderWidth = 2.0;
+const CGFloat kSelectedBorderCornerRadius = 8.0f;
+const CGFloat kSelectedBorderWidth = 4.0f;
 }
 
 @implementation TabGridTabCell
 
-@synthesize label = _label;
-
 - (instancetype)initWithFrame:(CGRect)frame {
   if ((self = [super initWithFrame:frame])) {
-    self.contentView.layer.cornerRadius = kCornerRadius;
-    self.selectedBackgroundView.layer.cornerRadius = kCornerRadius;
+    self.selectedBackgroundView = [[UIView alloc] init];
+    self.selectedBackgroundView.backgroundColor = [UIColor blackColor];
+    self.selectedBackgroundView.layer.cornerRadius =
+        kSelectedBorderCornerRadius;
     self.selectedBackgroundView.layer.borderWidth = kSelectedBorderWidth;
-    self.selectedBackgroundView.layer.borderColor = [UIColor blueColor].CGColor;
+    self.selectedBackgroundView.layer.borderColor = self.tintColor.CGColor;
     self.selectedBackgroundView.transform = CGAffineTransformScale(
-        self.selectedBackgroundView.transform, 1.05, 1.05);
-
-    _label = [[UILabel alloc] initWithFrame:CGRectZero];
-    _label.translatesAutoresizingMaskIntoConstraints = NO;
-    _label.numberOfLines = 1;
-    _label.textAlignment = NSTextAlignmentCenter;
-    [self.contentView addSubview:_label];
-    [NSLayoutConstraint activateConstraints:@[
-      [_label.centerYAnchor
-          constraintEqualToAnchor:self.contentView.centerYAnchor],
-      [_label.leadingAnchor
-          constraintEqualToAnchor:self.contentView.layoutMarginsGuide
-                                      .leadingAnchor],
-      [_label.trailingAnchor
-          constraintEqualToAnchor:self.contentView.layoutMarginsGuide
-                                      .trailingAnchor],
-    ]];
+        self.selectedBackgroundView.transform, 1.08, 1.08);
   }
   return self;
 }
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
index 09c59f0..2bc70ab 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
@@ -29,6 +29,9 @@
 // Title for the tab at |index| in the grid.
 - (NSString*)titleAtIndex:(NSInteger)index;
 
+// Index for the active tab.
+- (NSInteger)indexOfActiveTab;
+
 @end
 
 // Controller for a scrolling view displaying square cells that represent
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 706910fe..9ee9700b 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -9,7 +9,6 @@
 #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.h"
 
 #include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_collection_view_layout.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h"
 #import "ios/clean/chrome/browser/ui/actions/settings_actions.h"
@@ -19,6 +18,7 @@
 #import "ios/clean/chrome/browser/ui/commands/tab_grid_commands.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/mdc_floating_button+cr_tab_grid.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_collection_view_layout.h"
+#import "ios/clean/chrome/browser/ui/tab_grid/tab_grid_tab_cell.h"
 #import "ios/clean/chrome/browser/ui/tab_grid/ui_stack_view+cr_tab_grid.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -73,8 +73,8 @@
   self.grid = grid;
   self.grid.dataSource = self;
   self.grid.delegate = self;
-  [self.grid registerClass:[TabSwitcherLocalSessionCell class]
-      forCellWithReuseIdentifier:[TabSwitcherLocalSessionCell identifier]];
+  [self.grid registerClass:[TabGridTabCell class]
+      forCellWithReuseIdentifier:[TabGridTabCell identifier]];
 
   [NSLayoutConstraint activateConstraints:@[
     [self.grid.topAnchor constraintEqualToAnchor:toolbar.bottomAnchor],
@@ -85,7 +85,6 @@
 }
 
 - (void)viewWillAppear:(BOOL)animated {
-  [self.grid reloadData];
   self.floatingNewTabButton = [MDCFloatingButton cr_tabGridNewTabButton];
   [self.floatingNewTabButton
       setFrame:[MDCFloatingButton
@@ -119,19 +118,27 @@
 
 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
                  cellForItemAtIndexPath:(nonnull NSIndexPath*)indexPath {
-  TabSwitcherLocalSessionCell* cell =
-      base::mac::ObjCCastStrict<TabSwitcherLocalSessionCell>([collectionView
-          dequeueReusableCellWithReuseIdentifier:
-                              [TabSwitcherLocalSessionCell identifier]
+  TabGridTabCell* cell =
+      base::mac::ObjCCastStrict<TabGridTabCell>([collectionView
+          dequeueReusableCellWithReuseIdentifier:[TabGridTabCell identifier]
                                     forIndexPath:indexPath]);
   cell.delegate = self;
   [cell setSessionType:TabSwitcherSessionType::REGULAR_SESSION];
   [cell setAppearanceForTabTitle:[self.dataSource titleAtIndex:indexPath.item]
                          favicon:nil
                         cellSize:CGSizeZero];
+  [cell setSelected:(indexPath.item == [self.dataSource indexOfActiveTab])];
   return cell;
 }
 
+#pragma mark - UICollectionViewDelegate methods
+
+- (BOOL)collectionView:(UICollectionView*)collectionView
+    shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath {
+  // Prevent user selection of items.
+  return NO;
+}
+
 #pragma mark - ZoomTransitionDelegate methods
 
 - (CGRect)rectForZoomWithKey:(NSObject*)key inView:(UIView*)view {
@@ -160,6 +167,13 @@
   NSInteger index = [self.grid numberOfItemsInSection:0];
   NSIndexPath* indexPath = [NSIndexPath indexPathForItem:index inSection:0];
   auto updateBlock = ^{
+    // Unselect current selected item.
+    NSInteger selectedIndex = [self.dataSource indexOfActiveTab];
+    NSIndexPath* selectedIndexPath =
+        [NSIndexPath indexPathForItem:selectedIndex inSection:0];
+    [self.grid reloadItemsAtIndexPaths:@[ selectedIndexPath ]];
+
+    // Create and show new tab.
     [self.tabCommandHandler createNewTabAtIndexPath:indexPath];
     [self.tabCommandHandler showTabAtIndexPath:indexPath];
     [self.grid insertItemsAtIndexPaths:@[ indexPath ]];
@@ -175,7 +189,15 @@
 }
 
 - (void)cellPressed:(UICollectionViewCell*)cell {
-  [self.tabCommandHandler showTabAtIndexPath:[self.grid indexPathForCell:cell]];
+  NSInteger selectedIndex = [self.dataSource indexOfActiveTab];
+  NSIndexPath* newSelectedIndexPath = [self.grid indexPathForCell:cell];
+  [self.tabCommandHandler showTabAtIndexPath:newSelectedIndexPath];
+  if (newSelectedIndexPath.item != selectedIndex) {
+    NSIndexPath* selectedIndexPath =
+        [NSIndexPath indexPathForItem:selectedIndex inSection:0];
+    [self.grid
+        reloadItemsAtIndexPaths:@[ selectedIndexPath, newSelectedIndexPath ]];
+  }
 }
 
 - (void)deleteButtonPressedForCell:(UICollectionViewCell*)cell {
diff --git a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm
index b92f4a6..e47bd47b 100644
--- a/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm
+++ b/ios/showcase/tab_grid/sc_tab_grid_coordinator.mm
@@ -48,4 +48,8 @@
   return [NSString stringWithFormat:@"Tab %" PRIdNS, index];
 }
 
+- (NSInteger)indexOfActiveTab {
+  return NSNotFound;
+}
+
 @end
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.h b/ios/web/public/test/fakes/crw_test_web_state_observer.h
index fb5fe73..5befde4 100644
--- a/ios/web/public/test/fakes/crw_test_web_state_observer.h
+++ b/ios/web/public/test/fakes/crw_test_web_state_observer.h
@@ -35,11 +35,6 @@
   WebState* web_state;
 };
 
-// Arguments passed to |webStateDidChangeURLHash:|.
-struct TestChangeUrlHashInfo {
-  WebState* web_state;
-};
-
 // Arguments passed to |webStateDidChangeHistoryState:|.
 struct TestChangeHistoryStateInfo {
   WebState* web_state;
@@ -115,8 +110,6 @@
 // Arguments passed to |webStateDidDismissInterstitial:|.
 @property(nonatomic, readonly)
     web::TestDismissInterstitialInfo* dismissInterstitialInfo;
-// Arguments passed to |webStateDidChangeURLHash:|.
-@property(nonatomic, readonly) web::TestChangeUrlHashInfo* changeUrlHashInfo;
 // Arguments passed to |webStateDidChangeHistoryState:|.
 @property(nonatomic, readonly)
     web::TestChangeHistoryStateInfo* changeHistoryStateInfo;
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.mm b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
index 755753f..b7e785c 100644
--- a/ios/web/public/test/fakes/crw_test_web_state_observer.mm
+++ b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
@@ -24,8 +24,6 @@
   std::unique_ptr<web::TestLoadPageInfo> _loadPageInfo;
   // Arguments passed to |webStateDidDismissInterstitial:|.
   std::unique_ptr<web::TestDismissInterstitialInfo> _dismissInterstitialInfo;
-  // Arguments passed to |webStateDidChangeURLHash:|.
-  std::unique_ptr<web::TestChangeUrlHashInfo> _changeUrlHashInfo;
   // Arguments passed to |webStateDidChangeHistoryState:|.
   std::unique_ptr<web::TestChangeHistoryStateInfo> _changeHistoryStateInfo;
   // Arguments passed to |webState:didChangeLoadingProgress:|.
@@ -66,10 +64,6 @@
   return _dismissInterstitialInfo.get();
 }
 
-- (web::TestChangeUrlHashInfo*)changeUrlHashInfo {
-  return _changeUrlHashInfo.get();
-}
-
 - (web::TestChangeHistoryStateInfo*)changeHistoryStateInfo {
   return _changeHistoryStateInfo.get();
 }
@@ -136,11 +130,6 @@
   _dismissInterstitialInfo->web_state = webState;
 }
 
-- (void)webStateDidChangeURLHash:(web::WebState*)webState {
-  _changeUrlHashInfo = base::MakeUnique<web::TestChangeUrlHashInfo>();
-  _changeUrlHashInfo->web_state = webState;
-}
-
 - (void)webStateDidChangeHistoryState:(web::WebState*)webState {
   _changeHistoryStateInfo = base::MakeUnique<web::TestChangeHistoryStateInfo>();
   _changeHistoryStateInfo->web_state = webState;
diff --git a/ios/web/public/web_state/web_state_observer.h b/ios/web/public/web_state/web_state_observer.h
index 62114a0..ff0a15de 100644
--- a/ios/web/public/web_state/web_state_observer.h
+++ b/ios/web/public/web_state/web_state_observer.h
@@ -80,14 +80,6 @@
   // Called when the interstitial is dismissed by the user.
   virtual void InterstitialDismissed() {}
 
-  // Called on URL hash change events.
-  // TODO(crbug.com/692331): Remove this method and use |DidFinishNavigation|.
-  virtual void UrlHashChanged() {}
-
-  // Called on history state change events.
-  // TODO(crbug.com/692331): Remove this method and use |DidFinishNavigation|.
-  virtual void HistoryStateChanged() {}
-
   // Notifies the observer that the page has made some progress loading.
   // |progress| is a value between 0.0 (nothing loaded) to 1.0 (page fully
   // loaded).
diff --git a/ios/web/public/web_state/web_state_observer_bridge.h b/ios/web/public/web_state/web_state_observer_bridge.h
index 9ee95c4..93614ab 100644
--- a/ios/web/public/web_state/web_state_observer_bridge.h
+++ b/ios/web/public/web_state/web_state_observer_bridge.h
@@ -35,12 +35,6 @@
 // Invoked by WebStateObserverBridge::InterstitialDismissed.
 - (void)webStateDidDismissInterstitial:(web::WebState*)webState;
 
-// Invoked by WebStateObserverBridge::UrlHashChanged.
-- (void)webStateDidChangeURLHash:(web::WebState*)webState;
-
-// Invoked by WebStateObserverBridge::HistoryStateChanged.
-- (void)webStateDidChangeHistoryState:(web::WebState*)webState;
-
 // Invoked by WebStateObserverBridge::LoadProgressChanged.
 - (void)webState:(web::WebState*)webState
     didChangeLoadingProgress:(double)progress;
@@ -100,8 +94,6 @@
   void PageLoaded(
       web::PageLoadCompletionStatus load_completion_status) override;
   void InterstitialDismissed() override;
-  void UrlHashChanged() override;
-  void HistoryStateChanged() override;
   void LoadProgressChanged(double progress) override;
   void DocumentSubmitted(const std::string& form_name,
                          bool user_initiated) override;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 3564aab..a232f4c6 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2862,8 +2862,6 @@
     item->SetIsCreatedFromHashChange(true);
   }
 
-  // Notify the observers.
-  _webStateImpl->OnUrlHashChanged();
   return YES;
 }
 
@@ -2962,8 +2960,6 @@
       return;
     base::scoped_nsobject<CRWWebController> strongSelf([weakSelf retain]);
     [strongSelf optOutScrollsToTopForSubviews];
-    // Notify the observers.
-    strongSelf.get()->_webStateImpl->OnHistoryStateChanged();
     [strongSelf didFinishNavigation];
   }];
   return YES;
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 4b7754a..5d4f0e8 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -82,12 +82,6 @@
   // Called when a navigation is committed.
   void OnNavigationCommitted(const GURL& url);
 
-  // Notifies the observers that the URL hash of the current page changed.
-  void OnUrlHashChanged();
-
-  // Notifies the observers that the history state of the current page changed.
-  void OnHistoryStateChanged();
-
   // Notifies the observers that same page navigation did finish.
   void OnSamePageNavigation(const GURL& url);
 
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 2a3034f..824affd 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -193,16 +193,6 @@
     observer.DidFinishNavigation(context.get());
 }
 
-void WebStateImpl::OnUrlHashChanged() {
-  for (auto& observer : observers_)
-    observer.UrlHashChanged();
-}
-
-void WebStateImpl::OnHistoryStateChanged() {
-  for (auto& observer : observers_)
-    observer.HistoryStateChanged();
-}
-
 void WebStateImpl::OnSamePageNavigation(const GURL& url) {
   std::unique_ptr<NavigationContext> context =
       NavigationContextImpl::CreateSamePageNavigationContext(this, url);
diff --git a/ios/web/web_state/web_state_impl_unittest.mm b/ios/web/web_state/web_state_impl_unittest.mm
index 992132f..3aa7097 100644
--- a/ios/web/web_state/web_state_impl_unittest.mm
+++ b/ios/web/web_state/web_state_impl_unittest.mm
@@ -127,7 +127,6 @@
         navigation_item_changed_called_(false),
         navigation_item_committed_called_(false),
         page_loaded_called_with_success_(false),
-        url_hash_changed_called_(false),
         history_state_changed_called_(false),
         did_finish_navigation_called_(false),
         web_state_destroyed_called_(false) {}
@@ -149,7 +148,6 @@
   bool page_loaded_called_with_success() const {
     return page_loaded_called_with_success_;
   }
-  bool url_hash_changed_called() const { return url_hash_changed_called_; }
   bool history_state_changed_called() const {
     return history_state_changed_called_;
   }
@@ -182,8 +180,6 @@
     page_loaded_called_with_success_ =
         load_completion_status == PageLoadCompletionStatus::SUCCESS;
   }
-  void UrlHashChanged() override { url_hash_changed_called_ = true; }
-  void HistoryStateChanged() override { history_state_changed_called_ = true; }
   void WebStateDestroyed() override {
     EXPECT_TRUE(web_state()->IsBeingDestroyed());
     web_state_destroyed_called_ = true;
@@ -195,7 +191,6 @@
   bool navigation_item_changed_called_;
   bool navigation_item_committed_called_;
   bool page_loaded_called_with_success_;
-  bool url_hash_changed_called_;
   bool history_state_changed_called_;
   bool did_finish_navigation_called_;
   bool web_state_destroyed_called_;
@@ -392,16 +387,6 @@
   web_state_->OnPageLoaded(GURL("http://test"), true);
   EXPECT_TRUE(observer->page_loaded_called_with_success());
 
-  // Test that UrlHashChanged() is called.
-  EXPECT_FALSE(observer->url_hash_changed_called());
-  web_state_->OnUrlHashChanged();
-  EXPECT_TRUE(observer->url_hash_changed_called());
-
-  // Test that HistoryStateChanged() is called.
-  EXPECT_FALSE(observer->history_state_changed_called());
-  web_state_->OnHistoryStateChanged();
-  EXPECT_TRUE(observer->history_state_changed_called());
-
   // Test that DidFinishNavigation() is called for same page navigations.
   EXPECT_FALSE(observer->did_finish_navigation_called());
   web_state_->OnSamePageNavigation(GURL("http://test"));
diff --git a/ios/web/web_state/web_state_observer_bridge.mm b/ios/web/web_state/web_state_observer_bridge.mm
index 13fbde3..bf22c02c 100644
--- a/ios/web/web_state/web_state_observer_bridge.mm
+++ b/ios/web/web_state/web_state_observer_bridge.mm
@@ -67,18 +67,6 @@
     [observer_ webStateDidDismissInterstitial:web_state()];
 }
 
-void WebStateObserverBridge::UrlHashChanged() {
-  SEL selector = @selector(webStateDidChangeURLHash:);
-  if ([observer_ respondsToSelector:selector])
-    [observer_ webStateDidChangeURLHash:web_state()];
-}
-
-void WebStateObserverBridge::HistoryStateChanged() {
-  SEL selector = @selector(webStateDidChangeHistoryState:);
-  if ([observer_ respondsToSelector:selector])
-    [observer_ webStateDidChangeHistoryState:web_state()];
-}
-
 void WebStateObserverBridge::LoadProgressChanged(double progress) {
   SEL selector = @selector(webState:didChangeLoadingProgress:);
   if ([observer_ respondsToSelector:selector])
diff --git a/ios/web/web_state/web_state_observer_bridge_unittest.mm b/ios/web/web_state/web_state_observer_bridge_unittest.mm
index 4e20088..8d626ef 100644
--- a/ios/web/web_state/web_state_observer_bridge_unittest.mm
+++ b/ios/web/web_state/web_state_observer_bridge_unittest.mm
@@ -90,24 +90,6 @@
   EXPECT_EQ(&test_web_state_, [observer_ dismissInterstitialInfo]->web_state);
 }
 
-// Tests |webState:webStateDidChangeURLHash:| forwarding.
-TEST_F(WebStateObserverBridgeTest, UrlHashChanged) {
-  ASSERT_FALSE([observer_ changeUrlHashInfo]);
-
-  bridge_->UrlHashChanged();
-  ASSERT_TRUE([observer_ changeUrlHashInfo]);
-  EXPECT_EQ(&test_web_state_, [observer_ changeUrlHashInfo]->web_state);
-}
-
-// Tests |webState:webStateDidChangeHistoryState:| forwarding.
-TEST_F(WebStateObserverBridgeTest, HistoryStateChanged) {
-  ASSERT_FALSE([observer_ changeHistoryStateInfo]);
-
-  bridge_->HistoryStateChanged();
-  ASSERT_TRUE([observer_ changeHistoryStateInfo]);
-  EXPECT_EQ(&test_web_state_, [observer_ changeHistoryStateInfo]->web_state);
-}
-
 // Tests |webState:didChangeLoadingProgress:| forwarding.
 TEST_F(WebStateObserverBridgeTest, LoadProgressChanged) {
   ASSERT_FALSE([observer_ changeLoadingProgressInfo]);
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index 9c5f07ef..27edac5 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -10,6 +10,7 @@
 
   public_deps = [
     "//base",
+    "//mojo/public/cpp/bindings",
     "//services/resource_coordinator/public/cpp",
     "//services/resource_coordinator/public/interfaces",
   ]
@@ -20,12 +21,15 @@
 
   sources = [
     "memory/coordinator/coordinator_impl_unittest.cc",
+    "public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc",
   ]
 
   deps = [
     ":lib",
     "//base",
     "//mojo/public/cpp/bindings",
+    "//services/resource_coordinator/public/cpp",
+    "//services/resource_coordinator/public/interfaces",
     "//testing/gtest",
   ]
 }
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
index 5c133f8..68e6de84b 100644
--- a/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
+++ b/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
@@ -4,14 +4,18 @@
 
 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/lazy_instance.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_request_args.h"
+#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
 #include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
 
 namespace memory_instrumentation {
@@ -24,20 +28,38 @@
 }  // namespace
 
 // static
-CoordinatorImpl* CoordinatorImpl::GetInstance() {
-  return g_coordinator.Pointer();
+CoordinatorImpl* CoordinatorImpl::GetInstance(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  CoordinatorImpl* out = g_coordinator.Pointer();
+  out->Initialize(task_runner);
+  return out;
 }
 
-// TODO(chiniforooshan): Initialize the global MemoryDumpManager instance here.
-// This is how the global MemoryDumpManager gets a reference to the delegate on
-// the service (read the browser) process for service process memory dumps. This
-// can be done when the delegate implementation is landed.
-CoordinatorImpl::CoordinatorImpl() : failed_memory_dump_count_(0) {}
+CoordinatorImpl::CoordinatorImpl()
+    : failed_memory_dump_count_(0), task_runner_(nullptr) {}
 
 CoordinatorImpl::~CoordinatorImpl() {}
 
+void CoordinatorImpl::Initialize(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  DCHECK(!task_runner_ || task_runner_ == task_runner);
+
+  if (!task_runner_) {
+    task_runner_ = task_runner;
+    MemoryDumpManagerDelegateImpl* delegate =
+        MemoryDumpManagerDelegateImpl::GetInstance();
+    delegate->InitializeWithCoordinator(this, task_runner_);
+  }
+}
+
+void CoordinatorImpl::InitializeForTest(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  task_runner_ = task_runner;
+}
+
 void CoordinatorImpl::BindCoordinatorRequest(
     mojom::CoordinatorRequest request) {
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   bindings_.AddBinding(this, std::move(request));
 }
 
@@ -51,8 +73,7 @@
 void CoordinatorImpl::RequestGlobalMemoryDump(
     const base::trace_event::MemoryDumpRequestArgs& args,
     const RequestGlobalMemoryDumpCallback& callback) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
 
   // If this is a periodic memory dump request and there already is another
@@ -87,8 +108,7 @@
 
 void CoordinatorImpl::RegisterProcessLocalDumpManager(
     mojom::ProcessLocalDumpManagerPtr process_manager) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
+  DCHECK(task_runner_->RunsTasksOnCurrentThread());
   process_manager.set_connection_error_handler(
       base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager,
                  base::Unretained(this), process_manager.get()));
@@ -101,7 +121,8 @@
 
 void CoordinatorImpl::UnregisterProcessLocalDumpManager(
     mojom::ProcessLocalDumpManager* process_manager) {
-  DCHECK(process_managers_.erase(process_manager) == 1);
+  size_t num_deleted = process_managers_.erase(process_manager);
+  DCHECK(num_deleted == 1);
 
   // Check if we are waiting for an ack from this process-local manager.
   if (pending_process_managers_.find(process_manager) !=
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl.h b/services/resource_coordinator/memory/coordinator/coordinator_impl.h
index 80ce6ae..69f63cd 100644
--- a/services/resource_coordinator/memory/coordinator/coordinator_impl.h
+++ b/services/resource_coordinator/memory/coordinator/coordinator_impl.h
@@ -11,7 +11,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
@@ -22,13 +22,15 @@
 
 class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
  public:
-  static CoordinatorImpl* GetInstance();
+  static CoordinatorImpl* GetInstance(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   // Coordinator
   void BindCoordinatorRequest(mojom::CoordinatorRequest) override;
 
  private:
-  friend class CoordinatorImplTest;  // For testing
+  friend std::default_delete<CoordinatorImpl>;  // For testing
+  friend class CoordinatorImplTest;             // For testing
   friend struct base::DefaultLazyInstanceTraits<CoordinatorImpl>;
 
   struct QueuedMemoryDumpRequest {
@@ -42,6 +44,10 @@
   CoordinatorImpl();
   ~CoordinatorImpl() override;
 
+  void Initialize(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  void InitializeForTest(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
   // mojom::Coordinator
   void RegisterProcessLocalDumpManager(
       mojom::ProcessLocalDumpManagerPtr process_manager) override;
@@ -78,7 +84,7 @@
   int failed_memory_dump_count_;
   std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_;
 
-  base::ThreadChecker thread_checker_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl);
 };
diff --git a/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc b/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
index 1bc8254..4d63e98 100644
--- a/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
+++ b/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
@@ -20,15 +21,20 @@
  public:
   CoordinatorImplTest() {}
   void SetUp() override {
-    dump_response_args_ = {static_cast<uint64_t>(-1), false};
+    dump_response_args_ = {0U, false};
+    coordinator_.reset(new CoordinatorImpl());
+    coordinator_->InitializeForTest(base::ThreadTaskRunnerHandle::Get());
   }
 
+  void TearDown() override { coordinator_.reset(); }
+
   void RegisterProcessLocalDumpManager(
       mojom::ProcessLocalDumpManagerPtr process_manager) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager,
-                              base::Unretained(&coordinator_),
-                              base::Passed(&process_manager)));
+        FROM_HERE,
+        base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager,
+                   base::Unretained(coordinator_.get()),
+                   base::Passed(&process_manager)));
   }
 
   void RequestGlobalMemoryDump(base::trace_event::MemoryDumpRequestArgs args,
@@ -36,7 +42,7 @@
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(&CoordinatorImpl::RequestGlobalMemoryDump,
-                   base::Unretained(&coordinator_), args,
+                   base::Unretained(coordinator_.get()), args,
                    base::Bind(&CoordinatorImplTest::OnGlobalMemoryDumpResponse,
                               base::Unretained(this), closure)));
   }
@@ -57,11 +63,11 @@
   DumpResponseArgs dump_response_args_;
 
  private:
-  CoordinatorImpl coordinator_;
+  std::unique_ptr<CoordinatorImpl> coordinator_;
   base::MessageLoop message_loop_;
 };
 
-class MockDumpManager : mojom::ProcessLocalDumpManager {
+class MockDumpManager : public mojom::ProcessLocalDumpManager {
  public:
   MockDumpManager(CoordinatorImplTest* test_coordinator, int expected_calls)
       : binding_(this), expected_calls_(expected_calls) {
@@ -93,7 +99,7 @@
       base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
   RequestGlobalMemoryDump(args, run_loop.QuitClosure());
   run_loop.Run();
-  EXPECT_EQ(static_cast<uint64_t>(1234), dump_response_args_.dump_guid);
+  EXPECT_EQ(1234U, dump_response_args_.dump_guid);
   EXPECT_TRUE(dump_response_args_.success);
 }
 
@@ -109,7 +115,7 @@
 
   run_loop.Run();
 
-  EXPECT_EQ(static_cast<uint64_t>(2345), dump_response_args_.dump_guid);
+  EXPECT_EQ(2345U, dump_response_args_.dump_guid);
   EXPECT_TRUE(dump_response_args_.success);
 }
 
@@ -132,7 +138,7 @@
 
   run_loop.Run();
 
-  EXPECT_EQ(static_cast<uint64_t>(3456), dump_response_args_.dump_guid);
+  EXPECT_EQ(3456U, dump_response_args_.dump_guid);
   EXPECT_FALSE(dump_response_args_.success);
 }
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
index 7072b67..1057794 100644
--- a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
+++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
@@ -4,6 +4,11 @@
 
 #include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "services/resource_coordinator/public/cpp/memory/coordinator.h"
@@ -12,26 +17,68 @@
 
 namespace memory_instrumentation {
 
-MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl(
-    service_manager::InterfaceProvider* interface_provider)
-    : is_coordinator_(false), binding_(this) {
-  interface_provider->GetInterface(mojo::MakeRequest(&coordinator_));
-  coordinator_->RegisterProcessLocalDumpManager(
-      binding_.CreateInterfacePtrAndBind());
+namespace {
+
+base::LazyInstance<MemoryDumpManagerDelegateImpl>::Leaky
+    g_memory_dump_manager_delegate = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+MemoryDumpManagerDelegateImpl* MemoryDumpManagerDelegateImpl::GetInstance() {
+  return g_memory_dump_manager_delegate.Pointer();
 }
 
-MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl(
-    Coordinator* coordinator)
-    : is_coordinator_(true), binding_(this) {
-  coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_));
-  coordinator_->RegisterProcessLocalDumpManager(
-      binding_.CreateInterfacePtrAndBind());
-}
+MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl()
+    : initialized_(false),
+      binding_(this),
+      task_runner_(nullptr),
+      pending_memory_dump_guid_(0) {}
 
 MemoryDumpManagerDelegateImpl::~MemoryDumpManagerDelegateImpl() {}
 
+void MemoryDumpManagerDelegateImpl::InitializeWithInterfaceProvider(
+    service_manager::InterfaceProvider* interface_provider) {
+  {
+    base::AutoLock lock(initialized_lock_);
+    DCHECK(!initialized_);
+    initialized_ = true;
+  }
+
+  interface_provider->GetInterface(mojo::MakeRequest(&coordinator_));
+  coordinator_->RegisterProcessLocalDumpManager(
+      binding_.CreateInterfacePtrAndBind());
+  base::trace_event::MemoryDumpManager::GetInstance()->Initialize(this);
+}
+
+void MemoryDumpManagerDelegateImpl::InitializeWithCoordinator(
+    Coordinator* coordinator,
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+  DCHECK(task_runner);
+  if (!task_runner->RunsTasksOnCurrentThread()) {
+    task_runner->PostTask(
+        FROM_HERE,
+        base::Bind(&MemoryDumpManagerDelegateImpl::InitializeWithCoordinator,
+                   base::Unretained(this), base::Unretained(coordinator),
+                   task_runner));
+    return;
+  }
+
+  {
+    base::AutoLock lock(initialized_lock_);
+    DCHECK(!initialized_);
+    initialized_ = true;
+  }
+
+  task_runner_ = task_runner;
+  coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_));
+  coordinator_->RegisterProcessLocalDumpManager(
+      binding_.CreateInterfacePtrAndBind());
+  base::trace_event::MemoryDumpManager::GetInstance()->Initialize(this);
+}
+
 bool MemoryDumpManagerDelegateImpl::IsCoordinator() const {
-  return is_coordinator_;
+  return task_runner_ != nullptr;
 }
 
 void MemoryDumpManagerDelegateImpl::RequestProcessMemoryDump(
@@ -43,7 +90,50 @@
 void MemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
     const base::trace_event::MemoryDumpRequestArgs& args,
     const base::trace_event::MemoryDumpCallback& callback) {
-  coordinator_->RequestGlobalMemoryDump(args, callback);
+  // Note: This condition is here to match the old behavior. If the delegate is
+  // in the browser process, we do not drop parallel requests in the delegate
+  // and so they will be queued by the Coordinator service (see
+  // CoordinatorImpl::RequestGlobalMemoryDump). If the delegate is in a child
+  // process, parallel requests will be cancelled.
+  //
+  // TODO(chiniforooshan): After transitioning to the mojo-based service is
+  // completed, we should enable queueing parallel global memory dump requests
+  // by delegates on all processes.
+  if (task_runner_) {
+    DCHECK(task_runner_);
+    task_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(&mojom::Coordinator::RequestGlobalMemoryDump,
+                   base::Unretained(coordinator_.get()), args, callback));
+    return;
+  }
+
+  {
+    base::AutoLock lock(pending_memory_dump_guid_lock_);
+    if (pending_memory_dump_guid_) {
+      callback.Run(args.dump_guid, false);
+      return;
+    }
+    pending_memory_dump_guid_ = args.dump_guid;
+  }
+  DCHECK(!task_runner_);
+  auto callback_proxy =
+      base::Bind(&MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy,
+                 base::Unretained(this), callback);
+  coordinator_->RequestGlobalMemoryDump(args, callback_proxy);
+}
+
+void MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy(
+    const base::trace_event::MemoryDumpCallback& callback,
+    uint64_t dump_guid,
+    bool success) {
+  DCHECK_NE(0U, pending_memory_dump_guid_);
+  pending_memory_dump_guid_ = 0;
+  callback.Run(dump_guid, success);
+}
+
+void MemoryDumpManagerDelegateImpl::SetAsNonCoordinatorForTesting() {
+  task_runner_ = nullptr;
 }
 
 }  // namespace memory_instrumentation
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
index 1176619..0986e22 100644
--- a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
+++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
@@ -5,6 +5,9 @@
 #ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
 #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
 
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -18,30 +21,56 @@
     : public base::trace_event::MemoryDumpManagerDelegate,
       public mojom::ProcessLocalDumpManager {
  public:
+  static MemoryDumpManagerDelegateImpl* GetInstance();
+
   // Use to bind to a remote coordinator.
-  MemoryDumpManagerDelegateImpl(
+  void InitializeWithInterfaceProvider(
       service_manager::InterfaceProvider* interface_provider);
 
   // Use to bind to a coordinator in the same process.
-  MemoryDumpManagerDelegateImpl(Coordinator* coordinator);
-  ~MemoryDumpManagerDelegateImpl() override;
+  void InitializeWithCoordinator(
+      Coordinator* coordinator,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
-  bool IsCoordinator() const;
+  bool IsCoordinator() const override;
 
   // The base::trace_event::MemoryDumpManager calls this.
   void RequestGlobalMemoryDump(
       const base::trace_event::MemoryDumpRequestArgs& args,
       const base::trace_event::MemoryDumpCallback& callback) override;
 
+  void SetAsNonCoordinatorForTesting();
+
  private:
+  friend std::default_delete<MemoryDumpManagerDelegateImpl>;  // For testing
+  friend class MemoryDumpManagerDelegateImplTest;             // For testing
+  friend struct base::DefaultLazyInstanceTraits<MemoryDumpManagerDelegateImpl>;
+
+  MemoryDumpManagerDelegateImpl();
+  ~MemoryDumpManagerDelegateImpl() override;
+
   // The ProcessLocalDumpManager interface. The coordinator calls this.
   void RequestProcessMemoryDump(
       const base::trace_event::MemoryDumpRequestArgs& args,
       const RequestProcessMemoryDumpCallback& callback) override;
 
-  bool is_coordinator_;
+  // A proxy callback for updating |pending_memory_dump_guid_|.
+  void MemoryDumpCallbackProxy(
+      const base::trace_event::MemoryDumpCallback& callback,
+      uint64_t dump_guid,
+      bool success);
+
+  bool initialized_;
   mojom::CoordinatorPtr coordinator_;
   mojo::Binding<mojom::ProcessLocalDumpManager> binding_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  uint64_t pending_memory_dump_guid_;
+
+  // Prevents racy access to |pending_memory_dump_guid_|.
+  base::Lock pending_memory_dump_guid_lock_;
+
+  // Prevents racy access to |initialized_|.
+  base::Lock initialized_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegateImpl);
 };
diff --git a/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc
new file mode 100644
index 0000000..09a712b
--- /dev/null
+++ b/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc
@@ -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.
+
+#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_log.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/resource_coordinator/public/cpp/memory/coordinator.h"
+#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::trace_event::MemoryDumpLevelOfDetail;
+using base::trace_event::MemoryDumpManager;
+using base::trace_event::MemoryDumpType;
+
+namespace memory_instrumentation {
+
+class MockCoordinator : public Coordinator, public mojom::Coordinator {
+ public:
+  void BindCoordinatorRequest(mojom::CoordinatorRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  void RegisterProcessLocalDumpManager(
+      mojom::ProcessLocalDumpManagerPtr process_manager) override {}
+
+  void RequestGlobalMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const RequestGlobalMemoryDumpCallback& callback) override {
+    callback.Run(args.dump_guid, true);
+  }
+
+ private:
+  mojo::BindingSet<mojom::Coordinator> bindings_;
+};
+
+class MemoryDumpManagerDelegateImplTest : public testing::Test {
+ public:
+  void SetUp() override {
+    message_loop_.reset(new base::MessageLoop());
+    coordinator_.reset(new MockCoordinator());
+    delegate_.reset(new MemoryDumpManagerDelegateImpl());
+    mdm_.reset(new MemoryDumpManager());
+    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+
+    // This will initialize |MemoryDumpManager|, too.
+    delegate_->InitializeWithCoordinator(coordinator_.get(),
+                                         base::ThreadTaskRunnerHandle::Get());
+    delegate_->SetAsNonCoordinatorForTesting();
+
+    // Enable tracing.
+    std::string category_filter = "-*,";
+    category_filter += MemoryDumpManager::kTraceCategory;
+    base::trace_event::TraceConfig trace_config(category_filter, "");
+    base::trace_event::TraceLog::GetInstance()->SetEnabled(
+        trace_config, base::trace_event::TraceLog::RECORDING_MODE);
+
+    // Reset the counters.
+    expected_callback_calls_ = 0;
+    dump_requests_received_by_coordinator_ = 0;
+    quit_closure_.Reset();
+  }
+
+  void TearDown() override {
+    base::trace_event::TraceLog::GetInstance()->SetDisabled();
+    MemoryDumpManager::SetInstanceForTesting(nullptr);
+    mdm_.reset();
+    delegate_.reset();
+    coordinator_.reset();
+    message_loop_.reset();
+  }
+
+  void OnGlobalMemoryDumpDone(int more_requests,
+                              uint64_t dump_guid,
+                              bool success) {
+    EXPECT_GT(expected_callback_calls_, 0);
+    EXPECT_FALSE(quit_closure_.is_null());
+
+    dump_requests_received_by_coordinator_ += success ? 1 : 0;
+    expected_callback_calls_--;
+    if (expected_callback_calls_ == 0)
+      quit_closure_.Run();
+
+    if (more_requests > 0)
+      SequentiallyRequestGlobalDumps(more_requests);
+  }
+
+  void SequentiallyRequestGlobalDumps(int num_requests) {
+    MemoryDumpManager::GetInstance()->RequestGlobalDump(
+        MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::LIGHT,
+        base::Bind(&MemoryDumpManagerDelegateImplTest::OnGlobalMemoryDumpDone,
+                   base::Unretained(this), num_requests - 1));
+  }
+
+  int expected_callback_calls_;
+  int dump_requests_received_by_coordinator_;
+  base::Closure quit_closure_;
+
+ private:
+  std::unique_ptr<base::MessageLoop> message_loop_;
+  std::unique_ptr<MockCoordinator> coordinator_;
+  std::unique_ptr<MemoryDumpManagerDelegateImpl> delegate_;
+  std::unique_ptr<MemoryDumpManager> mdm_;
+};
+
+// Makes several global dump requests each after receiving the ACK for the
+// previous one. There should be no throttling and all requests should be
+// forwarded to the coordinator.
+TEST_F(MemoryDumpManagerDelegateImplTest, NonOverlappingMemoryDumpRequests) {
+  base::RunLoop run_loop;
+  expected_callback_calls_ = 3;
+  quit_closure_ = run_loop.QuitClosure();
+  SequentiallyRequestGlobalDumps(3);
+  run_loop.Run();
+  EXPECT_EQ(3, dump_requests_received_by_coordinator_);
+}
+
+// Makes several global dump requests without waiting for previous requests to
+// finish. Only the first request should make it to the coordinator. The rest
+// should be cancelled.
+TEST_F(MemoryDumpManagerDelegateImplTest, OverlappingMemoryDumpRequests) {
+  base::RunLoop run_loop;
+  expected_callback_calls_ = 3;
+  quit_closure_ = run_loop.QuitClosure();
+  SequentiallyRequestGlobalDumps(1);
+  SequentiallyRequestGlobalDumps(1);
+  SequentiallyRequestGlobalDumps(1);
+  run_loop.Run();
+  EXPECT_EQ(1, dump_requests_received_by_coordinator_);
+}
+
+}  // namespace memory_instrumentation
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 0955f5ce..49eb5d9a 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -840,21 +840,22 @@
 crbug.com/567965 [ Debug ] external/wpt/user-timing/test_user_timing_mark.html [ Skip ]
 crbug.com/518993 external/wpt/user-timing/test_user_timing_measure_navigation_timing.html [ Skip ]
 
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/scrollbars-changed.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-columns-repaint.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/repaint.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-row-repaint.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-rows-repaint.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/button-reset-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/range-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ NeedsManualRebaseline ]
-crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ NeedsManualRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/scrollbars-changed.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-columns-repaint.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-collapse-to-separate.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/flexbox/repaint.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-row-repaint.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/css-grid-layout/grid-element-change-rows-repaint.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-percent-size-cell.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/border-collapse-change-separate-to-collapse.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/compositing/should-not-repaint-composited-descendants.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/button-reset-focus-by-mouse-then-keydown.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/range-focus-by-mouse-then-keydown.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ NeedsRebaseline ]
+crbug.com/676748 virtual/disable-spinvalidation/paint/invalidation/table/resize-table-repaint-vertical-align-cell.html [ NeedsRebaseline ]
+crbug.com/696398 virtual/disable-spinvalidation/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ NeedsRebaseline ]
 
 crbug.com/636053 [ Mac Win ] printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ]
 crbug.com/636053 [ Mac Win ] virtual/threaded/printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ NeedsManualRebaseline ]
@@ -2562,7 +2563,6 @@
 crbug.com/695352 [ Mac ] virtual/threaded/compositing/visibility/overlays-persist-on-navigation.html [ Pass Crash ]
 
 # Sheriff failures 2017-02-27
-crbug.com/696398 [ Win7 ] virtual/disable-spinvalidation/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ Failure ]
 crbug.com/696407 [ Linux ] external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-with-colon.sub.html [ Failure Pass ]
 crbug.com/694338 [ Mac10.9 ] fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Failure ]
 crbug.com/694338 [ Mac10.9 ] fast/forms/calendar-picker/calendar-picker-appearance-zoom200.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt
deleted file mode 100644
index d8f83e3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/change-context-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This test ensures that changing the context does not crash. 
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/change-context.html b/third_party/WebKit/LayoutTests/fast/canvas/change-context.html
index 9e24759..675742dc 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/change-context.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/change-context.html
@@ -1,19 +1,22 @@
-This test ensures that changing the context does not crash.
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <canvas id="canvas"></canvas><br />
+
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+test(function(t) {
 
-var canvas = document.getElementById("canvas");
-var ctx1 = canvas.getContext("2d");
-var ctx2 = canvas.getContext("");
-ctx1.save();
-
-canvas.parentNode.removeChild(canvas);
-
-if (window.GCController)
-    GCController.collect();
+    var canvas = document.getElementById("canvas");
+    var ctx1 = canvas.getContext("2d");
+    var ctx2 = canvas.getContext("");
+    ctx1.save();
     
-ctx1.save();
-
+    canvas.parentNode.removeChild(canvas);
+    
+    if (window.GCController)
+        GCController.collect();
+        
+    ctx1.save();
+    
+}, 'This test ensures that changing the context does not crash.');
 </script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt
deleted file mode 100644
index d7fa08a7..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'..
-PASS canvas.drawFocusIfNeeded(); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': 1 argument required, but only 0 present..
-PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'..
-PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true
-PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt
deleted file mode 100644
index 909dda9..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-This test passes by not crashing.
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html
index 314268f..87f2362 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-invisible-crash.html
@@ -1,17 +1,20 @@
-<!DOCTYPE HTML>
-<p>This test passes by not crashing.</p>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+    
 <canvas id="canvas">
     <button id="button"></button>
 </canvas>
-<script>
-if (window.testRunner)
-    testRunner.dumpAsText();
 
-var button = document.getElementById("button");
-button.focus();
-var canvas = document.getElementById("canvas")
-var ctx = canvas.getContext("2d");
-ctx.rect(0, 0, 10, 10);
-canvas.style.display = "none";
-ctx.drawFocusIfNeeded(button);
-</script>
+<script>
+test(function(t) {
+
+    var button = document.getElementById("button");
+    button.focus();
+    var canvas = document.getElementById("canvas")
+    var ctx = canvas.getContext("2d");
+    ctx.rect(0, 0, 10, 10);
+    canvas.style.display = "none";
+    ctx.drawFocusIfNeeded(button);
+    
+}, 'Test that drawFocusIfNeeded does not crash.');
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt
deleted file mode 100644
index 2a5eb81d..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true
-PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html
index aef285b0..6fcf15d 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-on-event.html
@@ -1,17 +1,10 @@
-<!DOCTYPE HTML>
-<head>
-<title>Canvas test: drawFocusIfNeeded</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body style="padding: 0; margin: 0">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <canvas id="canvas" class="output" width="300" height="350">
     <button id="button1"></button>
     <button id="button2"></button>
 </canvas>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
-
 var canvas = document.getElementById("canvas").getContext("2d");
 
 document.getElementById("button1").addEventListener('focus', function() {
@@ -28,17 +21,21 @@
     canvas.drawFocusIfNeeded(document.getElementById("button2"));
 });
 
-document.getElementById("button1").focus();
+test(function(t) {
 
-// The top rect's focus ring is tied to button1, which is focused.
-// It should have an outline in some color other than the background color.
-var imageData = canvas.getImageData(49, 50, 1, 1);
-var data = imageData.data;
-shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true");
-
-// The bottom rect"s focus ring is tied to button2, which is not focused.
-imageData = canvas.getImageData(49, 200, 1, 1);
-data = imageData.data;
-shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true");
+    document.getElementById("button1").focus();
+    
+    // The top rect's focus ring is tied to button1, which is focused.
+    // It should have an outline in some color other than the background color.
+    var imageData = canvas.getImageData(49, 50, 1, 1);
+    var data = imageData.data;
+    assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0);
+    
+    // The bottom rect"s focus ring is tied to button2, which is not focused.
+    imageData = canvas.getImageData(49, 200, 1, 1);
+    data = imageData.data;
+    assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0);
+    
+}, 'Test that drawFocusIfNeeded does not crash on event.');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt
deleted file mode 100644
index 3f1cc39..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-PASS window.pageXOffset is 0
-PASS window.pageXOffset is >= minXOffset
-PASS maxXOffset is >= window.pageXOffset
-PASS window.pageXOffset is >= minXOffset
-PASS maxXOffset is >= window.pageXOffset
-PASS window.pageXOffset is >= minXOffset
-PASS maxXOffset is >= window.pageXOffset
-PASS successfullyParsed is true
-
-TEST COMPLETE
-1000-pixel box
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html
index 46a66d9..3e8ffe0 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-scrolls-horiz.html
@@ -1,9 +1,6 @@
-<!DOCTYPE HTML>
-<head>
-<title>Canvas test: drawFocusIfNeeded scrolls</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body style="padding: 0; margin: 0">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <div style="width: 6500px;">
   <div style="float: left; border: 1px solid #000; width: 1000px; height: 300px">
       1000-pixel box
@@ -13,49 +10,50 @@
       <button id="right_button"></button>
   </canvas>
 </div>
+
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+test(function(t) {
 
-var canvas = document.getElementById("canvas");
-var context = canvas.getContext("2d");
+    var canvas = document.getElementById("canvas");
+    var context = canvas.getContext("2d");
+  
+    var LEFT_BUTTON_X_POS = 50;
+    var RIGHT_BUTTON_X_POS = 4750;
 
-var LEFT_BUTTON_X_POS = 50;
-var RIGHT_BUTTON_X_POS = 4750;
+    function draw() {
+        context.beginPath();
+        context.rect(LEFT_BUTTON_X_POS, 50, 200, 100);
+        context.fillStyle = "#ccf";
+        context.fill();
+        context.drawFocusIfNeeded(document.getElementById("left_button"));
+    
+        context.beginPath();
+        context.rect(RIGHT_BUTTON_X_POS, 50, 200, 100);
+        context.fillStyle = "#fcc";
+        context.fill();
+        context.drawFocusIfNeeded(document.getElementById("right_button"));
+    }
 
-function draw() {
-    context.beginPath();
-    context.rect(LEFT_BUTTON_X_POS, 50, 200, 100);
-    context.fillStyle = "#ccf";
-    context.fill();
-    context.drawFocusIfNeeded(document.getElementById("left_button"));
+    document.getElementById("right_button").focus();
+    window.scrollTo(0, 0);
+    assert_true(window.pageXOffset == 0);
+    draw();
 
-    context.beginPath();
-    context.rect(RIGHT_BUTTON_X_POS, 50, 200, 100);
-    context.fillStyle = "#fcc";
-    context.fill();
-    context.drawFocusIfNeeded(document.getElementById("right_button"));
-}
+    var minXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth;
+    var maxXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft;
+    assert_true(window.pageXOffset >= minXOffset);
+    assert_true(maxXOffset >= window.pageXOffset);
 
-document.getElementById("right_button").focus();
-window.scrollTo(0, 0);
-shouldBe("window.pageXOffset", "0");
-draw();
+    document.getElementById("left_button").focus();
+    assert_true(window.pageXOffset >= minXOffset);
+    assert_true(maxXOffset >= window.pageXOffset);
 
-var minXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth;
-var maxXOffset = RIGHT_BUTTON_X_POS + canvas.offsetLeft;
-shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset");
-shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset");
+    draw();
+    minXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth;
+    maxXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft;
+    assert_true(window.pageXOffset >= minXOffset);
+    assert_true(maxXOffset >= window.pageXOffset);
 
-document.getElementById("left_button").focus();
-shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset");
-shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset");
-
-draw();
-minXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft - window.innerWidth;
-maxXOffset = LEFT_BUTTON_X_POS + canvas.offsetLeft;
-shouldBeGreaterThanOrEqual("window.pageXOffset", "minXOffset");
-shouldBeGreaterThanOrEqual("maxXOffset", "window.pageXOffset");
-
+}, 'Canvas test: drawFocusIfNeeded scrolls');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt
deleted file mode 100644
index dd990cf..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-PASS canvas.drawFocusIfNeeded(undefined); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'..
-PASS canvas.drawFocusIfNeeded(undefined, undefined); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'..
-PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'..
-PASS canvas.drawFocusIfNeeded(null, null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'..
-PASS canvas.drawFocusIfNeeded(); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': 1 argument required, but only 0 present..
-PASS canvas.drawFocusIfNeeded(null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Element'..
-PASS canvas.drawFocusIfNeeded(null, null); threw exception TypeError: Failed to execute 'drawFocusIfNeeded' on 'CanvasRenderingContext2D': parameter 1 is not of type 'Path2D'..
-PASS data[0] != 0 || data[1] != 0 || data[2] != 0 is true
-PASS data[0] == 0 && data[1] == 0 && data[2] == 0 is true
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html
index 24731b8..479a692 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed-with-path2d.html
@@ -1,51 +1,50 @@
-<!DOCTYPE HTML>
-<head>
-<title>Canvas test: drawFocusIfNeeded with Path2D</title>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body style="padding: 0; margin: 0">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <canvas id="canvas" class="output" width="300" height="350">
     <button id="button1"></button>
     <button id="button2"></button>
 </canvas>
+
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+test(function(t) {
 
-document.getElementById("button1").focus();
-
-var canvas = document.getElementById("canvas").getContext("2d");
-
-shouldThrow('canvas.drawFocusIfNeeded(undefined);');
-shouldThrow('canvas.drawFocusIfNeeded(undefined, undefined);');
-shouldThrow('canvas.drawFocusIfNeeded(null);');
-shouldThrow('canvas.drawFocusIfNeeded(null, null);');
-shouldThrow('canvas.drawFocusIfNeeded();');
-
-var path = new Path2D();
-path.rect(50, 50, 200, 100);
-canvas.fillStyle = "#ccf";
-canvas.fill(path);
-// re-test null case after having defined a path (regression test for crbug.com/353248)
-shouldThrow('canvas.drawFocusIfNeeded(null);');
-shouldThrow('canvas.drawFocusIfNeeded(null, null);');
-canvas.drawFocusIfNeeded(path, document.getElementById("button1"));
-
-path = new Path2D();
-path.rect(50, 200, 200, 100);
-canvas.fillStyle = "#cfc";
-canvas.fill(path);
-canvas.drawFocusIfNeeded(path, document.getElementById("button2"));
-
-// The top rect"s focus ring is tied to button1, which is focused.
-// It should have an outline in some color other than the background color.
-var imageData = canvas.getImageData(49, 50, 1, 1);
-var data = imageData.data;
-shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true");
-
-// The bottom rect"s focus ring is tied to button2, which is not focused.
-imageData = canvas.getImageData(49, 200, 1, 1);
-data = imageData.data;
-shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true");
+    document.getElementById("button1").focus();
+    
+    var canvas = document.getElementById("canvas").getContext("2d");
+    
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(undefined);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(undefined, undefined);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null, null);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded();});
+    
+    var path = new Path2D();
+    path.rect(50, 50, 200, 100);
+    canvas.fillStyle = "#ccf";
+    canvas.fill(path);
+    // re-test null case after having defined a path (regression test for crbug.com/353248)
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null, null);});
+    canvas.drawFocusIfNeeded(path, document.getElementById("button1"));
+    
+    path = new Path2D();
+    path.rect(50, 200, 200, 100);
+    canvas.fillStyle = "#cfc";
+    canvas.fill(path);
+    canvas.drawFocusIfNeeded(path, document.getElementById("button2"));
+    
+    // The top rect"s focus ring is tied to button1, which is focused.
+    // It should have an outline in some color other than the background color.
+    var imageData = canvas.getImageData(49, 50, 1, 1);
+    var data = imageData.data;
+    assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0);
+    
+    // The bottom rect"s focus ring is tied to button2, which is not focused.
+    imageData = canvas.getImageData(49, 200, 1, 1);
+    data = imageData.data;
+    assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0);
+    
+}, 'Canvas test: drawFocusIfNeeded with Path2D');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html
index 8bfb2ea3..394f4b9 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/draw-focus-if-needed.html
@@ -1,47 +1,47 @@
 <!DOCTYPE HTML>
 <head>
-<title>Canvas test: drawFocusIfNeeded</title>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 </head>
-<body style="padding: 0; margin: 0">
 <canvas id="canvas" class="output" width="300" height="350">
     <button id="button1"></button>
     <button id="button2"></button>
 </canvas>
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+test(function(t) {
 
-document.getElementById("button1").focus();
-
-var canvas = document.getElementById("canvas").getContext("2d");
-
-shouldThrow('canvas.drawFocusIfNeeded(null);');
-shouldThrow('canvas.drawFocusIfNeeded();');
-
-canvas.beginPath();
-canvas.rect(50, 50, 200, 100);
-canvas.fillStyle = "#ccf";
-canvas.fill();
-// re-test null case after having defined a path (regression test for crbug.com/353248)
-shouldThrow('canvas.drawFocusIfNeeded(null);');
-canvas.drawFocusIfNeeded(document.getElementById("button1"));
-
-canvas.beginPath();
-canvas.rect(50, 200, 200, 100);
-canvas.fillStyle = "#cfc";
-canvas.fill();
-canvas.drawFocusIfNeeded(document.getElementById("button2"));
-
-// The top rect"s focus ring is tied to button1, which is focused.
-// It should have an outline in some color other than the background color.
-var imageData = canvas.getImageData(49, 50, 1, 1);
-var data = imageData.data;
-shouldBe("data[0] != 0 || data[1] != 0 || data[2] != 0", "true");
-
-// The bottom rect"s focus ring is tied to button2, which is not focused.
-imageData = canvas.getImageData(49, 200, 1, 1);
-data = imageData.data;
-shouldBe("data[0] == 0 && data[1] == 0 && data[2] == 0", "true");
+    document.getElementById("button1").focus();
+    
+    var canvas = document.getElementById("canvas").getContext("2d");
+    
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null);});
+    assert_throws(null, function(){canvas.drawFocusIfNeeded();});
+    
+    canvas.beginPath();
+    canvas.rect(50, 50, 200, 100);
+    canvas.fillStyle = "#ccf";
+    canvas.fill();
+    // re-test null case after having defined a path (regression test for crbug.com/353248)
+    assert_throws(null, function(){canvas.drawFocusIfNeeded(null);});
+    canvas.drawFocusIfNeeded(document.getElementById("button1"));
+    
+    canvas.beginPath();
+    canvas.rect(50, 200, 200, 100);
+    canvas.fillStyle = "#cfc";
+    canvas.fill();
+    canvas.drawFocusIfNeeded(document.getElementById("button2"));
+    
+    // The top rect's focus ring is tied to button1, which is focused.
+    // It should have an outline in some color other than the background color.
+    var imageData = canvas.getImageData(49, 50, 1, 1);
+    var data = imageData.data;
+    assert_true(data[0] != 0 || data[1] != 0 || data[2] != 0);
+    
+    // The bottom rect"s focus ring is tied to button2, which is not focused.
+    imageData = canvas.getImageData(49, 200, 1, 1);
+    data = imageData.data;
+    assert_true(data[0] == 0 && data[1] == 0 && data[2] == 0);
+    
+}, 'Canvas test: drawFocusIfNeeded');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt
deleted file mode 100644
index feb6b5c..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas-expected.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html
index 9b30429..d191d4e0 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-bad-canvas.html
@@ -1,10 +1,9 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <script>
-    description("This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing.");
+test(function(){
+
     var canvas1 = document.createElement("canvas");
     var ctx1 = canvas1.getContext('2d');
     var canvas2 = document.createElement("canvas");
@@ -13,6 +12,6 @@
     canvas2.height = 1000000;
     var ctx2 = canvas2.getContext('2d');
     ctx2.drawImage(canvas1, 0, 0);
+
+}, "This test checks behavior of drawImage on a canvas that failed to allocate its backing store. This test passes by not crashing.");
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt
deleted file mode 100644
index 33ea039e..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-This test checks behavior of Canvas::drawImage with a broken source image.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS ctx.drawImage(null, 0, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(null, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(undefined, 0, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(undefined, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'.
-PASS ctx.drawImage(invalidImage, 0, 0) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state..
-PASS ctx.drawImage(invalidImage, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state..
-PASS ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state..
-PASS ctx.drawImage(invalidImage, 0, 0, 0, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state..
-PASS ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20) threw exception InvalidStateError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html
index afb0f143..16d4500 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-broken-image.html
@@ -1,36 +1,37 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <script>
-    window.jsTestIsAsync = true;
-    description("This test checks behavior of Canvas::drawImage with a broken source image.");
 
-    // Create an image with invalid data.
-    var invalidImage = new Image();
-    invalidImage.src = 'resources/shadow-offset.js';
-    invalidImage.onerror = draw;
+// Create an image with invalid data.
+var invalidImage = new Image();
+invalidImage.src = 'resources/shadow-offset.js';
 
-    var ctx = document.createElement("canvas").getContext('2d');
-    function draw() {
-        // null and undefined images should throw TypeError
-        shouldThrow("ctx.drawImage(null, 0, 0)");
-        shouldThrow("ctx.drawImage(null, 0, 0, 20, 20)");
-        shouldThrow("ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20)");
-        shouldThrow("ctx.drawImage(undefined, 0, 0)");
-        shouldThrow("ctx.drawImage(undefined, 0, 0, 20, 20)");
-        shouldThrow("ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20)");
+var ctx = document.createElement("canvas").getContext('2d');
+function draw() {
+    // null and undefined images should throw TypeError
+    assert_throws(null, function() {ctx.drawImage(null, 0, 0)});
+    assert_throws(null, function() {ctx.drawImage(null, 0, 0, 20, 20)});
+    assert_throws(null, function() {ctx.drawImage(null, 0, 0, 20, 20, 0, 0, 20, 20)});
+    assert_throws(null, function() {ctx.drawImage(undefined, 0, 0)});
+    assert_throws(null, function() {ctx.drawImage(undefined, 0, 0, 20, 20)});
+    assert_throws(null, function() {ctx.drawImage(undefined, 0, 0, 20, 20, 0, 0, 20, 20)});
 
-        // broken images should not throw
-        shouldThrow("ctx.drawImage(invalidImage, 0, 0)");
-        shouldThrow("ctx.drawImage(invalidImage, 0, 0, 20, 20)");
-        shouldThrow("ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20)");
-        shouldThrow("ctx.drawImage(invalidImage, 0, 0, 0, 20)");
-        shouldThrow("ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20)");
+    // broken images should not throw
+    assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0)});
+    assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 20, 20)});
+    assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 20, 20, 0, 0, 20, 20)});
+    assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 0, 20)});
+    assert_throws(null, function() {ctx.drawImage(invalidImage, 0, 0, 0, 20, 0, 0, 20, 20)});
+}
+    
+async_test(t => {
+        invalidImage.onerror = function() {
+            t.step(draw);
+            t.done();
+        }
+}, "This test checks behavior of Canvas::drawImage with a broken source image.");
 
-        finishJSTest();
-    }
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt
deleted file mode 100644
index f41ac92..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imgdata[4] is 0
-PASS imgdata[5] is 255
-PASS imgdata[6] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[4] is 0
-PASS imgdata[5] is 0
-PASS imgdata[6] is 0
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html
index ad0dbc6..3d866ef 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.html
@@ -1,13 +1,38 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
 <!-- Test based on that found at 
      http://philip.html5.org/tests/canvas/suite/tests/2d.drawImage.negativesource.html
   -->
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <canvas id="canvas" width="100" height="100"></canvas>
-<script src="drawImage-with-negative-source-destination.js"></script>
-</body>
-</html>
+<script>
+
+test(function(){
+
+    var canvas2 = document.createElement('canvas');
+    canvas2.width = 100;
+    canvas2.height = 100;
+    var ctx2 = canvas2.getContext('2d');
+    ctx2.fillStyle = '#f00';
+    ctx2.fillRect(0, 0, 100, 50);
+    ctx2.fillStyle = '#0f0';
+    ctx2.fillRect(0, 50, 100, 50);
+    
+    var canvas = document.getElementById('canvas').getContext('2d');
+    canvas.drawImage(canvas2, 100, 50, -50, 50, 0, 0, 50, 50);
+    canvas.drawImage(canvas2, 100, 100, -50, -50, 0, 100, 50, -50);
+    canvas.drawImage(canvas2, 0, 100, 100, -50, 100, 100, -50, -50);
+    canvas.drawImage(canvas2, 0, 50, 100, 50, 100, 0, -50, 50);
+    
+    var imageData = canvas.getImageData(1, 0, 1, 1).data;
+    assert_array_equals(imageData.slice(0,3), [0, 255, 0]);
+    
+    // test width or height -1
+    canvas.fillStyle = '#000';
+    canvas.fillRect(0, 0, 1, 2);
+    canvas.drawImage(canvas2, 0, 0, 1, 1, 1, 1, -1, -1);
+    var imageData = canvas.getImageData(0, 0, 1, 2).data;
+    assert_array_equals(imageData.slice(0,3), [255, 0, 0]);
+    assert_array_equals(imageData.slice(4,7), [0, 0, 0]);
+
+}, "Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js
deleted file mode 100644
index 671fd73b..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-negative-source-destination.js
+++ /dev/null
@@ -1,34 +0,0 @@
-description("Series of tests to ensure correct behaviour on negative source/destination of a HTMLCanvasElement");
-var canvas2 = document.createElement('canvas');
-canvas2.width = 100;
-canvas2.height = 100;
-var ctx2 = canvas2.getContext('2d');
-ctx2.fillStyle = '#f00';
-ctx2.fillRect(0, 0, 100, 50);
-ctx2.fillStyle = '#0f0';
-ctx2.fillRect(0, 50, 100, 50);
-
-var canvas = document.getElementById('canvas').getContext('2d');
-canvas.drawImage(canvas2, 100, 50, -50, 50, 0, 0, 50, 50);
-canvas.drawImage(canvas2, 100, 100, -50, -50, 0, 100, 50, -50);
-canvas.drawImage(canvas2, 0, 100, 100, -50, 100, 100, -50, -50);
-canvas.drawImage(canvas2, 0, 50, 100, 50, 100, 0, -50, 50);
-
-var imageData = canvas.getImageData(0, 0, 100, 100);
-var imgdata = imageData.data;
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "255");
-shouldBe("imgdata[6]", "0");
-
-// test width or height -1
-canvas.fillStyle = '#000';
-canvas.fillRect(0, 0, 1, 2);
-canvas.drawImage(canvas2, 0, 0, 1, 1, 1, 1, -1, -1);
-var imageData = canvas.getImageData(0, 0, 1, 2);
-var imgdata = imageData.data;
-shouldBe("imgdata[0]", "255");
-shouldBe("imgdata[1]", "0");
-shouldBe("imgdata[2]", "0");
-shouldBe("imgdata[4]", "0");
-shouldBe("imgdata[5]", "0");
-shouldBe("imgdata[6]", "0");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt
deleted file mode 100644
index a319f0f..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image-expected.txt
+++ /dev/null
@@ -1,51 +0,0 @@
-This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS ctx.drawImage() threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 0 present..
-PASS ctx.drawImage(myImage) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 1 present..
-PASS ctx.drawImage(myImage, 0) threw exception TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only 2 present..
-PASS ctx.drawImage(myImage, 0, 0) did not throw exception.
-PASS ctx.drawImage(myImage, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 0, 0, 0, 0) did not throw exception.
-PASS ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0) did not throw exception.
-PASS ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0, 0, 20) did not throw exception.
-PASS ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0, 0, 0) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0) did not throw exception.
-PASS ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20) did not throw exception.
-PASS ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20) did not throw exception.
-PASS ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20) did not throw exception.
-PASS ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20) did not throw exception.
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html
index b05a4963..fb1c9a6 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/drawImage-with-valid-image.html
@@ -1,155 +1,153 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <script>
-    window.jsTestIsAsync = true;
-    description("This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image.");
 
-    function ExpectedNotEnoughArgumentsMessage(num) {
-        return "\"TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only " + num + " present.\"";
-    }
-    var IndexSizeError = "IndexSizeError: Index or size was negative, or greater than the allowed value.";
+function ExpectedNotEnoughArgumentsMessage(num) {
+    return "\"TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': 3 arguments required, but only " + num + " present.\"";
+}
 
-    // Create image
-    var myImage = new Image();
-    var img_src = 'resources/apple.gif';
-    myImage.src = img_src;
-    myImage.onload = draw;
+var IndexSizeError = "IndexSizeError: Index or size was negative, or greater than the allowed value.";
 
-    var bitmap;
-    var ctx = document.createElement("canvas").getContext('2d');
-    function draw() {
-        // No arguments should get exception
-        shouldThrow("ctx.drawImage()", ExpectedNotEnoughArgumentsMessage(0));
+// Create image
+var myImage = new Image();
+var img_src = 'resources/apple.gif';
+myImage.src = img_src;
 
-        // image argument only should get exception
-        shouldThrow("ctx.drawImage(myImage)", ExpectedNotEnoughArgumentsMessage(1));
+var bitmap;
+var ctx = document.createElement("canvas").getContext('2d');
 
-        // image argument plus one number should get exception
-        shouldThrow("ctx.drawImage(myImage, 0)", ExpectedNotEnoughArgumentsMessage(2));
+function draw() {
+    // No arguments should get exception
+    assert_throws(null, function() {ctx.drawImage();}, ExpectedNotEnoughArgumentsMessage(0));
 
-        // image argument plus 2 numbers
-        shouldNotThrow("ctx.drawImage(myImage, 0, 0)");
+    // image argument only should get exception
+    assert_throws(null, function() {ctx.drawImage(myImage);}, ExpectedNotEnoughArgumentsMessage(1));
 
-        // image argument plus 4 numbers
-        shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20)");
+    // image argument plus one number should get exception
+    assert_throws(null, function() {ctx.drawImage(myImage, 0);}, ExpectedNotEnoughArgumentsMessage(2));
 
-        // image argument plus 8 numbers
-        shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20)");
+    // image argument plus 2 numbers
+    ctx.drawImage(myImage, 0, 0);
 
-        // image argument plus zero size
-        shouldNotThrow("ctx.drawImage(myImage, 0, 0, 0, 0)");
+    // image argument plus 4 numbers
+    ctx.drawImage(myImage, 0, 0, 20, 20);
 
-        // image argument plus 8 numbers, zero size
-        shouldNotThrow("ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0)");
+    // image argument plus 8 numbers
+    ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 20, 20);
 
-        // imageRect does not contain sourceRect on the left side
-        shouldNotThrow("ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20)");
+    // image argument plus zero size
+    ctx.drawImage(myImage, 0, 0, 0, 0);
 
-        // imageRect does not contain sourceRect on the right side
-        shouldNotThrow("ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20)");
+    // image argument plus 8 numbers, zero size
+    ctx.drawImage(myImage, 0, 0, 20, 20, 0, 0, 0, 0);
 
-        // imageRect does not contain sourceRect on top
-        shouldNotThrow("ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on the left side
+    ctx.drawImage(myImage, -10, 0, 52, 64, 0, 0, 20, 20);
 
-        // imageRect does not contain sourceRect on bottom
-        shouldNotThrow("ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on the right side
+    ctx.drawImage(myImage, 10, 0, 52, 64, 0, 0, 20, 20);
 
-        // sourceRect is bigger than imageSource on every side
-        shouldNotThrow("ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on top
+    ctx.drawImage(myImage, 0, -10, 52, 64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on the left side
-        shouldNotThrow("ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on bottom
+    ctx.drawImage(myImage, 0, 10, 52, 64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on the right side
-        shouldNotThrow("ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20)");
+    // sourceRect is bigger than imageSource on every side
+    ctx.drawImage(myImage, -10, -10, 72, 84, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on top
-        shouldNotThrow("ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on the left side
+    ctx.drawImage(myImage, 42, 64, -52, -64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on bottom
-        shouldNotThrow("ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on the right side
+    ctx.drawImage(myImage, 62, 64, -52, -64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on every side
-        shouldNotThrow("ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on top
+    ctx.drawImage(myImage, 52, 54, -52, -64, 0, 0, 20, 20);
 
-        // images with no src can be drawn
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0)");
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 20, 20)");
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on bottom
+    ctx.drawImage(myImage, 52, 74, -52, -64, 0, 0, 20, 20);
 
-        // images with no src exit early before IndexSizeError is thrown
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0)");
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 0, 20)");
-        shouldNotThrow("ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on every side
+    ctx.drawImage(myImage, 62, 74, -72, -84, 0, 0, 20, 20);
 
-        createImageBitmap(myImage).then(drawBitmap, function() {
-            testFailed("Promise was rejected.");
-            finishJSTest();
-        });
-    }
+    // images with no src can be drawn
+    ctx.drawImage(new Image(), 0, 0);
+    ctx.drawImage(new Image(), 0, 0, 20, 20);
+    ctx.drawImage(new Image(), 0, 0, 20, 20, 0, 0, 20, 20);
 
-    function drawBitmap(imageBitmap) {
-        bitmap = imageBitmap;
+    // images with no src exit early before IndexSizeError is thrown
+    ctx.drawImage(new Image(), 0, 0);
+    ctx.drawImage(new Image(), 0, 0, 0, 20);
+    ctx.drawImage(new Image(), 0, 0, 0, 20, 0, 0, 20, 20);
+}
 
-        // bitmap argument plus 2 numbers
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0)");
+function drawBitmap(imageBitmap) {
+    bitmap = imageBitmap;
 
-        // bitmap argument plus 4 numbers
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20)");
+    // bitmap argument plus 2 numbers
+    ctx.drawImage(bitmap, 0, 0);
 
-        // bitmap argument plus 8 numbers
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20)");
+    // bitmap argument plus 4 numbers
+    ctx.drawImage(bitmap, 0, 0, 20, 20);
 
-        // bitmap argument plus zero size
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 0, 0)");
+    // bitmap argument plus 8 numbers
+    ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 20, 20);
 
-        // bitmap argument plus 8 numbers, zero size
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0)");
+    // bitmap argument plus zero size
+    ctx.drawImage(bitmap, 0, 0, 0, 0);
 
-        // bitmap argument plus 8 numbers, negative size of source, zero size
-        shouldNotThrow("ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20)");
+    // bitmap argument plus 8 numbers, zero size
+    ctx.drawImage(bitmap, 0, 0, 20, 20, 0, 0, 0, 0);
 
-        // bitmap argument plus 8 numbers, negative size of destination, zero size
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20)");
+    // bitmap argument plus 8 numbers, negative size of source, zero size
+    ctx.drawImage(bitmap, 20, 20, -20, 0, 0, 0, 20, 20);
 
-        // bitmap argument plus 8 numbers, negative size of source and destination, zero size
-        shouldNotThrow("ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20)");
+    // bitmap argument plus 8 numbers, negative size of destination, zero size
+    ctx.drawImage(bitmap, 0, 0, 20, 0, 20, 20, -20, -20);
 
-        // imageRect does not contain sourceRect on the left side
-        shouldNotThrow("ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20)");
+    // bitmap argument plus 8 numbers, negative size of source and destination, zero size
+    ctx.drawImage(bitmap, 20, 20, -20, 0, 20, 20, -20, -20);
 
-        // imageRect does not contain sourceRect on the right side
-        shouldNotThrow("ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on the left side
+    ctx.drawImage(bitmap, -10, 0, 52, 64, 0, 0, 20, 20);
 
-        // imageRect does not contain sourceRect on top
-        shouldNotThrow("ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on the right side
+    ctx.drawImage(bitmap, 10, 0, 52, 64, 0, 0, 20, 20);
 
-        // imageRect does not contain sourceRect on bottom
-        shouldNotThrow("ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on top
+    ctx.drawImage(bitmap, 0, -10, 52, 64, 0, 0, 20, 20);
 
-        // sourceRect is bigger than imageSource on every side
-        shouldNotThrow("ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20)");
+    // imageRect does not contain sourceRect on bottom
+    ctx.drawImage(bitmap, 0, 10, 52, 64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on the left side
-        shouldNotThrow("ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20)");
+    // sourceRect is bigger than imageSource on every side
+    ctx.drawImage(bitmap, -10, -10, 72, 84, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on the right side
-        shouldNotThrow("ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on the left side
+    ctx.drawImage(bitmap, 42, 64, -52, -64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on top
-        shouldNotThrow("ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on the right side
+    ctx.drawImage(bitmap, 62, 64, -52, -64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on bottom
-        shouldNotThrow("ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on top
+    ctx.drawImage(bitmap, 52, 54, -52, -64, 0, 0, 20, 20);
 
-        // negative size of source, imageRect does not contain sourceRect on every side
-        shouldNotThrow("ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20)");
+    // negative size of source, imageRect does not contain sourceRect on bottom
+    ctx.drawImage(bitmap, 52, 74, -52, -64, 0, 0, 20, 20);
 
-        finishJSTest();
-    }
+    // negative size of source, imageRect does not contain sourceRect on every side
+    ctx.drawImage(bitmap, 62, 74, -72, -84, 0, 0, 20, 20);
+}
+
+async_test(t => {
+        myImage.onload = function() {
+            t.step(draw);
+            createImageBitmap(myImage).then(t.step_func(function(image) {
+                drawBitmap(image);
+            }));
+            t.done();
+        }
+}, "This test checks behavior of valid arguments to Canvas::drawImage that use a valid source image.");
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt
deleted file mode 100644
index ce1a3cf..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content-expected.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-This test makes sure that focusable elements in canvas fallback content are focusable.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-link1 should be focusable.
-PASS document.activeElement == element is true
-
-button1 should be focusable.
-PASS document.activeElement == element is true
-
-text1 should be focusable.
-PASS document.activeElement == element is true
-
-checkbox1 should be focusable.
-PASS document.activeElement == element is true
-
-radio1 should be focusable.
-PASS document.activeElement == element is true
-
-slider1 should be focusable.
-PASS document.activeElement == element is true
-
-submit1 should be focusable.
-PASS document.activeElement == element is true
-
-combobox1 should be focusable.
-PASS document.activeElement == element is true
-
-listbox1 should be focusable.
-PASS document.activeElement == element is true
-
-textarea1 should be focusable.
-PASS document.activeElement == element is true
-
-focusable1 should be focusable.
-PASS document.activeElement == element is true
-
-link2 should be focusable.
-PASS document.activeElement == element is true
-
-button2 should be focusable.
-PASS document.activeElement == element is true
-
-text2 should be focusable.
-PASS document.activeElement == element is true
-
-checkbox2 should be focusable.
-PASS document.activeElement == element is true
-
-radio2 should be focusable.
-PASS document.activeElement == element is true
-
-slider2 should be focusable.
-PASS document.activeElement == element is true
-
-submit2 should be focusable.
-PASS document.activeElement == element is true
-
-combobox2 should be focusable.
-PASS document.activeElement == element is true
-
-listbox2 should be focusable.
-PASS document.activeElement == element is true
-
-textarea2 should be focusable.
-PASS document.activeElement == element is true
-
-focusable2 should be focusable.
-PASS document.activeElement == element is true
-
-linkInHiddenCanvas should not be focusable.
-PASS document.activeElement == previousFocusedElement is true
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html
index 699aecb..9dff9a65 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/fallback-content.html
@@ -1,8 +1,9 @@
-<!DOCTYPE HTML>
 <html>
 <body>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <div id="container">
+
 <div>
   <a id="link1" href="#">Link</a>
   <button id="button1">Button</button>
@@ -34,61 +35,59 @@
 <canvas hidden id="hiddenCanvas" width="300" height="300">
   <a id="linkInHiddenCanvas" href="#">Link</a>
 </canvas>
+
 </div>
-<div id="console"></div>
 <script>
-description("This test makes sure that focusable elements in canvas fallback content are focusable.");
-
-if (window.testRunner)
-    window.testRunner.dumpAsText();
-
 var element;
+var previousFocusedElement;
+
 function checkFocusable(id) {
-    debug(id + " should be focusable.");
     element = document.getElementById(id);
     element.focus();
-    shouldBe("document.activeElement == element", "true");
-    debug("");
+    assert_true(document.activeElement == element);
 }
 
-checkFocusable("link1");
-checkFocusable("button1");
-checkFocusable("text1");
-checkFocusable("checkbox1");
-checkFocusable("radio1");
-checkFocusable("slider1");
-checkFocusable("submit1");
-checkFocusable("combobox1");
-checkFocusable("listbox1");
-checkFocusable("textarea1");
-checkFocusable("focusable1");
-
-checkFocusable("link2");
-checkFocusable("button2");
-checkFocusable("text2");
-checkFocusable("checkbox2");
-checkFocusable("radio2");
-checkFocusable("slider2");
-checkFocusable("submit2");
-checkFocusable("combobox2");
-checkFocusable("listbox2");
-checkFocusable("textarea2");
-checkFocusable("focusable2");
-
-var previousFocusedElement;
 function checkNotFocusable(id) {
-    debug(id + " should not be focusable.");
     previousFocusedElement = document.activeElement;
     element = document.getElementById(id);
     element.focus();
-    shouldBe("document.activeElement == previousFocusedElement", "true");
-    debug("");
+    assert_true(document.activeElement == previousFocusedElement);
 }
 
-checkNotFocusable("linkInHiddenCanvas");
+var focusableTestScenarios = [
+    ['FocusableTestCase1', "link1"],
+    ['FocusableTestCase2', "button1"],
+    ['FocusableTestCase3', "text1"],
+    ['FocusableTestCase4', "checkbox1"],
+    ['FocusableTestCase5', "radio1"],
+    ['FocusableTestCase6', "slider1"],
+    ['FocusableTestCase7', "submit1"],
+    ['FocusableTestCase8', "combobox1"],
+    ['FocusableTestCase9', "listbox1"],
+    ['FocusableTestCase10', "textarea1"],
+    ['FocusableTestCase11', "focusable1"],
 
+    ['FocusableTestCase12', "link2"],
+    ['FocusableTestCase13', "button2"],
+    ['FocusableTestCase14', "text2"],
+    ['FocusableTestCase15', "checkbox2"],
+    ['FocusableTestCase16', "radio2"],
+    ['FocusableTestCase17', "slider2"],
+    ['FocusableTestCase18', "submit2"],
+    ['FocusableTestCase19', "combobox2"],
+    ['FocusableTestCase20', "listbox2"],
+    ['FocusableTestCase21', "textarea2"],
+    ['FocusableTestCase22', "focusable2"]
+];
+
+var notFocusableTestScenarios = [
+    ['NotFocusableTestCase', "linkInHiddenCanvas"],
+];
+
+generate_tests(checkFocusable, focusableTestScenarios);
+generate_tests(checkNotFocusable, notFocusableTestScenarios);
 document.querySelector("#container").remove();
-</script>
 
+</script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt
deleted file mode 100644
index 8f245b9..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow-expected.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-Testing with no transform
-Testing with blur of 0 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Testing with blur of 1 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Testing with blur of 5 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Testing with scale transform
-Testing with blur of 0 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Testing with blur of 1 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-Testing with blur of 5 pixels
-PASS imgdata[0] is 0
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 0
-PASS imgdata[0] is 255
-PASS imgdata[1] is 0
-PASS imgdata[2] is 0
-PASS imgdata[3] is 255
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html
index 57611ca..57dca07 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/fillText-shadow.html
@@ -1,55 +1,47 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <canvas width="600" height="300" style="border: solid 1px gray"></canvas>
+
 <script>
-description('Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount.');
+
+// Tests that (vertical) shadow offsets are applied correctly when using fillText() regardless of blur amount.
+
 var ctx = document.getElementsByTagName('canvas')[0].getContext('2d');
 ctx.font = 'bold 128px sans-serif';
 ctx.shadowColor = 'red'
 ctx.shadowOffsetY = 100;
 
 function testWithBlur(blur, belowOffset) {
-  ctx.clearRect(0, 0, 600, 300);
-  ctx.shadowBlur = blur;
-  
-  // Center the I around the Y axis.
-  ctx.fillText('I', -ctx.measureText('I').width/2, 128);
-  
-  debug('Testing with blur of ' + blur + ' pixels');
+    ctx.clearRect(0, 0, 600, 300);
+    ctx.shadowBlur = blur;
+    
+    // Center the I around the Y axis.
+    ctx.fillText('I', -ctx.measureText('I').width/2, 128);
 
-  // Make sure that the shadow doesn't end up above the text...
-  var imageData = ctx.getImageData(0, 0, 1, 1);
-  imgdata = imageData.data;
+    // Make sure that the shadow doesn't end up above the text...
+    var imageData = ctx.getImageData(0, 0, 1, 1).data;
+    assert_array_equals(imageData, [0, 0, 0, 0]);
 
-  shouldBe('imgdata[0]', '0');
-  shouldBe('imgdata[1]', '0');
-  shouldBe('imgdata[2]', '0');
-  shouldBe('imgdata[3]', '0');
-  
-  // ...but below.
-  var imageData = ctx.getImageData(0, belowOffset, 1, 1);
-  imgdata = imageData.data;  
-  shouldBe('imgdata[0]', '255');
-  shouldBe('imgdata[1]', '0');
-  shouldBe('imgdata[2]', '0');
-  shouldBe('imgdata[3]', '255');
+    // ...but below.
+    var imageData = ctx.getImageData(0, belowOffset, 1, 1).data;
+    assert_array_equals(imageData, [255, 0, 0, 255]);
 }
 
-debug('Testing with no transform');
-testWithBlur(0, 150);
-testWithBlur(1, 150);
-testWithBlur(5, 150);
+var testScenariosNoTransform = [
+    ['TestShadowOffsetWithNoTransform 1', 0, 150],
+    ['TestShadowOffsetWithNoTransform 2', 1, 150],
+    ['TestShadowOffsetWithNoTransform 3', 5, 150],
+];
 
-debug('Testing with scale transform');
+var testScenariosScaleTransform = [
+    ['TestShadowOffsetWithScaleTransform 1', 0, 299],
+    ['TestShadowOffsetWithScaleTransform 2', 1, 299],
+    ['TestShadowOffsetWithScaleTransform 3', 5, 299],
+];
+
+generate_tests(testWithBlur, testScenariosNoTransform);
+
 ctx.scale(1, 2);
-testWithBlur(0, 299);
-testWithBlur(1, 299);
-testWithBlur(5, 299);
+generate_tests(testWithBlur, testScenariosScaleTransform);
 
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt
deleted file mode 100644
index d8300436..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Test that putImageData(getImageData) pair leaves canvas ImageData the same.
-
- 
-Result: PASS
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html
index 94ac797..ab075af 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/getPutImageDataPairTest.html
@@ -1,33 +1,11 @@
-<!DOCTYPE html>
-<title>putImageData(getImageData) pair test</title>
-<body class="show_output">
-<h3>Test that putImageData(getImageData) pair leaves canvas ImageData the same.</h3>
-<canvas id="c" class="output" width="64" height="64"><p class="fallback">FAIL (fallback content)</p></canvas>
-<br>
-Result: <a id="result"></a>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <script>
-if (window.testRunner)
-    testRunner.dumpAsText();
+var canvas = document.createElement('canvas');
+var ctx = canvas.getContext('2d');
 
-var canvas = document.getElementById("c");
-var ctx = canvas.getContext("2d");
-var passed = getPutImageData(50, ctx, 0, 0, 0, 0.0);
-passed |= getPutImageData(50, ctx, 0, 0, 0, 0.5);
-passed |= getPutImageData(50, ctx, 0, 0, 0, 1.0);
-passed |= getPutImageData(50, ctx, 127, 128, 129, 0.49);
-passed |= getPutImageData(50, ctx, 127, 128, 129, 0.51);
-passed |= getPutImageData(50, ctx, 127, 128, 129, 0.5);
-passed |= getPutImageData(50, ctx, 128, 128, 128, 0.0);
-passed |= getPutImageData(50, ctx, 128, 128, 128, 0.5);
-passed |= getPutImageData(50, ctx, 128, 128, 128, 1.0);
-
-var result_a = document.getElementById("result");
-if (!passed)
-    result_a.innerHTML = "FAIL";
-else
-    result_a.innerHTML = "PASS";
-
-function getPutImageData(numIters, ctx, r, g, b, a) {
+function getPutImageData(numIters, ctx, rgba) {
     var x = 0, y = 0, w = ctx.canvas.width, h = ctx.canvas.height;
 
     // Paint the canvas green to start
@@ -35,7 +13,7 @@
     ctx.fillRect(x,y,w,h);
 
     // Now paint the canvas a random hue of gray
-    var color = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; 
+    var color = 'rgba(' + rgba + ')'; 
     ctx.fillStyle = color;
     ctx.fillRect(x,y,w,h);
 
@@ -45,20 +23,33 @@
 
     // Get and put the image data 'numIters' times
     for(var i = 0; i < numIters; i++)
-        ctx.putImageData(ctx.getImageData(x,y,w,h), x,y);
+        ctx.putImageData(ctx.getImageData(x, y, w, h), x,y);
 
     // Grab new current image data
     var currImageData = ctx.getImageData(x, y, w, h);
 
     // Verify that original and new current image datas are equal
-    for(var i = 0; i < currImageData.data.length; i++) {
-        var origSubpixel = origImageData.data[i];
-        var currSubpixel = currImageData.data[i];
-
-        // If even 1 subpixel is off, return failure
-        if (origSubpixel != currSubpixel)
-            return false;
-    }
-    return true;
+    var dataMatch = true;
+    for(var i = 0; i < currImageData.data.length; i++)
+        if (origImageData.data[i] != currImageData.data[i]) {
+            dataMatch = false;
+            break;
+        }
+    assert_true(dataMatch);
 }
-</script>
\ No newline at end of file
+
+var testScenarios = [
+    ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.0'],
+    ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 0.5'],
+    ['GetPutImageDataTestCase ', 50, ctx, '0, 0, 0, 1.0'],
+    ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.49'],
+    ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.51'],
+    ['GetPutImageDataTestCase ', 50, ctx, '127, 128, 129, 0.5'],
+    ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.0'],
+    ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 0.5'],
+    ['GetPutImageDataTestCase ', 50, ctx, '128, 128, 128, 1.0'],
+];
+
+generate_tests(getPutImageData, testScenarios);
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt
deleted file mode 100644
index 560a3bd3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This test checks invalid colors on gradients.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS gradient.addColorStop(0, '') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('') could not be parsed as a color..
-PASS gradient.addColorStop(0, '#cc') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('#cc') could not be parsed as a color..
-PASS gradient.addColorStop(0, 'rgb(257, 0)') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('rgb(257, 0)') could not be parsed as a color..
-PASS gradient.addColorStop(0, 'rgb(257, 0, 5, 0)') threw exception SyntaxError: Failed to execute 'addColorStop' on 'CanvasGradient': The value provided ('rgb(257, 0, 5, 0)') could not be parsed as a color..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html
index 51eb48f..d731bc77 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-color.html
@@ -1,9 +1,17 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="script-tests/gradient-addColorStop-with-invalid-color.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function(){
+
+    var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0);
+
+    assert_throws(null, function(){gradient.addColorStop(0, '');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'\') could not be parsed as a color."');
+
+    assert_throws(null, function(){gradient.addColorStop(0, '#cc');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'#cc\') could not be parsed as a color."');
+
+    assert_throws(null, function(){gradient.addColorStop(0, 'rgb(257, 0)');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0)\') could not be parsed as a color."');
+
+    assert_throws(null, function(){gradient.addColorStop(0, 'rgb(257, 0, 5, 0)');}, '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0, 5, 0)\') could not be parsed as a color."');
+
+}, 'This test checks invalid colors on gradients.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt
deleted file mode 100644
index cad908e4..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset-expected.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-This test checks invalid offsets on gradients.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS gradient.addColorStop(-1, '#000') threw exception IndexSizeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided value (-1) is outside the range (0.0, 1.0)..
-PASS gradient.addColorStop(2, '#000') threw exception IndexSizeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided value (2) is outside the range (0.0, 1.0)..
-PASS gradient.addColorStop(Infinity, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite..
-PASS gradient.addColorStop(-Infinity, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite..
-PASS gradient.addColorStop(NaN, '#000') threw exception TypeError: Failed to execute 'addColorStop' on 'CanvasGradient': The provided float value is non-finite..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html
index f340a48..c2640a4 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-addColorStop-with-invalid-offset.html
@@ -1,9 +1,15 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="script-tests/gradient-addColorStop-with-invalid-offset.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+test(function() {
+
+    var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0);
+
+    assert_throws(null, function(){gradient.addColorStop(-1, '#000');});
+    assert_throws(null, function(){gradient.addColorStop(2, '#000');});
+    assert_throws(null, function(){gradient.addColorStop(Infinity, '#000');});
+    assert_throws(null, function(){gradient.addColorStop(-Infinity, '#000');});
+    assert_throws(null, function(){gradient.addColorStop(NaN, '#000');});
+
+}, 'This test checks invalid offsets on gradients.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt
deleted file mode 100644
index 160a7dd1..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS pixel 20, 20 is [0, 128, 0, 255]
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html
index 99d2171..7797585 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/gradient-with-clip.html
@@ -1,9 +1,50 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <body>
-<script src="script-tests/gradient-with-clip.js"></script>
+<script>
+
+var canvas;
+function fillWithColor(context, color) {
+    context.save();
+    context.fillStyle = color;
+    context.fillRect(0, 0, canvas.width, canvas.height);
+    context.restore();
+}
+
+test(function(t) {
+    canvas = document.createElement("canvas");
+    canvas.height = 100;
+    canvas.width = 100;
+    canvas.style.height = "100";
+    canvas.style.width = "100";
+    
+    document.body.appendChild(canvas);
+    
+    var greenImage = document.createElement("canvas");
+    greenImage.height = 10;
+    greenImage.width = 10;
+    var greenCtx = greenImage.getContext('2d');
+    fillWithColor(greenCtx, "green");
+    var greenPixel = greenCtx.getImageData(0, 0, 1, 1).data;
+    
+    var ctx = canvas.getContext('2d');
+    var gradient = ctx.createLinearGradient(0, 0, 10, 0);
+    gradient.addColorStop(0, "blue");
+    gradient.addColorStop(1, "red");
+    ctx.fillStyle = gradient;
+    ctx.beginPath();
+    ctx.moveTo(0, 0);
+    ctx.lineTo(10, 5);
+    ctx.lineTo(10, 10);
+    ctx.lineTo(5, 10);
+    ctx.closePath();
+    ctx.fill();
+    
+    ctx.fillStyle = "green";
+    ctx.fillRect(20, 20, 10, 10);
+    
+    assert_array_equals(ctx.getImageData(20, 20, 1, 1).data, greenPixel);
+
+}, "Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498")
+</script>
 </body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt
deleted file mode 100644
index 7ccec9e..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate-expected.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-PASS successfullyParsed is true
-
-TEST COMPLETE
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-PASS imgdata[0] is 0
-PASS imgdata[1] is 255
-PASS imgdata[2] is 0
-Visual result below is for debugging purposes only (test uses text baseline only). You should see sixteen canvases with a green dot (rotated square) in the center.
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html
index 0c970d3e..87a120a 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/image-pattern-rotate.html
@@ -1,19 +1,21 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
-        "http://www.w3.org/TR/html4/loose.dtd">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
 <style>
 canvas {
     border: 1px solid #000;
     margin: 2px;
 }
 </style>
+<div id="canvases"></div>
+
 <script>
+// Visual result for debugging (test uses text baseline only): You should see sixteen canvases with a green dot (rotated square) in the center.
+
 var img;
 var imgdata;
 
-function imageLoaded() {
+function runTests() {
     var NUM_IMAGE = 16;
     for (var i = 0; i < NUM_IMAGE; i++) {
         var canvases = document.getElementById('canvases')
@@ -34,40 +36,25 @@
         div.appendChild(canvas);
         canvases.appendChild(div);
 
-        var imageData = ctx.getImageData(4, 4, 1, 1);
-        imgdata = imageData.data;
-        shouldBe("imgdata[0]", "0");
-        shouldBe("imgdata[1]", "255");
-        shouldBe("imgdata[2]", "0");
-    }
-
-    if (window.testRunner) {
-        testRunner.notifyDone();
+        assert_array_equals(ctx.getImageData(4, 4, 1, 1).data.slice(0,3), [0, 255, 0]);
     }
 }
 
-function runTests() {
-    if (window.testRunner) {
-		testRunner.dumpAsText();
-        testRunner.waitUntilDone();
-    }
 
-    var patternCanvas = document.createElement('canvas');
-    patternCanvas.width = 9;
-    patternCanvas.height = 9;
-    var patternCtx = patternCanvas.getContext('2d');
-    patternCtx.fillStyle = '#0F0';
-    patternCtx.fillRect(3, 3, 3, 3);
-    img = new Image();
-    img.onload = imageLoaded;
-    img.src = patternCanvas.toDataURL();
+var patternCanvas = document.createElement('canvas');
+patternCanvas.width = 9;
+patternCanvas.height = 9;
+var patternCtx = patternCanvas.getContext('2d');
+patternCtx.fillStyle = '#0F0';
+patternCtx.fillRect(3, 3, 3, 3);
+img = new Image();
+img.src = patternCanvas.toDataURL();
 
-}
+
+async_test(t => {
+        img.onload = function() {
+            t.step(runTests);
+            t.done();
+        }
+}, "Test image pattern rotation.");
 </script>
-</head>
-<body onload="runTests();">
-Visual result below is for debugging purposes only (test uses text baseline only). You should see sixteen canvases with a green dot (rotated square) in the center.
-<div id="canvases"></div>
-</pre>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt
deleted file mode 100644
index 7093c38..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Tests that ImageData contains a Uint8ClampedArray.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS imageData.data.constructor is Uint8ClampedArray
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html
index 9d89f1d..39060860 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/imagedata-contains-uint8clampedarray.html
@@ -1,19 +1,15 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 <script>
-description("Tests that ImageData contains a Uint8ClampedArray.");
+test(function(){
 
-var canvas = document.createElement("canvas");
-canvas.width = 10;
-canvas.height = 10;
-var context = canvas.getContext("2d");
+    var canvas = document.createElement("canvas");
+    canvas.width = 10;
+    canvas.height = 10;
+    var context = canvas.getContext("2d");
 
-var imageData = context.getImageData(0, 0, 1, 1);
-shouldBe('imageData.data.constructor', 'Uint8ClampedArray');
+    var imageData = context.getImageData(0, 0, 1, 1);
+    assert_equals(imageData.data.constructor, Uint8ClampedArray);
+
+}, "Tests that ImageData contains a Uint8ClampedArray.");
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt
deleted file mode 100644
index d31f6ea..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash-expected.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This test should not crash.
-
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html
index 5bfc970..58067b5 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/invalid-set-font-crash.html
@@ -1,19 +1,18 @@
-<html>
-<head>
-    <script type="text/javascript">
-    if (window.testRunner)
-        testRunner.dumpAsText();
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
 
-    function init()
-    {
-        var ctx = document.getElementById("canvas").getContext("2d");
-        ctx.font = "font-family: Helvetica; font-size: 48pt; font-color: #000000";
-        ctx.fillText("Hello world", 10, 200);
+<script>
+function runTest()
+{
+    var ctx = document.createElement("canvas").getContext("2d");
+    ctx.font = "font-family: Helvetica; font-size: 48pt; font-color: #000000";
+    ctx.fillText("Hello world", 10, 200);
+}
+
+async_test(t => {
+    window.onload = function() {
+        t.step(runTest);
+        t.done();
     }
-    </script>
-</head>
-<body onload="init()">
-    <p>This test should not crash.</p>
-    <canvas id="canvas" height="300" width="300"></canvas>
-</body>
-</html>
+}, 'Verify that setting the font does not crash.');
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt
deleted file mode 100644
index f257fe3..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values-expected.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-This test checks createLinearGradient with infinite values
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS ctx.createLinearGradient(0, 0, 100, NaN) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, 0, 100, Infinity) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, 0, 100, -Infinity) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, 0, NaN, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, 0, Infinity, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, 0, -Infinity, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, NaN, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, Infinity, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(0, -Infinity, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(NaN, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(Infinity, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS ctx.createLinearGradient(-Infinity, 0, 100, 100) threw exception TypeError: Failed to execute 'createLinearGradient' on 'CanvasRenderingContext2D': The provided double value is non-finite..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html
index 3e4694a..97c6eb9 100644
--- a/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html
+++ b/third_party/WebKit/LayoutTests/fast/canvas/linearGradient-infinite-values.html
@@ -1,9 +1,30 @@
-<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
-<html>
-<head>
-<script src="../../resources/js-test.js"></script>
-</head>
-<body>
-<script src="script-tests/linearGradient-infinite-values.js"></script>
-</body>
-</html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+
+<script>
+// This test checks createLinearGradient with infinite values
+var ctx = document.createElement('canvas').getContext('2d');
+
+function testCreateLinearGradient(params)
+{
+    x0 = params[0]; y0 = params[1]; x1 = params[2]; y1 = params[3];
+    assert_throws(null, function(){ctx.createLinearGradient(x0, y0, x1, y1);});
+}
+
+var testScenarios = [
+    ['Test createLinearGradient(0, 0, 100, NaN)' , [0, 0, 100, NaN]],
+    ['Test createLinearGradient(0, 0, 100, Infinity)' , [0, 0, 100, Infinity]],
+    ['Test createLinearGradient(0, 0, 100, -Infinity)' , [0, 0, 100, -Infinity]],
+    ['Test createLinearGradient(0, 0, NaN, 100)' , [0, 0, NaN, 100]],
+    ['Test createLinearGradient(0, 0, Infinity, 100)' , [0, 0, Infinity, 100]],
+    ['Test createLinearGradient(0, 0, -Infinity, 100)' , [0, 0, -Infinity, 100]],
+    ['Test createLinearGradient(0, NaN, 100, 100)' , [0, NaN, 100, 100]],
+    ['Test createLinearGradient(0, Infinity, 100, 100)' , [0, Infinity, 100, 100]],
+    ['Test createLinearGradient(0, -Infinity, 100, 100)' , [0, -Infinity, 100, 100]],
+    ['Test createLinearGradient(NaN, 0, 100, 100)' , [NaN, 0, 100, 100]],
+    ['Test createLinearGradient(Infinity, 0, 100, 100)' , [Infinity, 0, 100, 100]],
+    ['Test createLinearGradient(-Infinity, 0, 100, 100)' , [-Infinity, 0, 100, 100]],
+];
+
+generate_tests(testCreateLinearGradient, testScenarios);
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js
deleted file mode 100644
index 07dae37f..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-color.js
+++ /dev/null
@@ -1,10 +0,0 @@
-description(
-'This test checks invalid colors on gradients.'
-);
-
-var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0);
-
-shouldThrow("gradient.addColorStop(0, '')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'\') could not be parsed as a color."');
-shouldThrow("gradient.addColorStop(0, '#cc')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'#cc\') could not be parsed as a color."');
-shouldThrow("gradient.addColorStop(0, 'rgb(257, 0)')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0)\') could not be parsed as a color."');
-shouldThrow("gradient.addColorStop(0, 'rgb(257, 0, 5, 0)')", '"SyntaxError: Failed to execute \'addColorStop\' on \'CanvasGradient\': The value provided (\'rgb(257, 0, 5, 0)\') could not be parsed as a color."');
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js
deleted file mode 100644
index 493ad9a..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-addColorStop-with-invalid-offset.js
+++ /dev/null
@@ -1,10 +0,0 @@
-description('This test checks invalid offsets on gradients.');
-
-var gradient = document.createElement('canvas').getContext('2d').createLinearGradient(0, 0, 150, 0);
-
-// Check that invalid offset values throw.
-shouldThrow("gradient.addColorStop(-1, '#000')");
-shouldThrow("gradient.addColorStop(2, '#000')");
-shouldThrow("gradient.addColorStop(Infinity, '#000')");
-shouldThrow("gradient.addColorStop(-Infinity, '#000')");
-shouldThrow("gradient.addColorStop(NaN, '#000')");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js
deleted file mode 100644
index e8d7929..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/gradient-with-clip.js
+++ /dev/null
@@ -1,63 +0,0 @@
-description("Test for canvas regression where gradient clips were not cleared https://bugs.webkit.org/show_bug.cgi?id=21498")
-
-function pixelValueAt(context, x, y) {
-    var imageData = context.getImageData(x, y, 1, 1);
-    return imageData.data;
-}
-
-function pixelToString(p) {
-    return "[" + p[0] + ", " + p[1] + ", " + p[2] + ", " + p[3] + "]"
-}
-
-function pixelShouldBe(context, x, y, expectedPixelString) {
-    var pixel = pixelValueAt(context, x, y);
-    var expectedPixel = eval(expectedPixelString);
-    
-    var pixelString = "pixel " + x + ", " + y;
-    if (areArraysEqual(pixel, expectedPixel)) {
-        testPassed(pixelString + " is " + pixelToString(pixel));
-    } else {
-        testFailed(pixelString + " should be " + pixelToString(expectedPixel) + " was " + pixelToString(pixel));
-    }
-}
-
-function fillWithColor(context, color) {
-    context.save();
-    context.fillStyle = color;
-    context.fillRect(0, 0, canvas.width, canvas.height);
-    context.restore();
-}
-
-var canvas = document.createElement("canvas");
-canvas.height = 100;
-canvas.width = 100;
-canvas.style.height = "100";
-canvas.style.width = "100";
-
-document.body.appendChild(canvas);
-
-var greenImage = document.createElement("canvas");
-greenImage.height = 10;
-greenImage.width = 10;
-var greenCtx = greenImage.getContext('2d');
-fillWithColor(greenCtx, "green");
-var greenPixel = pixelValueAt(greenCtx, 0, 0);
-
-
-var ctx = canvas.getContext('2d');
-var gradient = ctx.createLinearGradient(0, 0, 10, 0);
-gradient.addColorStop(0, "blue");
-gradient.addColorStop(1, "red");
-ctx.fillStyle = gradient;
-ctx.beginPath();
-ctx.moveTo(0, 0);
-ctx.lineTo(10, 5);
-ctx.lineTo(10, 10);
-ctx.lineTo(5, 10);
-ctx.closePath();
-ctx.fill();
-
-ctx.fillStyle = "green";
-ctx.fillRect(20, 20, 10, 10);
-
-pixelShouldBe(ctx, 20, 20, "greenPixel");
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js b/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js
deleted file mode 100644
index a3f886a..0000000
--- a/third_party/WebKit/LayoutTests/fast/canvas/script-tests/linearGradient-infinite-values.js
+++ /dev/null
@@ -1,18 +0,0 @@
-description(
-'This test checks createLinearGradient with infinite values'
-);
-
-var ctx = document.createElement('canvas').getContext('2d');
-
-shouldThrow("ctx.createLinearGradient(0, 0, 100, NaN)");
-shouldThrow("ctx.createLinearGradient(0, 0, 100, Infinity)");
-shouldThrow("ctx.createLinearGradient(0, 0, 100, -Infinity)");
-shouldThrow("ctx.createLinearGradient(0, 0, NaN, 100)");
-shouldThrow("ctx.createLinearGradient(0, 0, Infinity, 100)");
-shouldThrow("ctx.createLinearGradient(0, 0, -Infinity, 100)");
-shouldThrow("ctx.createLinearGradient(0, NaN, 100, 100)");
-shouldThrow("ctx.createLinearGradient(0, Infinity, 100, 100)");
-shouldThrow("ctx.createLinearGradient(0, -Infinity, 100, 100)");
-shouldThrow("ctx.createLinearGradient(NaN, 0, 100, 100)");
-shouldThrow("ctx.createLinearGradient(Infinity, 0, 100, 100)");
-shouldThrow("ctx.createLinearGradient(-Infinity, 0, 100, 100)");
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index e23782d..14eb5f0 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1209,23 +1209,6 @@
     VRGetDisplays = 1558,
     VRPresent = 1559,
     VRDeprecatedGetPose = 1560,
-    WebAudioAnalyserNode = 1561,
-    WebAudioAudioBuffer = 1562,
-    WebAudioAudioBufferSourceNode = 1563,
-    WebAudioBiquadFilterNode = 1564,
-    WebAudioChannelMergerNode = 1565,
-    WebAudioChannelSplitterNode = 1566,
-    WebAudioConvolverNode = 1567,
-    WebAudioDelayNode = 1568,
-    WebAudioDynamicsCompressorNode = 1569,
-    WebAudioGainNode = 1570,
-    WebAudioIIRFilterNode = 1571,
-    WebAudioMediaElementAudioSourceNode = 1572,
-    WebAudioOscillatorNode = 1573,
-    WebAudioPannerNode = 1574,
-    WebAudioPeriodicWave = 1575,
-    WebAudioStereoPannerNode = 1576,
-    WebAudioWaveShaperNode = 1577,
     CSSZoomReset = 1578,
     CSSZoomDocument = 1579,
     XSSAuditorBlockedScript = 1581,
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp b/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp
index a93258a..3f48d92 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGAnimationElement.cpp
@@ -253,24 +253,14 @@
   return clampTo<float>(duration.value());
 }
 
-void SVGAnimationElement::beginElement() {
-  beginElementAt(0);
-}
-
 void SVGAnimationElement::beginElementAt(float offset) {
-  ASSERT(std::isfinite(offset));
-  SMILTime elapsed = this->elapsed();
-  addBeginTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
-}
-
-void SVGAnimationElement::endElement() {
-  endElementAt(0);
+  DCHECK(std::isfinite(offset));
+  addInstanceTime(Begin, elapsed() + offset, SMILTimeWithOrigin::ScriptOrigin);
 }
 
 void SVGAnimationElement::endElementAt(float offset) {
-  ASSERT(std::isfinite(offset));
-  SMILTime elapsed = this->elapsed();
-  addEndTime(elapsed, elapsed + offset, SMILTimeWithOrigin::ScriptOrigin);
+  DCHECK(std::isfinite(offset));
+  addInstanceTime(End, elapsed() + offset, SMILTimeWithOrigin::ScriptOrigin);
 }
 
 void SVGAnimationElement::updateAnimationMode() {
diff --git a/third_party/WebKit/Source/core/svg/SVGAnimationElement.h b/third_party/WebKit/Source/core/svg/SVGAnimationElement.h
index 2aa9411d..50e62db4 100644
--- a/third_party/WebKit/Source/core/svg/SVGAnimationElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGAnimationElement.h
@@ -60,9 +60,9 @@
   float getCurrentTime() const;
   float getSimpleDuration(ExceptionState&) const;
 
-  void beginElement();
+  void beginElement() { beginElementAt(0); }
   void beginElementAt(float offset);
-  void endElement();
+  void endElement() { endElementAt(0); }
   void endElementAt(float offset);
 
   DEFINE_MAPPED_ATTRIBUTE_EVENT_LISTENER(begin, beginEvent);
diff --git a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
index cbf3a6d..9a0ab683 100644
--- a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
+++ b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
@@ -121,7 +121,11 @@
 void ConditionEventListener::handleEvent(ExecutionContext*, Event* event) {
   if (!m_animation)
     return;
-  m_animation->handleConditionEvent(event, m_condition);
+  if (event->type() == "repeatn" &&
+      toRepeatEvent(event)->repeat() != m_condition->repeat())
+    return;
+  m_animation->addInstanceTime(m_condition->getBeginOrEnd(),
+                               m_animation->elapsed() + m_condition->offset());
 }
 
 SVGSMILElement::Condition::Condition(Type type,
@@ -720,20 +724,20 @@
   return std::min(dur(), SMILTime::indefinite());
 }
 
-void SVGSMILElement::addBeginTime(SMILTime eventTime,
-                                  SMILTime beginTime,
-                                  SMILTimeWithOrigin::Origin origin) {
-  m_beginTimes.push_back(SMILTimeWithOrigin(beginTime, origin));
-  sortTimeList(m_beginTimes);
-  beginListChanged(eventTime);
-}
-
-void SVGSMILElement::addEndTime(SMILTime eventTime,
-                                SMILTime endTime,
-                                SMILTimeWithOrigin::Origin origin) {
-  m_endTimes.push_back(SMILTimeWithOrigin(endTime, origin));
-  sortTimeList(m_endTimes);
-  endListChanged(eventTime);
+void SVGSMILElement::addInstanceTime(BeginOrEnd beginOrEnd,
+                                     SMILTime time,
+                                     SMILTimeWithOrigin::Origin origin) {
+  SMILTime elapsed = this->elapsed();
+  if (elapsed.isUnresolved())
+    return;
+  Vector<SMILTimeWithOrigin>& list =
+      beginOrEnd == Begin ? m_beginTimes : m_endTimes;
+  list.push_back(SMILTimeWithOrigin(time, origin));
+  sortTimeList(list);
+  if (beginOrEnd == Begin)
+    beginListChanged(elapsed);
+  else
+    endListChanged(elapsed);
 }
 
 inline bool compareTimes(const SMILTimeWithOrigin& left,
@@ -1210,13 +1214,7 @@
         time = syncBase.m_interval.end + condition->offset();
       if (!time.isFinite())
         continue;
-      SMILTime elapsed = this->elapsed();
-      if (elapsed.isUnresolved())
-        continue;
-      if (condition->getBeginOrEnd() == Begin)
-        addBeginTime(elapsed, time);
-      else
-        addEndTime(elapsed, time);
+      addInstanceTime(condition->getBeginOrEnd(), time);
     }
   }
 }
@@ -1231,25 +1229,8 @@
   m_syncBaseDependents.erase(&animation);
 }
 
-void SVGSMILElement::handleConditionEvent(Event* event, Condition* condition) {
-  if (event->type() == "repeatn" &&
-      toRepeatEvent(event)->repeat() != condition->repeat())
-    return;
-
-  SMILTime elapsed = this->elapsed();
-  if (elapsed.isUnresolved())
-    return;
-  if (condition->getBeginOrEnd() == Begin)
-    addBeginTime(elapsed, elapsed + condition->offset());
-  else
-    addEndTime(elapsed, elapsed + condition->offset());
-}
-
 void SVGSMILElement::beginByLinkActivation() {
-  SMILTime elapsed = this->elapsed();
-  if (elapsed.isUnresolved())
-    return;
-  addBeginTime(elapsed, elapsed);
+  addInstanceTime(Begin, elapsed());
 }
 
 void SVGSMILElement::endedActiveInterval() {
diff --git a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h
index b89f404..773552c 100644
--- a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h
+++ b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.h
@@ -127,13 +127,11 @@
   DECLARE_VIRTUAL_TRACE();
 
  protected:
-  void addBeginTime(
-      SMILTime eventTime,
-      SMILTime endTime,
-      SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
-  void addEndTime(
-      SMILTime eventTime,
-      SMILTime endTime,
+  enum BeginOrEnd { Begin, End };
+
+  void addInstanceTime(
+      BeginOrEnd,
+      SMILTime,
       SMILTimeWithOrigin::Origin = SMILTimeWithOrigin::ParserOrigin);
 
   void setInactive() { m_activeState = Inactive; }
@@ -159,8 +157,6 @@
 
   bool layoutObjectIsNeeded(const ComputedStyle&) override { return false; }
 
-  enum BeginOrEnd { Begin, End };
-
   SMILTime findInstanceTime(BeginOrEnd,
                             SMILTime minimumTime,
                             bool equalsMinimumOK) const;
@@ -237,9 +233,6 @@
   void disconnectSyncBaseConditions();
   void disconnectEventBaseConditions();
 
-  // Event base timing
-  void handleConditionEvent(Event*, Condition*);
-
   void notifyDependentsIntervalChanged();
   void createInstanceTimesFromSyncbase(SVGSMILElement& syncbase);
   void addSyncBaseDependent(SVGSMILElement&);
diff --git a/third_party/WebKit/Source/modules/modules_idl_files.gni b/third_party/WebKit/Source/modules/modules_idl_files.gni
index 8dec1f3..94ed5f68 100644
--- a/third_party/WebKit/Source/modules/modules_idl_files.gni
+++ b/third_party/WebKit/Source/modules/modules_idl_files.gni
@@ -628,7 +628,6 @@
           "vibration/NavigatorVibration.idl",
           "vr/NavigatorVR.idl",
           "wake_lock/ScreenWakeLock.idl",
-          "webaudio/WindowWebAudio.idl",
           "webaudio/WindowAudioWorklet.idl",
           "webauth/NavigatorAuth.idl",
           "webdatabase/WindowWebDatabase.idl",
diff --git a/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h b/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h
deleted file mode 100644
index 2725e65..0000000
--- a/third_party/WebKit/Source/modules/webaudio/DOMWindowWebAudio.h
+++ /dev/null
@@ -1,6 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// TODO: This is a dummy header file required by the generated binding code.
-// This file should be removed after fixing the code generator.
diff --git a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl b/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl
deleted file mode 100644
index 4cc737d..0000000
--- a/third_party/WebKit/Source/modules/webaudio/WindowWebAudio.idl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[
-    ImplementedAs=DOMWindowWebAudio,
-] partial interface Window {
-    // The individual constructible AudioNodes.
-    [MeasureAs=WebAudioAnalyserNode] attribute AnalyserNodeConstructor AnalyserNode;
-    [MeasureAs=WebAudioAudioBuffer] attribute AudioBufferConstructor AudioBuffer;
-    [MeasureAs=WebAudioAudioBufferSourceNode] attribute AudioBufferSourceNodeConstructor AudioBufferSourceNode;
-    [MeasureAs=WebAudioBiquadFilterNode] attribute BiquadFilterNodeConstructor BiquadFilterNode;
-    [MeasureAs=WebAudioChannelMergerNode] attribute ChannelMergerNodeConstructor ChannelMergerNode;
-    [MeasureAs=WebAudioChannelSplitterNode] attribute ChannelSplitterNodeConstructor ChannelSplitterNode;
-    [MeasureAs=WebAudioConstantSourceNode] attribute ConstantSourceNodeConstructor ConstantSourceNode;
-    [MeasureAs=WebAudioConvolverNode] attribute ConvolverNodeConstructor ConvolverNode;
-    [MeasureAs=WebAudioDelayNode] attribute DelayNodeConstructor DelayNode;
-    [MeasureAs=WebAudioDynamicsCompressorNode] attribute DynamicsCompressorNodeConstructor DynamicsCompressorNode;
-    [MeasureAs=WebAudioGainNode] attribute GainNodeConstructor GainNode;
-    [MeasureAs=WebAudioIIRFilterNode] attribute IIRFilterNodeConstructor IIRFilterNode;
-    [MeasureAs=WebAudioMediaElementAudioSourceNode] attribute MediaElementAudioSourceNodeConstructor MediaElementAudioSourceNode;
-    [MeasureAs=WebAudioOscillatorNode] attribute OscillatorNodeConstructor OscillatorNode;
-    [MeasureAs=WebAudioPannerNode] attribute PannerNodeConstructor PannerNode;
-    [MeasureAs=WebAudioPeriodicWave] attribute PeriodicWaveConstructor PeriodicWave;
-    [MeasureAs=WebAudioStereoPannerNode] attribute StereoPannerNodeConstructor StereoPannerNode;
-    [MeasureAs=WebAudioWaveShaperNode] attribute WaveShaperNodeConstructor WaveShaperNode;
-};
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp
index dd50473..07eff840 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.cpp
@@ -45,8 +45,7 @@
 
 // static
 bool WebGLDrawBuffers::supported(WebGLRenderingContextBase* context) {
-  return (context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers") &&
-          satisfiesWebGLRequirements(context));
+  return context->extensionsUtil()->supportsExtension("GL_EXT_draw_buffers");
 }
 
 // static
@@ -96,101 +95,4 @@
   }
 }
 
-// static
-bool WebGLDrawBuffers::satisfiesWebGLRequirements(
-    WebGLRenderingContextBase* webglContext) {
-  gpu::gles2::GLES2Interface* gl = webglContext->contextGL();
-  Extensions3DUtil* extensionsUtil = webglContext->extensionsUtil();
-
-  // This is called after we make sure GL_EXT_draw_buffers is supported.
-  GLint maxDrawBuffers = 0;
-  GLint maxColorAttachments = 0;
-  gl->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers);
-  gl->GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &maxColorAttachments);
-  if (maxDrawBuffers < 4 || maxColorAttachments < 4)
-    return false;
-
-  GLuint fbo;
-  gl->GenFramebuffers(1, &fbo);
-  gl->BindFramebuffer(GL_FRAMEBUFFER, fbo);
-
-  const unsigned char* buffer =
-      0;  // Chromium doesn't allow init data for depth/stencil tetxures.
-  bool supportsDepth =
-      (extensionsUtil->supportsExtension("GL_CHROMIUM_depth_texture") ||
-       extensionsUtil->supportsExtension("GL_OES_depth_texture") ||
-       extensionsUtil->supportsExtension("GL_ARB_depth_texture"));
-  bool supportsDepthStencil =
-      (extensionsUtil->supportsExtension("GL_EXT_packed_depth_stencil") ||
-       extensionsUtil->supportsExtension("GL_OES_packed_depth_stencil"));
-  GLuint depthStencil = 0;
-  if (supportsDepthStencil) {
-    gl->GenTextures(1, &depthStencil);
-    gl->BindTexture(GL_TEXTURE_2D, depthStencil);
-    gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, 1, 1, 0,
-                   GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, buffer);
-  }
-  GLuint depth = 0;
-  if (supportsDepth) {
-    gl->GenTextures(1, &depth);
-    gl->BindTexture(GL_TEXTURE_2D, depth);
-    gl->TexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0,
-                   GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, buffer);
-  }
-
-  Vector<GLuint> colors;
-  bool ok = true;
-  GLint maxAllowedBuffers = std::min(maxDrawBuffers, maxColorAttachments);
-  for (GLint i = 0; i < maxAllowedBuffers; ++i) {
-    GLuint color;
-
-    gl->GenTextures(1, &color);
-    colors.push_back(color);
-    gl->BindTexture(GL_TEXTURE_2D, color);
-    gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
-                   GL_UNSIGNED_BYTE, buffer);
-    gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
-                             GL_TEXTURE_2D, color, 0);
-    if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
-      ok = false;
-      break;
-    }
-    if (supportsDepth) {
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                               GL_TEXTURE_2D, depth, 0);
-      if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) !=
-          GL_FRAMEBUFFER_COMPLETE) {
-        ok = false;
-        break;
-      }
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
-                               GL_TEXTURE_2D, 0, 0);
-    }
-    if (supportsDepthStencil) {
-      // For ES 2.0 contexts DEPTH_STENCIL is not available natively, so we
-      // emulate it at the command buffer level for WebGL contexts.
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                               GL_TEXTURE_2D, depthStencil, 0);
-      if (gl->CheckFramebufferStatus(GL_FRAMEBUFFER) !=
-          GL_FRAMEBUFFER_COMPLETE) {
-        ok = false;
-        break;
-      }
-      gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
-                               GL_TEXTURE_2D, 0, 0);
-    }
-  }
-
-  webglContext->restoreCurrentFramebuffer();
-  gl->DeleteFramebuffers(1, &fbo);
-  webglContext->restoreCurrentTexture2D();
-  if (supportsDepth)
-    gl->DeleteTextures(1, &depth);
-  if (supportsDepthStencil)
-    gl->DeleteTextures(1, &depthStencil);
-  gl->DeleteTextures(colors.size(), colors.data());
-
-  return ok;
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h
index 500caa90..4bf6b217 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLDrawBuffers.h
@@ -45,8 +45,6 @@
 
  private:
   explicit WebGLDrawBuffers(WebGLRenderingContextBase*);
-
-  static bool satisfiesWebGLRequirements(WebGLRenderingContextBase*);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
index b0603181..75436bf8 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -387,11 +387,29 @@
   m_harfBuzzFontData->m_rangeSet = rangeSet;
   m_harfBuzzFontData->updateSimpleFontData(m_platformData);
 
-  // TODO crbug.com/674879 - Connect variation axis parameters to future
-  // HarfBuzz API here.
   ASSERT(m_harfBuzzFontData->m_simpleFontData);
   int scale = SkiaScalarToHarfBuzzPosition(m_platformData->size());
   hb_font_set_scale(m_unscaledFont, scale, scale);
+
+// TODO: crbug.com/696570 Remove this conditional
+// once HarfBuzz on CrOS is updated.
+#if HB_VERSION_ATLEAST(1, 4, 2)
+  SkTypeface* typeface = m_harfBuzzFontData->m_paint.getTypeface();
+  int axisCount = typeface->getVariationDesignPosition(nullptr, 0);
+  if (axisCount > 0) {
+    Vector<SkFontArguments::VariationPosition::Coordinate> axisValues;
+    axisValues.resize(axisCount);
+    typeface->getVariationDesignPosition(axisValues.data(), axisValues.size());
+    Vector<float> axisValuesFloat;
+    axisValuesFloat.resize(axisCount);
+    for (size_t i = 0; i < axisValues.size(); i++) {
+      axisValuesFloat[i] = axisValues[i].value;
+    }
+    hb_font_set_var_coords_design(m_unscaledFont, axisValuesFloat.data(),
+                                  axisValuesFloat.size());
+  }
+#endif
+
   return m_unscaledFont;
 }
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
index f50d7d8..1024d14 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
@@ -163,7 +163,7 @@
         """
         # `git status -z` is a version of `git status -s`, that's recommended
         # for machine parsing. Lines are terminated with NUL rather than LF.
-        change_lines = self._run_git(['status', '-z']).rstrip('\x00')
+        change_lines = self._run_git(['status', '-z', '--untracked-files=all']).rstrip('\x00')
         if not change_lines:
             return {}  # No changes.
         unstaged_changes = {}
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
index 34b80cd..1c7ac25 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl.py
@@ -16,16 +16,23 @@
 
 _log = logging.getLogger(__name__)
 
+# A refresh token may be needed for some commands, such as git cl try,
+# in order to authenticate with buildbucket.
+_COMMANDS_THAT_TAKE_REFRESH_TOKEN = ('try',)
+
 
 class GitCL(object):
 
-    def __init__(self, host, cwd=None):
+    def __init__(self, host, auth_refresh_token_json=None, cwd=None):
         self._host = host
+        self._auth_refresh_token_json = auth_refresh_token_json
         self._cwd = cwd
 
     def run(self, args):
         """Runs git-cl with the given arguments and returns the output."""
         command = ['git', 'cl'] + args
+        if self._auth_refresh_token_json and args[0] in _COMMANDS_THAT_TAKE_REFRESH_TOKEN:
+            command += ['--auth-refresh-token-json', self._auth_refresh_token_json]
         return self._host.executive.run_command(command, cwd=self._cwd)
 
     def get_issue_number(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
index b30bccdc..f2ddfb5 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/net/git_cl_unittest.py
@@ -20,12 +20,21 @@
         self.assertEqual(output, 'mock-output')
         self.assertEqual(host.executive.calls, [['git', 'cl', 'command']])
 
-    def test_run_basic(self):
+    def test_run_with_auth(self):
         host = MockHost()
         host.executive = MockExecutive(output='mock-output')
-        git_cl = GitCL(host)
-        git_cl.run(['upload'])
-        self.assertEqual(host.executive.calls, [['git', 'cl', 'upload']])
+        git_cl = GitCL(host, auth_refresh_token_json='token.json')
+        git_cl.run(['try', '-b', 'win10_blink_rel'])
+        self.assertEqual(
+            host.executive.calls,
+            [['git', 'cl', 'try', '-b', 'win10_blink_rel', '--auth-refresh-token-json', 'token.json']])
+
+    def test_some_commands_not_run_with_auth(self):
+        host = MockHost()
+        host.executive = MockExecutive(output='mock-output')
+        git_cl = GitCL(host, auth_refresh_token_json='token.json')
+        git_cl.run(['issue'])
+        self.assertEqual(host.executive.calls, [['git', 'cl', 'issue']])
 
     def test_get_issue_number(self):
         host = MockHost()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 4bb5a936..2ef4840 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -55,7 +55,7 @@
         if not self.checkout_is_okay(options.allow_local_commits):
             return 1
 
-        self.git_cl = GitCL(self.host)
+        self.git_cl = GitCL(self.host, auth_refresh_token_json=options.auth_refresh_token_json)
 
         _log.debug('Noting the current Chromium commit.')
         _, show_ref_output = self.run(['git', 'show-ref', 'HEAD'])
@@ -124,7 +124,9 @@
         parser.add_argument('--auto-update', action='store_true',
                             help='uploads CL and initiates commit queue.')
         parser.add_argument('--auth-refresh-token-json',
-                            help='Auth refresh JSON token (ignored, deprecated)')
+                            help='authentication refresh token JSON file, '
+                                 'used for authentication for try jobs, '
+                                 'generally not necessary on developer machines')
         parser.add_argument('--ignore-exportable-commits', action='store_true',
                             help='Continue even if there are exportable commits that may be overwritten.')
         return parser.parse_args(argv)
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index a54cd2d0..df0613d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -97880,6 +97880,7 @@
   <int value="-138773929" label="PassiveDocumentEventListeners:enabled"/>
   <int value="-122492389" label="enable-browser-task-scheduler"/>
   <int value="-119055644" label="GenericSensor:enabled"/>
+  <int value="-108881882" label="NTPCondensedTileLayout:enabled"/>
   <int value="-102537270" label="extension-content-verification"/>
   <int value="-99781021" label="disable-roboto-font-ui"/>
   <int value="-89690053" label="MaterialDesignUserManager:enabled"/>
@@ -98060,6 +98061,7 @@
   <int value="684806628" label="TranslateLanguageByULP:disabled"/>
   <int value="689489984" label="disable-zero-suggest"/>
   <int value="690185633" label="NonValidatingReloadOnNormalReload:disabled"/>
+  <int value="691020108" label="NTPCondensedTileLayout:disabled"/>
   <int value="693012666" label="QuickUnlockPin:disabled"/>
   <int value="709850261" label="disable-touch-editing"/>
   <int value="711424932" label="enable-cloud-print-xps"/>
diff --git a/ui/app_list/search/mixer.cc b/ui/app_list/search/mixer.cc
index 0e8cdb33..78db4de 100644
--- a/ui/app_list/search/mixer.cc
+++ b/ui/app_list/search/mixer.cc
@@ -28,8 +28,7 @@
 
 }  // namespace
 
-Mixer::SortData::SortData() : result(NULL), score(0.0) {
-}
+Mixer::SortData::SortData() : result(nullptr), score(0.0) {}
 
 Mixer::SortData::SortData(SearchResult* result, double score)
     : result(result), score(score) {
@@ -47,21 +46,22 @@
       : max_results_(max_results), multiplier_(multiplier) {}
   ~Group() {}
 
-  void AddProvider(SearchProvider* provider) { providers_.push_back(provider); }
+  void AddProvider(SearchProvider* provider) {
+    providers_.emplace_back(provider);
+  }
 
   void FetchResults(bool is_voice_query, const KnownResults& known_results) {
     results_.clear();
 
     for (const SearchProvider* provider : providers_) {
-      for (SearchResult* result : provider->results()) {
+      for (const auto& result : provider->results()) {
         DCHECK(!result->id().empty());
 
         // We cannot rely on providers to give relevance scores in the range
         // [0.0, 1.0] (e.g., PeopleProvider directly gives values from the
         // Google+ API). Clamp to that range.
-        double relevance = std::min(std::max(result->relevance(), 0.0), 1.0);
-
-        double multiplier = multiplier_;
+        const double relevance =
+            std::min(std::max(result->relevance(), 0.0), 1.0);
         double boost = 0.0;
 
         // Recommendations should not be affected by query-to-launch correlation
@@ -97,7 +97,7 @@
             boost += 4.0;
         }
 
-        results_.push_back(SortData(result, relevance * multiplier + boost));
+        results_.emplace_back(result.get(), relevance * multiplier_ + boost);
       }
     }
 
@@ -145,7 +145,7 @@
   // Add results from each group. Limit to the maximum number of results in each
   // group.
   for (const Group* group : groups_) {
-    size_t num_results =
+    const size_t num_results =
         std::min(group->results().size(), group->max_results());
     results.insert(results.end(), group->results().begin(),
                    group->results().begin() + num_results);
@@ -157,8 +157,8 @@
   RemoveDuplicates(&results);
   std::sort(results.begin(), results.end());
 
-  if (results.size() < num_max_results) {
-    size_t original_size = results.size();
+  const size_t original_size = results.size();
+  if (original_size < num_max_results) {
     // We didn't get enough results. Insert all the results again, and this
     // time, do not limit the maximum number of results from each group. (This
     // will result in duplicates, which will be removed by RemoveDuplicates.)
@@ -192,7 +192,7 @@
   // meaningful indexes.
   auto current_results = ui_results->RemoveAll();
   std::map<std::string, std::unique_ptr<SearchResult>> ui_results_map;
-  for (std::unique_ptr<SearchResult>& ui_result : current_results)
+  for (auto& ui_result : current_results)
     ui_results_map[ui_result->id()] = std::move(ui_result);
 
   // Add items back to |ui_results| in the order of |new_results|.
@@ -227,12 +227,10 @@
 
   std::set<std::string> id_set;
   for (const SortData& sort_data : *results) {
-    const std::string& id = sort_data.result->id();
-    if (id_set.find(id) != id_set.end())
+    if (!id_set.insert(sort_data.result->id()).second)
       continue;
 
-    id_set.insert(id);
-    final.push_back(sort_data);
+    final.emplace_back(sort_data);
   }
 
   results->swap(final);
diff --git a/ui/app_list/search/tokenized_string.cc b/ui/app_list/search/tokenized_string.cc
index 232b3e1..887fe86 100644
--- a/ui/app_list/search/tokenized_string.cc
+++ b/ui/app_list/search/tokenized_string.cc
@@ -38,9 +38,9 @@
     const size_t word_start = break_iter.prev();
     TermBreakIterator term_iter(word);
     while (term_iter.Advance()) {
-      tokens_.push_back(base::i18n::ToLower(term_iter.GetCurrentTerm()));
-      mappings_.push_back(gfx::Range(word_start + term_iter.prev(),
-                                    word_start + term_iter.pos()));
+      tokens_.emplace_back(base::i18n::ToLower(term_iter.GetCurrentTerm()));
+      mappings_.emplace_back(word_start + term_iter.prev(),
+                             word_start + term_iter.pos());
     }
   }
 }
diff --git a/ui/app_list/search_controller.cc b/ui/app_list/search_controller.cc
index 64ea6b3..83cca8d 100644
--- a/ui/app_list/search_controller.cc
+++ b/ui/app_list/search_controller.cc
@@ -23,7 +23,7 @@
 namespace {
 
 // Maximum time (in milliseconds) to wait to the search providers to finish.
-const int kStopTimeMS = 1500;
+constexpr int kStopTimeMS = 1500;
 }
 
 namespace app_list {
@@ -43,11 +43,9 @@
   base::TrimWhitespace(search_box_->text(), base::TRIM_ALL, &query);
 
   dispatching_query_ = true;
-  for (Providers::iterator it = providers_.begin();
-       it != providers_.end();
-       ++it) {
-    (*it)->Start(is_voice_query, query);
-  }
+  for (const auto& provider : providers_)
+    provider->Start(is_voice_query, query);
+
   dispatching_query_ = false;
   query_for_recommendation_ = query.empty() ? true : false;
 
@@ -64,11 +62,8 @@
 void SearchController::Stop() {
   stop_timer_.Stop();
 
-  for (Providers::iterator it = providers_.begin();
-       it != providers_.end();
-       ++it) {
-    (*it)->Stop();
-  }
+  for (const auto& provider : providers_)
+    provider->Stop();
 }
 
 void SearchController::OpenResult(SearchResult* result, int event_flags) {
@@ -117,7 +112,7 @@
   provider->set_result_changed_callback(
       base::Bind(&SearchController::OnResultsChanged, base::Unretained(this)));
   mixer_->AddProviderToGroup(group_id, provider.get());
-  providers_.push_back(std::move(provider));
+  providers_.emplace_back(std::move(provider));
 }
 
 void SearchController::OnResultsChanged() {
diff --git a/ui/app_list/search_controller.h b/ui/app_list/search_controller.h
index 3fd9427..f8f69583 100644
--- a/ui/app_list/search_controller.h
+++ b/ui/app_list/search_controller.h
@@ -10,7 +10,6 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "base/timer/timer.h"
 #include "ui/app_list/app_list_export.h"
 #include "ui/app_list/app_list_model.h"
@@ -49,8 +48,6 @@
   void AddProvider(size_t group_id, std::unique_ptr<SearchProvider> provider);
 
  private:
-  typedef ScopedVector<SearchProvider> Providers;
-
   // Invoked when the search results are changed.
   void OnResultsChanged();
 
@@ -60,6 +57,8 @@
 
   // If true, the search results are shown on the launcher start page.
   bool query_for_recommendation_ = false;
+
+  using Providers = std::vector<std::unique_ptr<SearchProvider>>;
   Providers providers_;
   std::unique_ptr<Mixer> mixer_;
   History* history_;  // KeyedService, not owned.
diff --git a/ui/app_list/search_provider.cc b/ui/app_list/search_provider.cc
index 6d7bea8..a8887ee 100644
--- a/ui/app_list/search_provider.cc
+++ b/ui/app_list/search_provider.cc
@@ -16,7 +16,12 @@
 }
 
 void SearchProvider::Add(std::unique_ptr<SearchResult> result) {
-  results_.push_back(std::move(result));
+  results_.emplace_back(std::move(result));
+  FireResultChanged();
+}
+
+void SearchProvider::SwapResults(Results* new_results) {
+  results_.swap(*new_results);
   FireResultChanged();
 }
 
diff --git a/ui/app_list/search_provider.h b/ui/app_list/search_provider.h
index 22f0f2c1..406b4cf 100644
--- a/ui/app_list/search_provider.h
+++ b/ui/app_list/search_provider.h
@@ -6,10 +6,10 @@
 #define UI_APP_LIST_SEARCH_PROVIDER_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "ui/app_list/app_list_export.h"
 
@@ -19,8 +19,8 @@
 
 class APP_LIST_EXPORT SearchProvider {
  public:
-  typedef ScopedVector<SearchResult> Results;
-  typedef base::Closure ResultChangedCallback;
+  using Results = std::vector<std::unique_ptr<SearchResult>>;
+  using ResultChangedCallback = base::Closure;
 
   SearchProvider();
   virtual ~SearchProvider();
@@ -40,6 +40,12 @@
  protected:
   // Interface for the derived class to generate search results.
   void Add(std::unique_ptr<SearchResult> result);
+
+  // Swaps the internal results with |new_results|.
+  // This is useful when multiple results will be added, and the notification is
+  // desired to be done only once when all results are added.
+  void SwapResults(Results* new_results);
+
   void ClearResults();
 
  private:
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc
index fb19777..f7a48f5c 100644
--- a/ui/app_list/views/start_page_view.cc
+++ b/ui/app_list/views/start_page_view.cc
@@ -202,7 +202,6 @@
     search_result_tile_views_[i]->SetEnabled(true);
   }
 
-  Layout();
   parent()->Layout();
   // Add 1 to the results size to account for the all apps button.
   return display_results.size() + 1;
@@ -249,6 +248,7 @@
 
   // Add SearchResultTileItemViews to the container.
   int i = 0;
+  search_result_tile_views_.reserve(apps_num);
   for (; i < apps_num; ++i) {
     SearchResultTileItemView* tile_item =
         new SearchResultTileItemView(this, view_delegate_);
@@ -258,7 +258,7 @@
     AddChildView(tile_item);
     tile_item->SetParentBackgroundColor(kLabelBackgroundColor);
     tile_item->SetHoverStyle(TileItemView::HOVER_STYLE_ANIMATE_SHADOW);
-    search_result_tile_views_.push_back(tile_item);
+    search_result_tile_views_.emplace_back(tile_item);
   }
 
   // Also add a special "all apps" button to the end of the container.
@@ -294,7 +294,6 @@
   AddChildView(custom_launcher_page_background_);
 
   tiles_container_->SetResults(view_delegate_->GetModel()->results());
-  Reset();
 }
 
 StartPageView::~StartPageView() {
diff --git a/ui/display/manager/chromeos/display_change_observer.cc b/ui/display/manager/chromeos/display_change_observer.cc
index 95a1e57..f4206c7e83 100644
--- a/ui/display/manager/chromeos/display_change_observer.cc
+++ b/ui/display/manager/chromeos/display_change_observer.cc
@@ -293,8 +293,6 @@
   const auto& cached_displays = display_configurator_->cached_displays();
   if (!cached_displays.empty())
     OnDisplayModeChanged(cached_displays);
-  else
-    VLOG(1) << "Not updating touchscreen associations";
 }
 
 // static
diff --git a/ui/display/manager/chromeos/touchscreen_util.cc b/ui/display/manager/chromeos/touchscreen_util.cc
index 31dbf2f6..aaa0996 100644
--- a/ui/display/manager/chromeos/touchscreen_util.cc
+++ b/ui/display/manager/chromeos/touchscreen_util.cc
@@ -276,7 +276,7 @@
   AssociateToSingleDisplay(&displays, &devices);
 
   for (const ManagedDisplayInfo* display : displays)
-    LOG(WARNING) << "Unmatched display " << display->name();
+    VLOG(2) << "Unmatched display " << display->name();
   for (const ui::TouchscreenDevice* device : devices)
     LOG(WARNING) << "Unmatched device " << device->name;
 }
diff --git a/ui/views/controls/slider.cc b/ui/views/controls/slider.cc
index 219ebf6c..eacd6aa2 100644
--- a/ui/views/controls/slider.cc
+++ b/ui/views/controls/slider.cc
@@ -243,14 +243,26 @@
 }
 
 bool Slider::OnKeyPressed(const ui::KeyEvent& event) {
-  float new_value = value_;
-  if (event.key_code() == ui::VKEY_LEFT)
-    new_value -= keyboard_increment_;
-  else if (event.key_code() == ui::VKEY_RIGHT)
-    new_value += keyboard_increment_;
-  else
-    return false;
-  SetValueInternal(new_value, VALUE_CHANGED_BY_USER);
+  int direction = 1;
+  switch (event.key_code()) {
+    case ui::VKEY_LEFT:
+      direction = base::i18n::IsRTL() ? 1 : -1;
+      break;
+    case ui::VKEY_RIGHT:
+      direction = base::i18n::IsRTL() ? -1 : 1;
+      break;
+    case ui::VKEY_UP:
+      direction = 1;
+      break;
+    case ui::VKEY_DOWN:
+      direction = -1;
+      break;
+
+    default:
+      return false;
+  }
+  SetValueInternal(value_ + direction * keyboard_increment_,
+                   VALUE_CHANGED_BY_USER);
   return true;
 }
 
diff --git a/ui/views/controls/slider_unittest.cc b/ui/views/controls/slider_unittest.cc
index 44893c9..6bd6706 100644
--- a/ui/views/controls/slider_unittest.cc
+++ b/ui/views/controls/slider_unittest.cc
@@ -262,10 +262,8 @@
   // Scroll below the minimum.
   slider()->SetValue(0.5);
   event_generator()->GestureScrollSequence(
-    gfx::Point(0.5 * max_x(), 0.5 * max_y()),
-    gfx::Point(0, 0),
-    base::TimeDelta::FromMilliseconds(10),
-    5 /* steps */);
+      gfx::Point(0.5 * max_x(), 0.5 * max_y()), gfx::Point(0, 0),
+      base::TimeDelta::FromMilliseconds(10), 5 /* steps */);
   EXPECT_EQ(0, slider()->value());
 
   // Scroll above the maximum.
@@ -278,10 +276,9 @@
   // Scroll somewhere in the middle.
   slider()->SetValue(0.25);
   event_generator()->GestureScrollSequence(
-    gfx::Point(0.25 * max_x(), 0.25 * max_y()),
-    gfx::Point(0.75 * max_x(), 0.75 * max_y()),
-    base::TimeDelta::FromMilliseconds(10),
-    5 /* steps */);
+      gfx::Point(0.25 * max_x(), 0.25 * max_y()),
+      gfx::Point(0.75 * max_x(), 0.75 * max_y()),
+      base::TimeDelta::FromMilliseconds(10), 5 /* steps */);
   EXPECT_NEAR(0.75, slider()->value(), 0.03);
 }
 
@@ -296,6 +293,33 @@
   slider()->SetValue(value);
   event_generator()->PressKey(ui::VKEY_LEFT, 0);
   EXPECT_LT(slider()->value(), value);
+
+  slider()->SetValue(value);
+  event_generator()->PressKey(ui::VKEY_UP, 0);
+  EXPECT_GT(slider()->value(), value);
+
+  slider()->SetValue(value);
+  event_generator()->PressKey(ui::VKEY_DOWN, 0);
+  EXPECT_LT(slider()->value(), value);
+
+  // RTL reverse left/right but not up/down.
+  base::i18n::SetICUDefaultLocale("he");
+  EXPECT_TRUE(base::i18n::IsRTL());
+
+  event_generator()->PressKey(ui::VKEY_RIGHT, 0);
+  EXPECT_LT(slider()->value(), value);
+
+  slider()->SetValue(value);
+  event_generator()->PressKey(ui::VKEY_LEFT, 0);
+  EXPECT_GT(slider()->value(), value);
+
+  slider()->SetValue(value);
+  event_generator()->PressKey(ui::VKEY_UP, 0);
+  EXPECT_GT(slider()->value(), value);
+
+  slider()->SetValue(value);
+  event_generator()->PressKey(ui::VKEY_DOWN, 0);
+  EXPECT_LT(slider()->value(), value);
 }
 
 // Verifies the correct SliderListener events are raised for a tap gesture.