diff --git a/DEPS b/DEPS
index 43651905..9c0028f18 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': 'a8e5744afadd20e217a7c70099a79a222d2e7e4f',
+  'skia_revision': 'ff72a0857f4d1b13f3fe9f8d99020e04e2507729',
   # 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': '726c1912373d6c58237b2c4d8dd1e5aad2a81d7c',
+  'v8_revision': 'e3965fde0b4bf12c604660290921c8c1e7a3fa09',
   # 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.
@@ -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': 'd5df04f53ce84b12550e46a8a9d5ff496d73bb01',
+  'catapult_revision': '4298cb322ef35220f7d3c6a195dc5f6a8e76c620',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/build/android/findbugs_filter/findbugs_exclude.xml b/build/android/findbugs_filter/findbugs_exclude.xml
index d5c4476..0bbab67 100644
--- a/build/android/findbugs_filter/findbugs_exclude.xml
+++ b/build/android/findbugs_filter/findbugs_exclude.xml
@@ -32,7 +32,7 @@
   -->
   <Bug pattern="BC_UNCONFIRMED_CAST" />
 
-  <!-- Ignore unused public rules and implementations thereof in instrumentation tests -->
+  <!-- Ignore unused public Rule and RuleChain in instrumentation tests -->
   <Match>
     <Class name="~.*\.*Test" />
     <Field type="android.support.test.rule.UiThreadTestRule" />
@@ -43,10 +43,5 @@
     <Field type="org.junit.rules.RuleChain" />
     <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD" />
   </Match>
-  <Match>
-    <Class name="~.*\.*Test" />
-    <Field type="org.junit.rules.TestRule" />
-    <Bug pattern="URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD" />
-  </Match>
 
 </FindBugsFilter>
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index 51fe1c1..3d7f41e 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -17,7 +17,6 @@
 #include "cc/test/fake_raster_source.h"
 #include "cc/test/fake_recording_source.h"
 #include "cc/test/pixel_test.h"
-#include "cc/test/test_in_process_context_provider.h"
 #include "components/viz/service/display/gl_renderer.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "media/base/video_frame.h"
@@ -303,20 +302,10 @@
     bits_per_channel = 10;
   }
 
-  viz::ResourceFormat yuv_highbit_resource_format =
-      resource_provider->YuvResourceFormat(bits_per_channel);
-
-  float multiplier = 1.0;
-
-  if (yuv_highbit_resource_format != viz::R16_EXT)
-    bits_per_channel = 8;
-  else
-    multiplier = 65535.0f / ((1 << bits_per_channel) - 1);
-
   yuv_quad->SetNew(shared_state, rect, visible_rect, needs_blending,
                    ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size,
                    uv_tex_size, y_resource, u_resource, v_resource, a_resource,
-                   color_space, video_color_space, 0.0f, multiplier,
+                   color_space, video_color_space, 0.0f, 1.0f,
                    bits_per_channel);
 }
 
@@ -1315,35 +1304,9 @@
   std::unique_ptr<VideoResourceUpdater> video_resource_updater_;
 };
 
-enum class HighbitTexture {
-  Y8,
-  R16_EXT,
-};
-
 class VideoGLRendererPixelHiLoTest
     : public VideoGLRendererPixelTest,
-      public ::testing::WithParamInterface<
-          ::testing::tuple<bool, HighbitTexture>> {
- public:
-  void SetSupportHighbitTexture(HighbitTexture texture) {
-    TestInProcessContextProvider* context_provider =
-        GetTestInProcessContextProvider();
-    switch (texture) {
-      case HighbitTexture::Y8:
-        break;
-      case HighbitTexture::R16_EXT:
-        context_provider->SetSupportTextureNorm16(true);
-        video_resource_updater_->SetUseR16ForTesting(true);
-        break;
-    }
-  }
-
- private:
-  TestInProcessContextProvider* GetTestInProcessContextProvider() {
-    return static_cast<TestInProcessContextProvider*>(
-        output_surface_->context_provider());
-  }
-};
+      public ::testing::WithParamInterface<bool> {};
 
 TEST_P(VideoGLRendererPixelHiLoTest, SimpleYUVRect) {
   gfx::Rect rect(this->device_viewport_size_);
@@ -1357,10 +1320,7 @@
   SharedQuadState* shared_state =
       CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
 
-  const bool highbit = testing::get<0>(GetParam());
-  const HighbitTexture format = testing::get<1>(GetParam());
-  SetSupportHighbitTexture(format);
-
+  bool highbit = GetParam();
   CreateTestYUVVideoDrawQuad_Striped(
       shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_SD_REC601,
       false, highbit, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
@@ -1389,10 +1349,7 @@
   SharedQuadState* shared_state =
       CreateTestSharedQuadState(gfx::Transform(), viewport, pass.get());
 
-  const bool highbit = testing::get<0>(GetParam());
-  const HighbitTexture format = testing::get<1>(GetParam());
-  SetSupportHighbitTexture(format);
-
+  bool highbit = GetParam();
   CreateTestYUVVideoDrawQuad_Striped(
       shared_state, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_SD_REC601,
       false, highbit, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
@@ -1461,12 +1418,7 @@
 }
 
 // First argument (test case prefix) is intentionally left empty.
-INSTANTIATE_TEST_CASE_P(
-    ,
-    VideoGLRendererPixelHiLoTest,
-    testing::Combine(testing::Bool(),
-                     testing::Values(HighbitTexture::Y8,
-                                     HighbitTexture::R16_EXT)));
+INSTANTIATE_TEST_CASE_P(, VideoGLRendererPixelHiLoTest, ::testing::Bool());
 
 TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
   gfx::Rect rect(this->device_viewport_size_);
diff --git a/cc/raster/raster_buffer_provider.cc b/cc/raster/raster_buffer_provider.cc
index 081aaf5..1eb0fd03 100644
--- a/cc/raster/raster_buffer_provider.cc
+++ b/cc/raster/raster_buffer_provider.cc
@@ -37,7 +37,6 @@
     case viz::RED_8:
     case viz::LUMINANCE_F16:
     case viz::RGBA_F16:
-    case viz::R16_EXT:
       return false;
   }
   NOTREACHED();
@@ -131,7 +130,6 @@
     case viz::RGB_565:
     case viz::RED_8:
     case viz::LUMINANCE_F16:
-    case viz::R16_EXT:
       NOTREACHED();
       return;
   }
@@ -155,7 +153,6 @@
     case viz::RED_8:
     case viz::LUMINANCE_F16:
     case viz::RGBA_F16:
-    case viz::R16_EXT:
       return false;
   }
   NOTREACHED();
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index ce45d13..b9ed1ba 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -106,7 +106,6 @@
     case viz::ETC1:
     case viz::RED_8:
     case viz::LUMINANCE_F16:
-    case viz::R16_EXT:
       NOTREACHED();
       break;
   }
@@ -128,7 +127,6 @@
     case viz::ETC1:
     case viz::RED_8:
     case viz::LUMINANCE_F16:
-    case viz::R16_EXT:
       return false;
   }
   return false;
@@ -327,9 +325,6 @@
     : default_resource_type(resource_settings.use_gpu_memory_buffer_resources
                                 ? RESOURCE_TYPE_GPU_MEMORY_BUFFER
                                 : RESOURCE_TYPE_GL_TEXTURE),
-      yuv_highbit_resource_format(resource_settings.high_bit_for_testing
-                                      ? viz::R16_EXT
-                                      : viz::LUMINANCE_8),
       enable_color_correct_rasterization(enable_color_correct_rasterization),
       delegated_sync_points_required(delegated_sync_points_required) {
   if (!compositor_context_provider) {
@@ -352,10 +347,9 @@
     yuv_resource_format = yuv_highbit_resource_format = viz::RGBA_8888;
   } else {
     yuv_resource_format = caps.texture_rg ? viz::RED_8 : viz::LUMINANCE_8;
-    if (resource_settings.use_r16_texture && caps.texture_norm16)
-      yuv_highbit_resource_format = viz::R16_EXT;
-    else if (caps.texture_half_float_linear)
-      yuv_highbit_resource_format = viz::LUMINANCE_F16;
+    yuv_highbit_resource_format = caps.texture_half_float_linear
+                                      ? viz::LUMINANCE_F16
+                                      : yuv_resource_format;
   }
 
   GLES2Interface* gl = compositor_context_provider->ContextGL();
@@ -455,8 +449,6 @@
       return caps.texture_format_etc1;
     case viz::RED_8:
       return caps.texture_rg;
-    case viz::R16_EXT:
-      return caps.texture_norm16;
     case viz::LUMINANCE_F16:
     case viz::RGBA_F16:
       return caps.texture_half_float_linear;
@@ -490,7 +482,6 @@
     case viz::RED_8:
     case viz::ETC1:
     case viz::LUMINANCE_F16:
-    case viz::R16_EXT:
       // We don't currently render into these formats. If we need to render into
       // these eventually, we should expand this logic.
       return false;
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index f573170..f27a011 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -464,29 +464,12 @@
   }
 
   std::unique_ptr<media::HalfFloatMaker> half_float_maker;
-
-  switch (resource_provider_->YuvResourceFormat(bits_per_channel)) {
-    case viz::LUMINANCE_F16:
-      half_float_maker =
-          media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel);
-      external_resources.offset = half_float_maker->Offset();
-      external_resources.multiplier = half_float_maker->Multiplier();
-      break;
-    case viz::R16_EXT:
-      external_resources.multiplier = 65535.0f / ((1 << bits_per_channel) - 1);
-      external_resources.offset = 0;
-      break;
-    case viz::LUMINANCE_8:
-    case viz::RED_8:
-      break;
-    case viz::ALPHA_8:
-    case viz::RGBA_8888:
-    case viz::RGBA_4444:
-    case viz::BGRA_8888:
-    case viz::RGB_565:
-    case viz::ETC1:
-    case viz::RGBA_F16:
-      NOTREACHED();
+  if (resource_provider_->YuvResourceFormat(bits_per_channel) ==
+      viz::LUMINANCE_F16) {
+    half_float_maker =
+        media::HalfFloatMaker::NewHalfFloatMaker(bits_per_channel);
+    external_resources.offset = half_float_maker->Offset();
+    external_resources.multiplier = half_float_maker->Multiplier();
   }
 
   for (size_t i = 0; i < plane_resources.size(); ++i) {
@@ -521,9 +504,6 @@
       // step.
       if (plane_resource.resource_format() == viz::LUMINANCE_F16) {
         needs_conversion = true;
-      } else if (plane_resource.resource_format() == viz::R16_EXT) {
-        // R16_EXT can represent 16-bit int, so we don't need a conversion step.
-        needs_conversion = false;
       } else if (bits_per_channel > 8) {
         // If bits_per_channel > 8 and we can't use viz::LUMINANCE_F16, we need
         // to shift the data down and create an 8-bit texture.
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 50ec17c..a7ac7e5 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -86,10 +86,6 @@
   VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
       scoped_refptr<media::VideoFrame> video_frame);
 
-  void SetUseR16ForTesting(bool use_r16_for_testing) {
-    use_r16_for_testing_ = use_r16_for_testing;
-  }
-
  private:
   class PlaneResource {
    public:
@@ -188,7 +184,6 @@
   const bool use_stream_video_draw_quad_;
   std::unique_ptr<media::SkCanvasVideoRenderer> video_renderer_;
   std::vector<uint8_t> upload_pixels_;
-  bool use_r16_for_testing_ = false;
 
   // Recycle resources so that we can reduce the number of allocations and
   // data transfers.
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 3054a23..8c0f6ca6 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -105,12 +105,12 @@
 
   void SetUp() override {
     testing::Test::SetUp();
+
     shared_bitmap_manager_.reset(new SharedBitmapManagerAllocationCounter());
     resource_provider3d_ = FakeResourceProvider::Create(
-        context_provider_.get(), shared_bitmap_manager_.get(),
-        high_bit_for_testing_);
-    resource_provider_software_ = FakeResourceProvider::Create(
-        nullptr, shared_bitmap_manager_.get(), high_bit_for_testing_);
+        context_provider_.get(), shared_bitmap_manager_.get());
+    resource_provider_software_ =
+        FakeResourceProvider::Create(nullptr, shared_bitmap_manager_.get());
   }
 
   scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
@@ -251,7 +251,6 @@
   std::unique_ptr<ResourceProvider> resource_provider3d_;
   std::unique_ptr<ResourceProvider> resource_provider_software_;
   gpu::SyncToken release_sync_token_;
-  bool high_bit_for_testing_;
 };
 
 const gpu::SyncToken VideoResourceUpdaterTest::kMailboxSyncToken =
@@ -313,40 +312,6 @@
   EXPECT_NEAR(resources2.offset, 0.5, 0.1);
 }
 
-class VideoResourceUpdaterTestWithR16 : public VideoResourceUpdaterTest {
- public:
-  VideoResourceUpdaterTestWithR16() : VideoResourceUpdaterTest() {
-    high_bit_for_testing_ = true;
-    context3d_->set_support_texture_norm16(true);
-  }
-};
-
-TEST_F(VideoResourceUpdaterTestWithR16, HighBitFrame) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
-  updater.SetUseR16ForTesting(true);
-  scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
-
-  VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
-
-  // Max 10-bit values as read by a sampler.
-  double max_10bit_value = ((1 << 10) - 1) / 65535.0;
-  EXPECT_NEAR(resources.multiplier * max_10bit_value, 1.0, 0.0001);
-  EXPECT_NEAR(resources.offset, 0.0, 0.1);
-
-  // Create the resource again, to test the path where the
-  // resources are cached.
-  VideoFrameExternalResources resources2 =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources2.type);
-  EXPECT_NEAR(resources2.multiplier * max_10bit_value, 1.0, 0.0001);
-  EXPECT_NEAR(resources2.offset, 0.0, 0.1);
-}
-
 TEST_F(VideoResourceUpdaterTest, HighBitFrameSoftwareCompositor) {
   bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
diff --git a/cc/test/fake_resource_provider.h b/cc/test/fake_resource_provider.h
index 07e7638..e5ecb355 100644
--- a/cc/test/fake_resource_provider.h
+++ b/cc/test/fake_resource_provider.h
@@ -18,13 +18,11 @@
  public:
   static std::unique_ptr<FakeResourceProvider> Create(
       viz::ContextProvider* context_provider,
-      viz::SharedBitmapManager* shared_bitmap_manager,
-      bool high_bit_for_testing = false) {
+      viz::SharedBitmapManager* shared_bitmap_manager) {
     viz::ResourceSettings resource_settings;
     resource_settings.texture_id_allocation_chunk_size = 1;
     resource_settings.buffer_to_texture_target_map =
         viz::DefaultBufferToTextureTargetMapForTesting();
-    resource_settings.high_bit_for_testing = high_bit_for_testing;
     return base::WrapUnique(new FakeResourceProvider(
         context_provider, shared_bitmap_manager, nullptr, nullptr, true, false,
         resource_settings));
@@ -46,13 +44,11 @@
   static std::unique_ptr<FakeResourceProvider> Create(
       viz::ContextProvider* context_provider,
       viz::SharedBitmapManager* shared_bitmap_manager,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      bool high_bit_for_testing = false) {
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
     viz::ResourceSettings resource_settings;
     resource_settings.texture_id_allocation_chunk_size = 1;
     resource_settings.buffer_to_texture_target_map =
         viz::DefaultBufferToTextureTargetMapForTesting();
-    resource_settings.high_bit_for_testing = high_bit_for_testing;
     return base::WrapUnique(new FakeResourceProvider(
         context_provider, shared_bitmap_manager, gpu_memory_buffer_manager,
         nullptr, true, false, resource_settings));
diff --git a/cc/test/test_context_provider.cc b/cc/test/test_context_provider.cc
index 7ae32d0..1243e35 100644
--- a/cc/test/test_context_provider.cc
+++ b/cc/test/test_context_provider.cc
@@ -28,9 +28,9 @@
 
 // Various tests rely on functionality (capabilities) enabled by these extension
 // strings.
-const char* const kExtensions[] = {
-    "GL_EXT_stencil_wrap", "GL_EXT_texture_format_BGRA8888",
-    "GL_OES_rgb8_rgba8", "GL_EXT_texture_norm16"};
+const char* const kExtensions[] = {"GL_EXT_stencil_wrap",
+                                   "GL_EXT_texture_format_BGRA8888",
+                                   "GL_OES_rgb8_rgba8"};
 
 class TestGLES2InterfaceForContextProvider : public TestGLES2Interface {
  public:
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 1ca0806..6c566277 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -110,7 +110,6 @@
   gpu::Capabilities capabilities;
   capabilities.texture_rectangle = true;
   capabilities.sync_query = true;
-  capabilities.texture_norm16 = true;
   switch (viz::PlatformColor::Format()) {
     case viz::PlatformColor::SOURCE_FORMAT_RGBA8:
       capabilities.texture_format_bgra8888 = false;
diff --git a/cc/test/test_in_process_context_provider.h b/cc/test/test_in_process_context_provider.h
index 3568792b..7e3033a9 100644
--- a/cc/test/test_in_process_context_provider.h
+++ b/cc/test/test_in_process_context_provider.h
@@ -49,9 +49,6 @@
   gpu::Capabilities ContextCapabilities() override;
   void SetLostContextCallback(
       const LostContextCallback& lost_context_callback) override;
-  void SetSupportTextureNorm16(bool support) {
-    capabilities_texture_norm16_ = support;
-  }
 
  protected:
   friend class base::RefCountedThreadSafe<TestInProcessContextProvider>;
@@ -64,7 +61,6 @@
   std::unique_ptr<skia_bindings::GrContextForGLES2Interface> gr_context_;
   std::unique_ptr<viz::ContextCacheController> cache_controller_;
   base::Lock context_lock_;
-  bool capabilities_texture_norm16_ = false;
 };
 
 }  // namespace cc
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index ea35d2ac..c50893f90 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -344,9 +344,6 @@
   void set_support_texture_half_float_linear(bool support) {
     test_capabilities_.texture_half_float_linear = support;
   }
-  void set_support_texture_norm16(bool support) {
-    test_capabilities_.texture_norm16 = support;
-  }
   void set_msaa_is_slow(bool msaa_is_slow) {
     test_capabilities_.msaa_is_slow = msaa_is_slow;
   }
diff --git a/chrome/android/java/res/layout/content_suggestions_card_modern.xml b/chrome/android/java/res/layout/content_suggestions_card_modern.xml
index 4fdc09c..8a2cbf57 100644
--- a/chrome/android/java/res/layout/content_suggestions_card_modern.xml
+++ b/chrome/android/java/res/layout/content_suggestions_card_modern.xml
@@ -6,116 +6,35 @@
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:chrome="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     style="@style/SuggestionCardModern"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">
 
-    <!-- This layout is nested inside another layout so that we can align the thumbnail corners
-         relative to it. The corners are aligned with respect to the whole card, in case the card
-         contents are taller than the thumbnail. -->
-    <RelativeLayout
-        android:id="@+id/card_contents"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+    <org.chromium.chrome.browser.widget.TintedImageView
+        android:id="@+id/article_thumbnail"
+        android:layout_width="@dimen/snippets_thumbnail_size_large"
+        android:layout_height="@dimen/snippets_thumbnail_size_large"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
+        android:scaleType="centerCrop"
+        android:contentDescription="@null"
+        android:src="@null"
+        tools:src="@drawable/ic_snippet_thumbnail_placeholder" />
 
-        <org.chromium.chrome.browser.widget.TintedImageView
-            android:id="@+id/article_thumbnail"
-            android:layout_width="@dimen/snippets_thumbnail_size_large"
-            android:layout_height="@dimen/snippets_thumbnail_size_large"
-            android:layout_alignParentTop="true"
-            android:layout_alignParentStart="true"
-            android:scaleType="centerCrop"
-            android:contentDescription="@null"
-            android:src="@null"
-            tools:src="@drawable/ic_snippet_thumbnail_placeholder" />
-
-        <ImageView
-            android:id="@+id/offline_icon"
-            android:layout_width="@dimen/content_suggestions_card_modern_offline_badge_overlay_size"
-            android:layout_height=
-                    "@dimen/content_suggestions_card_modern_offline_badge_overlay_size"
-            android:layout_alignTop="@id/article_thumbnail"
-            android:layout_alignStart="@id/article_thumbnail"
-            android:layout_marginStart=
-                    "@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_start"
-            android:layout_marginTop=
-                    "@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_top"
-            android:contentDescription="@null"
-            android:visibility="gone"
-            app:srcCompat="@drawable/ic_offline_pin_white"
-            tools:src="@drawable/ic_offline_pin_white"/>
-
-        <LinearLayout
-            android:id="@+id/text_layout"
-            android:layout_alignParentEnd="true"
-            android:layout_alignParentTop="true"
-            android:layout_toEndOf="@+id/article_thumbnail"
-            android:layout_alignWithParentIfMissing="true"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:padding="@dimen/snippets_padding"
-            android:orientation="vertical">
-
-            <org.chromium.ui.widget.TextViewWithLeading
-                style="@style/SuggestionCardTitleModern"
-                android:id="@+id/article_headline"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                tools:text="Article headline" />
-
-            <org.chromium.ui.widget.TextViewWithLeading
-                style="@style/SuggestionCardBodyModern"
-                android:id="@+id/article_snippet"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="8dp"
-                android:maxLines="2"
-                tools:text="Article snippet" />
-
-            <LinearLayout
-                tools:ignore="UseCompoundDrawables"
-                android:id="@+id/publisher_bar"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="@dimen/snippets_publisher_margin_top_with_article_snippet"
-                android:orientation="horizontal">
-
-                <!-- The following attributes:
-                     - publisher_bar's android:layout_width="wrap_content"
-                     - article_publisher's android:layout_width="0dp"
-                     - article_publisher's android:layout_weight="1"
-                     - article_publisher's android:ellipsize="end"
-                     - article_age's android:layout_width="wrap_content"
-                     All ensure that when the publisher string is long, it starts to ellipsize
-                     before pushing the article age string and the offline icon off the screen.
-                     See: https://crbug.com/625775 and https://crbug.com/678568 -->
-                <TextView
-                    android:id="@+id/article_publisher"
-                    android:layout_width="0dp"
-                    android:layout_weight="1"
-                    android:layout_height="wrap_content"
-                    android:drawablePadding="8dp"
-                    android:maxLines="1"
-                    android:singleLine="true"
-                    android:ellipsize="end"
-                    android:textSize="12sp"
-                    android:textColor="@color/snippets_publisher_name_color"
-                    android:textDirection="locale"
-                    tools:text="chromium.org"/>
-                <TextView
-                    android:id="@+id/article_age"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:maxLines="1"
-                    android:textSize="12sp"
-                    android:textColor="@color/snippets_publisher_name_color"
-                    android:textDirection="locale"
-                    tools:text=" - 3 hours ago" />
-            </LinearLayout>
-        </LinearLayout>
-    </RelativeLayout>
+    <ImageView
+        android:id="@+id/offline_icon"
+        android:layout_width="@dimen/content_suggestions_card_modern_offline_badge_overlay_size"
+        android:layout_height="@dimen/content_suggestions_card_modern_offline_badge_overlay_size"
+        android:layout_alignTop="@id/article_thumbnail"
+        android:layout_alignStart="@id/article_thumbnail"
+        android:layout_marginStart="@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_start"
+        android:layout_marginTop="@dimen/content_suggestions_card_modern_offline_badge_overlay_margin_top"
+        android:contentDescription="@null"
+        android:visibility="gone"
+        app:srcCompat="@drawable/ic_offline_pin_white"
+        tools:src="@drawable/ic_offline_pin_white"/>
 
     <!-- It would have been nice to use RoundedBitmapDrawable on the thumbnail, but with that you
          cannot select which corners must be rounded, they are all rounded. -->
@@ -123,7 +42,7 @@
         android:id="@+id/corner_top"
         android:layout_width="@dimen/content_suggestions_card_modern_corner_radius"
         android:layout_height="@dimen/content_suggestions_card_modern_corner_radius"
-        android:layout_alignTop="@id/card_contents"
+        android:layout_alignParentTop="true"
         android:layout_alignParentStart="true"
         android:contentDescription="@null"
         android:scaleX="@integer/automirror_scale_x"
@@ -133,10 +52,79 @@
         android:id="@+id/corner_bottom"
         android:layout_width="@dimen/content_suggestions_card_modern_corner_radius"
         android:layout_height="@dimen/content_suggestions_card_modern_corner_radius"
-        android:layout_alignBottom="@id/card_contents"
+        android:layout_alignParentBottom="true"
         android:layout_alignParentStart="true"
         android:contentDescription="@null"
         android:scaleX="@integer/automirror_scale_x"
         app:srcCompat="@drawable/content_suggestions_card_corner_bottom" />
 
+    <LinearLayout
+        android:id="@+id/text_layout"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@+id/article_thumbnail"
+        android:layout_alignWithParentIfMissing="true"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:padding="@dimen/snippets_padding"
+        android:orientation="vertical">
+
+        <org.chromium.ui.widget.TextViewWithLeading
+            style="@style/SuggestionCardTitleModern"
+            android:id="@+id/article_headline"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            tools:text="Article headline" />
+
+        <org.chromium.ui.widget.TextViewWithLeading
+            style="@style/SuggestionCardBodyModern"
+            android:id="@+id/article_snippet"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="8dp"
+            android:maxLines="2"
+            tools:text="Article snippet" />
+
+        <LinearLayout
+            tools:ignore="UseCompoundDrawables"
+            android:id="@+id/publisher_bar"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="@dimen/snippets_publisher_margin_top_with_article_snippet"
+            android:orientation="horizontal">
+
+            <!-- The following attributes:
+                 - publisher_bar's android:layout_width="wrap_content"
+                 - article_publisher's android:layout_width="0dp"
+                 - article_publisher's android:layout_weight="1"
+                 - article_publisher's android:ellipsize="end"
+                 - article_age's android:layout_width="wrap_content"
+                 All ensure that when the publisher string is long, it starts to ellipsize before
+                 pushing the article age string and the offline icon off the screen.
+                 See: https://crbug.com/625775 and https://crbug.com/678568 -->
+            <TextView
+                android:id="@+id/article_publisher"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="wrap_content"
+                android:drawablePadding="8dp"
+                android:maxLines="1"
+                android:singleLine="true"
+                android:ellipsize="end"
+                android:textSize="12sp"
+                android:textColor="@color/snippets_publisher_name_color"
+                android:textDirection="locale"
+                tools:text="chromium.org"/>
+            <TextView
+                android:id="@+id/article_age"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:maxLines="1"
+                android:textSize="12sp"
+                android:textColor="@color/snippets_publisher_name_color"
+                android:textDirection="locale"
+                tools:text=" - 3 hours ago" />
+        </LinearLayout>
+    </LinearLayout>
 </RelativeLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
index f4b27ce..8b37705f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderService.java
@@ -14,9 +14,12 @@
 import android.os.SystemClock;
 
 import org.chromium.base.Log;
+import org.chromium.base.PathUtils;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.LibraryLoader;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
+import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -42,6 +45,12 @@
     @Override
     public void onCreate() {
         try {
+            // The decoder service relies on PathUtils.
+            ThreadUtils.runOnUiThreadBlocking(() -> {
+                PathUtils.setPrivateDataDirectorySuffix(
+                        ChromeBrowserInitializer.PRIVATE_DATA_DIRECTORY_SUFFIX);
+            });
+
             LibraryLoader.get(LibraryProcessType.PROCESS_CHILD).ensureInitialized();
             nativeInitializePhotoPickerSandbox();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 68eac91..6de9f4a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -4,9 +4,6 @@
 
 package org.chromium.chrome.browser.ntp.snippets;
 
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
@@ -22,31 +19,35 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TestRule;
+import org.junit.rules.ExternalResource;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.Callback;
-import org.chromium.base.CommandLine;
 import org.chromium.base.DiscardableReferencePool;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
-import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
-import org.chromium.base.test.params.ParameterSet;
-import org.chromium.base.test.params.ParameterizedRunner;
+import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.base.test.util.UrlUtils;
+import org.chromium.base.test.util.parameter.CommandLineParameter;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
 import org.chromium.chrome.browser.download.ui.ThumbnailProvider;
 import org.chromium.chrome.browser.download.ui.ThumbnailProvider.ThumbnailRequest;
 import org.chromium.chrome.browser.favicon.LargeIconBridge;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.ContextMenuManager.TouchEnabledDelegate;
+import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
 import org.chromium.chrome.browser.ntp.cards.SignInPromo;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.suggestions.ContentSuggestionsAdditionalAction;
 import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.ImageFetcher;
@@ -61,9 +62,8 @@
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 import org.chromium.chrome.browser.widget.displaystyle.VerticalDisplayStyle;
 import org.chromium.chrome.test.ChromeActivityTestRule;
-import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.RenderTestRule;
-import org.chromium.chrome.test.util.browser.compositor.layouts.DisableChromeAnimations;
 import org.chromium.chrome.test.util.browser.suggestions.DummySuggestionsEventReporter;
 import org.chromium.chrome.test.util.browser.suggestions.FakeSuggestionsSource;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
@@ -77,8 +77,7 @@
 /**
  * Tests for the appearance of Article Snippets.
  */
-@RunWith(ParameterizedRunner.class)
-@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
+@RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
         ChromeActivityTestRule.DISABLE_NETWORK_PREDICTION_FLAG})
 public class ArticleSnippetsTest {
@@ -88,184 +87,159 @@
     @Rule
     public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
             new ChromeActivityTestRule<>(ChromeActivity.class);
-
     @Rule
     public RenderTestRule mRenderTestRule =
             new RenderTestRule("chrome/test/data/android/render_tests");
 
+    // Rules must be public for JUnit to access them, but FindBugs complains about that.
+    @SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
     @Rule
-    public TestRule mDisableChromeAnimations = new DisableChromeAnimations();
+    public ExternalResource mDisableChromeAnimationsRule = new ExternalResource() {
 
-    private final boolean mChromeHomeEnabled;
+        private float mOldAnimationMultiplier;
 
-    @ClassParameter
-    private static List<ParameterSet> sClassParams = Arrays.asList(
-            new ParameterSet().name("ChromeHomeEnabled").value(true),
-            new ParameterSet().name("ChromeHomeDisabled").value(false));
+        @Override
+        protected void before() {
+            mOldAnimationMultiplier = ChromeAnimation.Animation.getAnimationMultiplier();
+            ChromeAnimation.Animation.setAnimationMultiplierForTesting(0f);
+        }
+
+        @Override
+        protected void after() {
+            ChromeAnimation.Animation.setAnimationMultiplierForTesting(mOldAnimationMultiplier);
+        }
+    };
 
     private SuggestionsUiDelegate mUiDelegate;
     private FakeSuggestionsSource mSnippetsSource;
-    private MockThumbnailProvider mThumbnailProvider;
-
     private SuggestionsRecyclerView mRecyclerView;
-    private ContextMenuManager mContextMenuManager;
+    private NewTabPageAdapter mAdapter;
+
     private FrameLayout mContentView;
     private SnippetArticleViewHolder mSuggestion;
     private SignInPromo.GenericPromoViewHolder mSigninPromo;
 
     private UiConfig mUiConfig;
 
-    private static final int FULL_CATEGORY = 0;
-    private static final int MINIMAL_CATEGORY = 1;
-
-    private long mTimestamp;
-
-    public ArticleSnippetsTest(boolean chromeHomeEnabled) {
-        mChromeHomeEnabled = chromeHomeEnabled;
-        if (chromeHomeEnabled) {
-            mRenderTestRule.setVariantPrefix("modern");
-        }
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        if (mChromeHomeEnabled) {
-            CommandLine.getInstance().appendSwitch("enable-features=ChromeHome,ChromeHomeModern");
-        } else {
-            CommandLine.getInstance().appendSwitch("disable-features=ChromeHome,ChromeHomeModern");
-        }
-
-        mActivityTestRule.startMainActivityOnBlankPage();
-        ChromePreferenceManager.getInstance().setNewTabPageGenericSigninPromoDismissed(true);
-        mThumbnailProvider = new MockThumbnailProvider();
-        mSnippetsSource = new FakeSuggestionsSource();
-        mSuggestionsDeps.getFactory().thumbnailProvider = mThumbnailProvider;
-        mSuggestionsDeps.getFactory().suggestionsSource = mSnippetsSource;
-        mUiDelegate = new MockUiDelegate();
-        mSnippetsSource.setDefaultFavicon(getBitmap(R.drawable.star_green));
-
-        mTimestamp = System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS;
-
-        FeatureUtilities.resetChromeHomeEnabledForTests();
-        FeatureUtilities.cacheChromeHomeEnabled();
-
-        assertThat(FeatureUtilities.isChromeHomeModernEnabled(), is(mChromeHomeEnabled));
-
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            mContentView = new FrameLayout(mActivityTestRule.getActivity());
-            mUiConfig = new UiConfig(mContentView);
-
-            mActivityTestRule.getActivity().setContentView(mContentView);
-
-            mRecyclerView = new SuggestionsRecyclerView(mActivityTestRule.getActivity());
-            TouchEnabledDelegate touchEnabledDelegate =
-                    enabled -> mRecyclerView.setTouchEnabled(enabled);
-            mContextMenuManager = new ContextMenuManager(mActivityTestRule.getActivity(),
-                    mUiDelegate.getNavigationDelegate(), touchEnabledDelegate);
-            mRecyclerView.init(mUiConfig, mContextMenuManager);
-
-            mSuggestion = new SnippetArticleViewHolder(
-                    mRecyclerView, mContextMenuManager, mUiDelegate, mUiConfig);
-            mSigninPromo = new SignInPromo.GenericPromoViewHolder(
-                    mRecyclerView, mContextMenuManager, mUiConfig);
-        });
-    }
+    private MockThumbnailProvider mThumbnailProvider;
 
     @Test
     @MediumTest
+    @DisabledTest(message = "crbug.com/757735")
     @Feature({"ArticleSnippets", "RenderTest"})
+    @CommandLineParameter({"", "enable-features=" + ChromeFeatureList.CHROME_HOME + ","
+            + ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT})
+    @RetryOnFailure
     public void testSnippetAppearance() throws IOException {
-        SuggestionsCategoryInfo fullCategoryInfo = new SuggestionsCategoryInfo(FULL_CATEGORY,
-                "Section Title", ContentSuggestionsCardLayout.FULL_CARD,
-                ContentSuggestionsAdditionalAction.NONE,
-                /* show_if_empty = */ true, "No suggestions");
-
-        SnippetArticle shortSnippet = new SnippetArticle(FULL_CATEGORY, "id1", "Snippet",
-                "Publisher", "Preview Text", "www.google.com",
-                mTimestamp, // Publish timestamp
-                10f, // Score
-                mTimestamp, // Fetch timestamp
-                false); // IsVideoSuggestion
-        Bitmap watch = BitmapFactory.decodeFile(
+        // Don't load the Bitmap on the UI thread - this is a StrictModeViolation.
+        final Bitmap watch = BitmapFactory.decodeFile(
                 UrlUtils.getIsolatedTestFilePath("chrome/test/data/android/watch.jpg"));
-        Drawable drawable = ThumbnailGradient.createDrawableWithGradientIfNeeded(
-                watch, mActivityTestRule.getActivity().getResources());
-        shortSnippet.setThumbnail(mUiDelegate.getReferencePool().put(drawable));
 
-        renderSuggestion(shortSnippet, fullCategoryInfo, "short_snippet");
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                setupTestData(watch);
 
-        SnippetArticle longSnippet = new SnippetArticle(FULL_CATEGORY, "id2",
-                new String(new char[20]).replace("\0", "Snippet "),
-                new String(new char[20]).replace("\0", "Publisher "),
-                new String(new char[80]).replace("\0", "Preview Text "), "www.google.com",
-                mTimestamp, // Publish timestamp
-                20f, // Score
-                mTimestamp, // Fetch timestamp
-                false); // IsVideoSuggestion
-        renderSuggestion(longSnippet, fullCategoryInfo, "long_snippet");
+                mContentView = new FrameLayout(mActivityTestRule.getActivity());
+                mUiConfig = new UiConfig(mContentView);
 
-        SuggestionsCategoryInfo minimalCategory = new SuggestionsCategoryInfo(MINIMAL_CATEGORY,
-                "Section Title", ContentSuggestionsCardLayout.MINIMAL_CARD,
-                ContentSuggestionsAdditionalAction.NONE,
-                /* show_if_empty = */ true, "No suggestions");
+                mActivityTestRule.getActivity().setContentView(mContentView);
 
-        SnippetArticle minimalSnippet = new SnippetArticle(MINIMAL_CATEGORY, "id3",
-                new String(new char[20]).replace("\0", "Bookmark "), "Publisher",
-                "This should not be displayed", "www.google.com",
-                mTimestamp, // Publish timestamp
-                10f, // Score
-                mTimestamp, // Fetch timestamp
-                false); // IsVideoSuggestion
-        renderSuggestion(minimalSnippet, minimalCategory, "minimal_snippet");
+                mRecyclerView = new SuggestionsRecyclerView(mActivityTestRule.getActivity());
+                mContentView.addView(mRecyclerView);
 
-        SnippetArticle minimalSnippet2 = new SnippetArticle(MINIMAL_CATEGORY, "id4", "Bookmark",
-                "Publisher", "This should not be displayed", "www.google.com",
-                mTimestamp, // Publish timestamp
-                10f, // Score
-                mTimestamp, // Fetch timestamp
-                false);
-
-        // See how everything looks in narrow layout.
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            // Since we inform the UiConfig manually about the desired display style, the only
-            // reason we actually change the LayoutParams is for the rendered Views to look right.
-            ViewGroup.LayoutParams params = mContentView.getLayoutParams();
-            params.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350,
-                    mRecyclerView.getResources().getDisplayMetrics());
-            mContentView.setLayoutParams(params);
-
-            mUiConfig.setDisplayStyleForTesting(new UiConfig.DisplayStyle(
-                    HorizontalDisplayStyle.NARROW, VerticalDisplayStyle.REGULAR));
+                mAdapter = new NewTabPageAdapter(mUiDelegate, /* aboveTheFold = */ null, mUiConfig,
+                        OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()),
+                        /* contextMenuManager = */ null, /* tileGroupDelegate = */ null,
+                        /* suggestionsCarousel = */ null);
+                mAdapter.refreshSuggestions();
+                mRecyclerView.setAdapter(mAdapter);
+            }
         });
 
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
-        renderSuggestion(shortSnippet, fullCategoryInfo, "short_snippet_narrow");
-        renderSuggestion(longSnippet, fullCategoryInfo, "long_snippet_narrow");
-        renderSuggestion(minimalSnippet, minimalCategory, "long_minimal_snippet_narrow");
-        renderSuggestion(minimalSnippet2, minimalCategory, "short_minimal_snippet_narrow");
-    }
+        int first = mAdapter.getFirstCardPosition();
+        mRenderTestRule.render(mRecyclerView.getChildAt(first), "short_snippet");
+        mRenderTestRule.render(mRecyclerView.getChildAt(first + 1), "long_snippet");
 
-    // TODO(bauerb): Test top, middle, and bottom card backgrounds.
+        int firstOfSecondCategory = first + 1 /* card 2 */ + 1 /* header */ + 1 /* card 3 */;
+
+        mRenderTestRule.render(mRecyclerView.getChildAt(firstOfSecondCategory), "minimal_snippet");
+        mRenderTestRule.render(mRecyclerView, "snippets");
+
+        // See how everything looks in narrow layout.
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                // Since we inform the UiConfig manually about the desired display style, the only
+                // reason we actually change the LayoutParams is for the rendered Views to look
+                // right.
+                ViewGroup.LayoutParams params = mContentView.getLayoutParams();
+                params.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350,
+                        mRecyclerView.getResources().getDisplayMetrics());
+                mContentView.setLayoutParams(params);
+
+                mUiConfig.setDisplayStyleForTesting(new UiConfig.DisplayStyle(
+                        HorizontalDisplayStyle.NARROW, VerticalDisplayStyle.REGULAR));
+            }
+        });
+
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        mRenderTestRule.render(mRecyclerView.getChildAt(first), "short_snippet_narrow");
+        mRenderTestRule.render(mRecyclerView.getChildAt(first + 1), "long_snippet_narrow");
+        mRenderTestRule.render(
+                mRecyclerView.getChildAt(firstOfSecondCategory), "long_minimal_snippet_narrow");
+        mRenderTestRule.render(mRecyclerView.getChildAt(firstOfSecondCategory + 1),
+                "short_minimal_snippet_narrow");
+        mRenderTestRule.render(mRecyclerView, "snippets_narrow");
+    }
 
     @Test
     @MediumTest
     @Feature({"ArticleSnippets", "RenderTest"})
     public void testDownloadSuggestion() throws IOException {
-        String downloadFilePath =
+        final String filePath =
                 UrlUtils.getIsolatedTestFilePath("chrome/test/data/android/capybara.jpg");
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            SnippetArticle downloadSuggestion = new SnippetArticle(KnownCategories.DOWNLOADS, "id1",
-                    "test_image.jpg", "example.com", null, "http://example.com", mTimestamp, 10f,
-                    mTimestamp, false);
-            downloadSuggestion.setAssetDownloadData("asdf", downloadFilePath, "image/jpeg");
-            SuggestionsCategoryInfo downloadsCategory = new SuggestionsCategoryInfo(
-                    KnownCategories.DOWNLOADS, "Downloads", ContentSuggestionsCardLayout.FULL_CARD,
-                    ContentSuggestionsAdditionalAction.NONE,
-                    /* show_if_empty = */ true, "No suggestions");
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mContentView = new FrameLayout(mActivityTestRule.getActivity());
+                mUiConfig = new UiConfig(mContentView);
 
-            mSuggestion.onBindViewHolder(downloadSuggestion, downloadsCategory);
-            mContentView.addView(mSuggestion.itemView);
+                mActivityTestRule.getActivity().setContentView(mContentView);
+
+                mRecyclerView = new SuggestionsRecyclerView(mActivityTestRule.getActivity());
+                TouchEnabledDelegate touchEnabledDelegate = new TouchEnabledDelegate() {
+                    @Override
+                    public void setTouchEnabled(boolean enabled) {
+                        mRecyclerView.setTouchEnabled(enabled);
+                    }
+                };
+                ContextMenuManager contextMenuManager =
+                        new ContextMenuManager(mActivityTestRule.getActivity(),
+                                mUiDelegate.getNavigationDelegate(), touchEnabledDelegate);
+                mRecyclerView.init(mUiConfig, contextMenuManager);
+                mRecyclerView.setAdapter(mAdapter);
+
+                mSuggestion = new SnippetArticleViewHolder(
+                        mRecyclerView, contextMenuManager, mUiDelegate, mUiConfig);
+
+                long timestamp = System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS;
+
+                SnippetArticle download = new SnippetArticle(KnownCategories.DOWNLOADS, "id1",
+                        "test_image.jpg", "example.com", null, "http://example.com", timestamp, 10f,
+                        timestamp, false);
+                download.setAssetDownloadData("asdf", filePath, "image/jpeg");
+                SuggestionsCategoryInfo categoryInfo =
+                        new SuggestionsCategoryInfo(KnownCategories.DOWNLOADS, "Downloads",
+                                ContentSuggestionsCardLayout.FULL_CARD,
+                                ContentSuggestionsAdditionalAction.NONE,
+                                /* show_if_empty = */ true, "No suggestions");
+                mSuggestion.onBindViewHolder(download, categoryInfo);
+                mContentView.addView(mSuggestion.itemView);
+            }
         });
 
         mRenderTestRule.render(mSuggestion.itemView, "download_snippet_placeholder");
@@ -273,21 +247,25 @@
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         List<ThumbnailRequest> requests = mThumbnailProvider.getRequests();
         Assert.assertEquals(1, requests.size());
-        ThumbnailRequest request = requests.get(0);
-        Assert.assertEquals(downloadFilePath, request.getFilePath());
+        final ThumbnailRequest request = requests.get(0);
+        Assert.assertEquals(filePath, request.getFilePath());
 
-        Bitmap thumbnail = BitmapFactory.decodeFile(downloadFilePath);
+        final Bitmap thumbnail = BitmapFactory.decodeFile(filePath);
 
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            mThumbnailProvider.fulfillRequest(request, thumbnail);
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mThumbnailProvider.fulfillRequest(request, thumbnail);
+            }
         });
-
         mRenderTestRule.render(mSuggestion.itemView, "download_snippet_thumbnail");
     }
 
     @Test
     @MediumTest
     @Feature({"ArticleSnippets", "RenderTest"})
+    @CommandLineParameter({"", "enable-features=" + ChromeFeatureList.CHROME_HOME + ","
+                    + ChromeFeatureList.CHROME_HOME_MODERN_LAYOUT})
     public void testSigninPromo() throws IOException {
         ThreadUtils.runOnUiThreadBlocking(() -> {
             mContentView = new FrameLayout(mActivityTestRule.getActivity());
@@ -302,6 +280,7 @@
                     new ContextMenuManager(mActivityTestRule.getActivity(),
                             mUiDelegate.getNavigationDelegate(), touchEnabledDelegate);
             mRecyclerView.init(mUiConfig, contextMenuManager);
+            mRecyclerView.setAdapter(mAdapter);
 
             mSigninPromo = new SignInPromo.GenericPromoViewHolder(
                     mRecyclerView, contextMenuManager, mUiConfig);
@@ -309,22 +288,85 @@
             mContentView.addView(mSigninPromo.itemView);
         });
 
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
         mRenderTestRule.render(mSigninPromo.itemView, "signin_promo");
     }
 
-    private void renderSuggestion(SnippetArticle suggestion, SuggestionsCategoryInfo categoryInfo,
-            String renderId) throws IOException {
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            mSuggestion.onBindViewHolder(suggestion, categoryInfo);
-            mContentView.addView(mSuggestion.itemView);
-        });
-        mRenderTestRule.render(mSuggestion.itemView, renderId);
+    private void setupTestData(Bitmap thumbnail) {
+        @CategoryInt
+        int fullCategory = 0;
+        @CategoryInt
+        int minimalCategory = 1;
+        SnippetArticle shortSnippet = new SnippetArticle(fullCategory, "id1", "Snippet",
+                "Publisher", "Preview Text", "www.google.com",
+                1466614774, // Publish timestamp
+                10f, // Score
+                1466634774, // Fetch timestamp
+                false); // IsVideoSuggestion
 
-        ThreadUtils.runOnUiThreadBlocking(() -> {
-            mContentView.removeView(mSuggestion.itemView);
-            mSuggestion.recycle();
-        });
+        Drawable drawable = ThumbnailGradient.createDrawableWithGradientIfNeeded(
+                thumbnail, mActivityTestRule.getActivity().getResources());
+        shortSnippet.setThumbnail(mUiDelegate.getReferencePool().put(drawable));
+
+        SnippetArticle longSnippet = new SnippetArticle(fullCategory, "id2",
+                new String(new char[20]).replace("\0", "Snippet "),
+                new String(new char[20]).replace("\0", "Publisher "),
+                new String(new char[80]).replace("\0", "Preview Text "), "www.google.com",
+                1466614074, // Publish timestamp
+                20f, // Score
+                1466634774, // Fetch timestamp
+                false); // IsVideoSuggestion
+
+        SnippetArticle minimalSnippet = new SnippetArticle(minimalCategory, "id3",
+                new String(new char[20]).replace("\0", "Bookmark "), "Publisher",
+                "This should not be displayed", "www.google.com",
+                1466614774, // Publish timestamp
+                10f, // Score
+                1466634774, // Fetch timestamp
+                false); // IsVideoSuggestion
+
+        SnippetArticle minimalSnippet2 = new SnippetArticle(minimalCategory, "id4", "Bookmark",
+                "Publisher", "This should not be displayed", "www.google.com",
+                1466614774, // Publish timestamp
+                10f, // Score
+                1466634774, // Fetch timestamp
+                false); // IsVideoSuggestion
+
+        mSnippetsSource.setInfoForCategory(fullCategory,
+                new SuggestionsCategoryInfo(fullCategory, "Section Title",
+                        ContentSuggestionsCardLayout.FULL_CARD,
+                        ContentSuggestionsAdditionalAction.NONE,
+                        /*show_if_empty=*/true, "No suggestions"));
+        mSnippetsSource.setStatusForCategory(fullCategory, CategoryStatus.AVAILABLE);
+        mSnippetsSource.setSuggestionsForCategory(
+                fullCategory, Arrays.asList(shortSnippet, longSnippet));
+
+        mSnippetsSource.setInfoForCategory(minimalCategory,
+                new SuggestionsCategoryInfo(minimalCategory, "Section Title",
+                        ContentSuggestionsCardLayout.MINIMAL_CARD,
+                        ContentSuggestionsAdditionalAction.NONE,
+                        /* show_if_empty = */ true, "No suggestions"));
+        mSnippetsSource.setStatusForCategory(minimalCategory, CategoryStatus.AVAILABLE);
+        mSnippetsSource.setSuggestionsForCategory(
+                minimalCategory, Arrays.asList(minimalSnippet, minimalSnippet2));
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
+        ChromePreferenceManager.getInstance().setNewTabPageGenericSigninPromoDismissed(true);
+        mThumbnailProvider = new MockThumbnailProvider();
+        mSnippetsSource = new FakeSuggestionsSource();
+        mSuggestionsDeps.getFactory().thumbnailProvider = mThumbnailProvider;
+        mSuggestionsDeps.getFactory().suggestionsSource = mSnippetsSource;
+        mUiDelegate = new MockUiDelegate();
+        mSnippetsSource.setDefaultFavicon(getBitmap(R.drawable.star_green));
+
+        FeatureUtilities.resetChromeHomeEnabledForTests();
+        FeatureUtilities.cacheChromeHomeEnabled();
+
+        if (FeatureUtilities.isChromeHomeModernEnabled()) {
+            mRenderTestRule.setVariantPrefix("modern");
+        }
     }
 
     private Bitmap getBitmap(@DrawableRes int resId) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
index c51cd9a..38168b7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/photo_picker/PhotoPickerDialogTest.java
@@ -6,13 +6,13 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
+import android.support.test.filters.LargeTest;
 import android.support.v7.widget.RecyclerView;
 import android.view.View;
 import android.widget.Button;
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
@@ -194,14 +194,7 @@
         });
     }
 
-    /**
-     * Continues to be flaky on bots which doesn't reproduce on local devices,
-     * continuing to investigate offline.
-     *
-     * https://crbug.com/761060
-     * @LargeTest
-     */
-    @DisabledTest
+    @LargeTest
     public void testNoSelection() throws Throwable {
         createDialog(false, Arrays.asList("image/*")); // Multi-select = false.
         assertTrue(mDialog.isShowing());
@@ -217,14 +210,7 @@
         dismissDialog();
     }
 
-    /**
-     * Continues to be flaky on bots which doesn't reproduce on local devices,
-     * continuing to investigate offline.
-     *
-     * https://crbug.com/761060
-     * @LargeTest
-     */
-    @DisabledTest
+    @LargeTest
     public void testSingleSelectionPhoto() throws Throwable {
         createDialog(false, Arrays.asList("image/*")); // Multi-select = false.
         assertTrue(mDialog.isShowing());
@@ -243,14 +229,7 @@
         dismissDialog();
     }
 
-    /**
-     * Continues to be flaky on bots which doesn't reproduce on local devices,
-     * continuing to investigate offline.
-     *
-     * https://crbug.com/761060
-     * @LargeTest
-     */
-    @DisabledTest
+    @LargeTest
     public void testMultiSelectionPhoto() throws Throwable {
         createDialog(true, Arrays.asList("image/*")); // Multi-select = true.
         assertTrue(mDialog.isShowing());
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index dcb43869..fea9db4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -2111,6 +2111,9 @@
       <message name="IDS_MANAGE" desc="Text for a button on permission bubbles, which opens a more detailed content settings page where users can manage that particular setting.">
         Manage
       </message>
+      <message name="IDS_LIST_BULLET" desc="Unicode bullet for list items in permission bubbles.">
+        •  $1
+      </message>
       <message name="IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL" desc="Header for multiple automatic downloads page on Content Settings dialog">
         Automatic Downloads
       </message>
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
index b0f9a54..dd3a474c 100644
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
+++ b/chrome/browser/chromeos/net/client_cert_store_chromeos.cc
@@ -14,8 +14,8 @@
 #include "base/callback.h"
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
-#include "base/task_runner_util.h"
-#include "base/threading/worker_pool.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "crypto/nss_crypto_module_delegate.h"
 #include "net/ssl/ssl_cert_request_info.h"
@@ -64,18 +64,13 @@
   scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
   if (!password_delegate_factory_.is_null())
     password_delegate = password_delegate_factory_.Run(request->host_and_port);
-  if (base::PostTaskAndReplyWithResult(
-          base::WorkerPool::GetTaskRunner(true /* task_is_slow */).get(),
-          FROM_HERE,
-          base::Bind(&ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread,
-                     base::Unretained(this), password_delegate,
-                     base::Unretained(request),
-                     base::Passed(&additional_certs)),
-          callback)) {
-    return;
-  }
-  // If the task could not be posted, behave as if there were no certificates.
-  callback.Run(net::ClientCertIdentityList());
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::Bind(&ClientCertStoreChromeOS::GetAndFilterCertsOnWorkerThread,
+                 base::Unretained(this), password_delegate,
+                 base::Unretained(request), base::Passed(&additional_certs)),
+      callback);
 }
 
 net::ClientCertIdentityList
@@ -84,6 +79,12 @@
         password_delegate,
     const net::SSLCertRequestInfo* request,
     net::ClientCertIdentityList additional_certs) {
+  // This method may acquire the NSS lock or reenter this code via extension
+  // hooks (such as smart card UI). To ensure threads are not starved or
+  // deadlocked, the base::ScopedBlockingCall below increments the thread pool
+  // capacity if this method takes too much time to run.
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+
   net::ClientCertIdentityList client_certs;
   net::ClientCertStoreNSS::GetPlatformCertsOnWorkerThread(
       std::move(password_delegate),
diff --git a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc b/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
index 361b15f..d6a66f8 100644
--- a/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/net/client_cert_store_chromeos_unittest.cc
@@ -12,9 +12,9 @@
 #include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h"
 #include "crypto/scoped_test_nss_db.h"
@@ -87,7 +87,9 @@
 
 class ClientCertStoreChromeOSTest : public ::testing::Test {
  public:
-  ClientCertStoreChromeOSTest() : message_loop_(new base::MessageLoopForIO()) {}
+  ClientCertStoreChromeOSTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
 
   scoped_refptr<net::X509Certificate> ImportCertToSlot(
       const std::string& cert_filename,
@@ -100,7 +102,7 @@
   }
 
  private:
-  std::unique_ptr<base::MessageLoop> message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
 // Ensure that cert requests, that are started before the filter is initialized,
diff --git a/chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py b/chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py
index 98ca5c4..a274a3b 100644
--- a/chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py
+++ b/chrome/browser/chromeos/policy/tools/generate_device_policy_remover.py
@@ -22,6 +22,12 @@
   sys.path.insert(0, descriptor_pool_path)
   sys.path.append(symbol_database_path)
   sys.path.append(chrome_device_policy_pb2_path)
+  # Make reload google library
+  # which might be already loaded due to Google App Engine
+  # TODO(crbug.com/764314): find better solution how to import protobuf.
+  import google.protobuf
+  reload(google)
+  reload(google.protobuf)
   from chrome_device_policy_pb2 import ChromeDeviceSettingsProto
   with open(off_hours_cleaner_path, 'wt') as file:
     file.write('//\n'
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 41c3eab..fce991e 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -552,8 +552,12 @@
                 unresponsive_threshold, crash_on_hang_threads);
   StartWatching(BrowserThread::IO, "IO", kSleepTime, kUnresponsiveTime,
                 unresponsive_threshold, crash_on_hang_threads);
+  StartWatching(BrowserThread::DB, "DB", kSleepTime, kUnresponsiveTime,
+                unresponsive_threshold, crash_on_hang_threads);
   StartWatching(BrowserThread::FILE, "FILE", kSleepTime, kUnresponsiveTime,
                 unresponsive_threshold, crash_on_hang_threads);
+  StartWatching(BrowserThread::CACHE, "CACHE", kSleepTime, kUnresponsiveTime,
+                unresponsive_threshold, crash_on_hang_threads);
 }
 
 // static
diff --git a/chrome/browser/notifications/persistent_notification_handler.cc b/chrome/browser/notifications/persistent_notification_handler.cc
index 1288d551..6d7d3e2 100644
--- a/chrome/browser/notifications/persistent_notification_handler.cc
+++ b/chrome/browser/notifications/persistent_notification_handler.cc
@@ -38,20 +38,8 @@
   const GURL notification_origin(origin);
   DCHECK(notification_origin.is_valid());
 
-  // TODO(peter): Convert the notification stack from this point onward to use
-  // base::Optional<> as well.
-
-  int action_index_int = -1 /* no_action */;
-  if (action_index.has_value())
-    action_index_int = action_index.value();
-
-  base::NullableString16 nullable_reply;
-  if (reply.has_value())
-    nullable_reply = base::NullableString16(reply.value(), false /* is_null */);
-
   PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
-      profile, notification_id, notification_origin, action_index_int,
-      nullable_reply);
+      profile, notification_id, notification_origin, action_index, reply);
 }
 
 void PersistentNotificationHandler::OpenSettings(Profile* profile) {
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 06296cf1..eac42b19 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -127,8 +127,8 @@
     BrowserContext* browser_context,
     const std::string& notification_id,
     const GURL& origin,
-    int action_index,
-    const base::NullableString16& reply) {
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   blink::mojom::PermissionStatus permission_status =
       CheckPermissionOnUIThread(browser_context, origin,
@@ -142,12 +142,12 @@
     return;
   }
 
-  if (action_index == -1) {
-    base::RecordAction(
-        base::UserMetricsAction("Notifications.Persistent.Clicked"));
-  } else {
+  if (action_index.has_value()) {
     base::RecordAction(base::UserMetricsAction(
         "Notifications.Persistent.ClickedActionButton"));
+  } else {
+    base::RecordAction(
+        base::UserMetricsAction("Notifications.Persistent.Clicked"));
   }
 
 #if BUILDFLAG(ENABLE_BACKGROUND)
diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h
index 7ccdce17..94511df 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.h
+++ b/chrome/browser/notifications/platform_notification_service_impl.h
@@ -16,6 +16,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/notification_common.h"
@@ -28,10 +29,6 @@
 class NotificationDelegate;
 class ScopedKeepAlive;
 
-namespace base {
-class NullableString16;
-}
-
 namespace content {
 class BrowserContext;
 struct NotificationResources;
@@ -53,11 +50,12 @@
   // To be called when a persistent notification has been clicked on. The
   // Service Worker associated with the registration will be started if
   // needed, on which the event will be fired. Must be called on the UI thread.
-  void OnPersistentNotificationClick(content::BrowserContext* browser_context,
-                                     const std::string& notification_id,
-                                     const GURL& origin,
-                                     int action_index,
-                                     const base::NullableString16& reply);
+  void OnPersistentNotificationClick(
+      content::BrowserContext* browser_context,
+      const std::string& notification_id,
+      const GURL& origin,
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply);
 
   // To be called when a persistent notification has been closed. The data
   // associated with the notification has to be pruned from the database in this
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1b1f539..0c10ba47 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2426,6 +2426,8 @@
       "cocoa/last_active_browser_cocoa.h",
       "cocoa/md_hover_button.h",
       "cocoa/md_hover_button.mm",
+      "cocoa/md_util.h",
+      "cocoa/md_util.mm",
       "cocoa/media_picker/desktop_media_picker_bridge.h",
       "cocoa/media_picker/desktop_media_picker_bridge.mm",
       "cocoa/media_picker/desktop_media_picker_cocoa.h",
diff --git a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc
index c8f93a47..0d47d4f 100644
--- a/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc
+++ b/chrome/browser/ui/browser_content_setting_bubble_model_delegate.cc
@@ -40,19 +40,10 @@
 
 void BrowserContentSettingBubbleModelDelegate::ShowContentSettingsPage(
     ContentSettingsType type) {
-  if (type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
-    // We don't (yet?) implement user-settable exceptions for mixed script
-    // blocking, so bounce to an explanatory page for now.
-    content_settings::RecordMixedScriptAction(
-        content_settings::MIXED_SCRIPT_ACTION_CLICKED_LEARN_MORE);
-    chrome::AddSelectedTabWithURL(browser_,
-                                  GURL(kInsecureScriptHelpUrl),
-                                  ui::PAGE_TRANSITION_LINK);
-  } else if (type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) {
+  if (type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS)
     chrome::ShowSettingsSubPage(browser_, chrome::kHandlerSettingsSubPage);
-  } else {
+  else
     chrome::ShowContentSettingsExceptions(browser_, type);
-  }
 }
 
 void BrowserContentSettingBubbleModelDelegate::ShowLearnMorePage(
@@ -65,6 +56,9 @@
     case CONTENT_SETTINGS_TYPE_ADS:
       learn_more_url = GURL(subresource_filter::kLearnMoreLink);
       break;
+    case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
+      learn_more_url = GURL(kInsecureScriptHelpUrl);
+      break;
     default:
       return;
   }
diff --git a/chrome/browser/ui/cocoa/animatable_image.h b/chrome/browser/ui/cocoa/animatable_image.h
index 102f337..b859404 100644
--- a/chrome/browser/ui/cocoa/animatable_image.h
+++ b/chrome/browser/ui/cocoa/animatable_image.h
@@ -21,26 +21,23 @@
  @private
   // The image to animate.
   base::scoped_nsobject<NSImage> image_;
-
-  // The frame of the image before and after the animation. This is in this
-  // window's coordinate system.
-  CGRect startFrame_;
-  CGRect endFrame_;
-
-  // Opacity values for the animation.
-  CGFloat startOpacity_;
-  CGFloat endOpacity_;
-
-  // The amount of time it takes to animate the image.
-  CGFloat duration_;
 }
 
+// The frame of the image before and after the animation. This is in this
+// window's coordinate system.
 @property(nonatomic) CGRect startFrame;
 @property(nonatomic) CGRect endFrame;
+
+// Opacity values for the animation.
 @property(nonatomic) CGFloat startOpacity;
 @property(nonatomic) CGFloat endOpacity;
+
+// The amount of time it takes to animate the image.
 @property(nonatomic) CGFloat duration;
 
+// The timing function to use for the animation.
+@property(nonatomic, assign) CAMediaTimingFunction* timingFunction;
+
 // Designated initializer. Do not use any other NSWindow initializers. Creates
 // but does not show the blank animation window of the given size. The
 // |animationFrame| should usually be big enough to contain the |startFrame|
diff --git a/chrome/browser/ui/cocoa/animatable_image.mm b/chrome/browser/ui/cocoa/animatable_image.mm
index 4fbc1f0..f21be0c 100644
--- a/chrome/browser/ui/cocoa/animatable_image.mm
+++ b/chrome/browser/ui/cocoa/animatable_image.mm
@@ -18,6 +18,7 @@
 @synthesize startOpacity = startOpacity_;
 @synthesize endOpacity = endOpacity_;
 @synthesize duration = duration_;
+@synthesize timingFunction = timingFunction_;
 
 - (id)initWithImage:(NSImage*)image
      animationFrame:(NSRect)animationFrame {
@@ -28,6 +29,8 @@
     DCHECK(image);
     image_.reset([image retain]);
     duration_ = 1.0;
+    timingFunction_ =
+        [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
     startOpacity_ = 1.0;
     endOpacity_ = 1.0;
 
@@ -57,10 +60,6 @@
   [layer setNeedsDisplayOnBoundsChange:YES];
   [rootLayer addSublayer:layer];
 
-  // Common timing function for all animations.
-  CAMediaTimingFunction* mediaFunction =
-      [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
-
   // Animate the bounds only if the image is resized.
   CABasicAnimation* boundsAnimation = nil;
   if (CGRectGetWidth([self startFrame]) != CGRectGetWidth([self endFrame]) ||
@@ -76,7 +75,7 @@
     [boundsAnimation setToValue:[NSValue valueWithRect:endRect]];
     [boundsAnimation gtm_setDuration:[self duration]
                            eventMask:NSLeftMouseUpMask];
-    [boundsAnimation setTimingFunction:mediaFunction];
+    [boundsAnimation setTimingFunction:timingFunction_];
   }
 
   // Positional animation.
@@ -88,7 +87,7 @@
       [NSValue valueWithPoint:NSPointFromCGPoint([self endFrame].origin)]];
   [positionAnimation gtm_setDuration:[self duration]
                            eventMask:NSLeftMouseUpMask];
-  [positionAnimation setTimingFunction:mediaFunction];
+  [positionAnimation setTimingFunction:timingFunction_];
 
   // Opacity animation.
   CABasicAnimation* opacityAnimation =
@@ -98,7 +97,7 @@
   [opacityAnimation setToValue:[NSNumber numberWithFloat:[self endOpacity]]];
   [opacityAnimation gtm_setDuration:[self duration]
                           eventMask:NSLeftMouseUpMask];
-  [opacityAnimation setTimingFunction:mediaFunction];
+  [opacityAnimation setTimingFunction:timingFunction_];
   // Set the delegate just for one of the animations so that this window can
   // be closed upon completion.
   [opacityAnimation setDelegate:self];
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
index b3fd1ca3..a2c9960e 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_controller.mm
@@ -22,6 +22,7 @@
 #import "chrome/browser/ui/cocoa/download/download_shelf_view_cocoa.h"
 #import "chrome/browser/ui/cocoa/harmony_button.h"
 #import "chrome/browser/ui/cocoa/md_hover_button.h"
+#import "chrome/browser/ui/cocoa/md_util.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/generated_resources.h"
@@ -457,6 +458,8 @@
   if (base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf)) {
     [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) {
       context.duration = kDownloadItemOpenDuration;
+      context.timingFunction =
+          CAMediaTimingFunction.cr_materialEaseOutTimingFunction;
       [self layoutItems];
     }
                         completionHandler:nil];
diff --git a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
index c333ff2..b1cd54e 100644
--- a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
+++ b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #import "chrome/browser/ui/cocoa/animatable_image.h"
+#import "chrome/browser/ui/cocoa/md_util.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/grit/theme_resources.h"
@@ -103,6 +104,11 @@
     [animation_ setStartOpacity:1.0];
     [animation_ setEndOpacity:0.4];
     [animation_ setDuration:0.6];
+    if (base::FeatureList::IsEnabled(
+            features::kMacMaterialDesignDownloadShelf)) {
+      [animation_ setTimingFunction:CAMediaTimingFunction
+                                        .cr_materialEaseInOutTimingFunction];
+    }
 
     // Set up to get notified about resize events on the parent window.
     NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
diff --git a/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.h b/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.h
index 43050b8d..f0bb2bf5 100644
--- a/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.h
+++ b/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.h
@@ -15,6 +15,9 @@
 // 0, shows an indeterminate progress bar.
 @property(nonatomic) CGFloat progress;
 
+// Is the download paused? If so, any indeterminate animation will freeze.
+@property(nonatomic) BOOL paused;
+
 // Sets progress to 0 with an animation representing cancelation.
 - (void)cancel;
 
diff --git a/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.mm b/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.mm
index 02f91137..62e3e95 100644
--- a/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.mm
+++ b/chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.mm
@@ -10,6 +10,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
+#import "chrome/browser/ui/cocoa/md_util.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #import "ui/base/cocoa/quartzcore_additions.h"
 
@@ -17,8 +18,10 @@
 
 // An indeterminate progress indicator is a moving 50° arc…
 constexpr CGFloat kIndeterminateArcSize = 50 / 360.0;
-// …which completes a rotation around the circle every 4.5 seconds.
+// …which completes a rotation around the circle every 4.5 seconds…
 constexpr CGFloat kIndeterminateAnimationDuration = 4.5;
+// …stored under this key.
+NSString* const kIndeterminateAnimationKey = @"indeterminate";
 
 }  // namespace
 
@@ -27,36 +30,40 @@
 }
 
 @synthesize progress = progress_;
+@synthesize paused = paused_;
 
 - (void)updateProgress {
-  if (progress_ < 0) {
-    progressShapeLayer_.strokeStart = 0;
-    progressShapeLayer_.strokeEnd = kIndeterminateArcSize;
+  BOOL isIndeterminate = progress_ < 0;
+  if (isIndeterminate &&
+      ![progressShapeLayer_ animationForKey:kIndeterminateAnimationKey]) {
     CABasicAnimation* anim =
         [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
     anim.byValue = @(M_PI * -2);
     anim.duration = kIndeterminateAnimationDuration;
     anim.repeatCount = HUGE_VALF;
-    [progressShapeLayer_ addAnimation:anim forKey:@"indeterminate"];
-  } else {
-    [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) {
-      context.duration = 0.25;
-      // If the bar was in an indeterminate state, replace the continuous
-      // rotation animation with a one-shot animation that resets it.
-      if ([progressShapeLayer_ animationForKey:@"indeterminate"]) {
-        CABasicAnimation* anim =
-            [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
-        NSNumber* from = [progressShapeLayer_.presentationLayer
-            valueForKeyPath:@"transform.rotation.z"];
-        anim.fromValue = from;
-        anim.byValue = @(-(from.doubleValue < 0 ? from.doubleValue
-                                                : -(M_PI + from.doubleValue)));
-        [progressShapeLayer_ addAnimation:anim forKey:@"indeterminate"];
-      }
-      progressShapeLayer_.strokeEnd = progress_;
-    }
-                        completionHandler:nil];
+    [progressShapeLayer_ addAnimation:anim forKey:kIndeterminateAnimationKey];
   }
+  [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) {
+    context.duration = 0.25;
+    context.timingFunction =
+        CAMediaTimingFunction.cr_materialEaseInOutTimingFunction;
+    // If the bar was in an indeterminate state, replace the continuous
+    // rotation animation with a one-shot animation that resets it.
+    CGFloat rotation =
+        static_cast<NSNumber*>([progressShapeLayer_.presentationLayer
+                                   valueForKeyPath:@"transform.rotation.z"])
+            .doubleValue;
+    if (!isIndeterminate && rotation) {
+      CABasicAnimation* anim =
+          [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
+      anim.fromValue = @(rotation);
+      anim.byValue = @(-(rotation < 0 ? rotation : -(M_PI + rotation)));
+      [progressShapeLayer_ addAnimation:anim forKey:kIndeterminateAnimationKey];
+    }
+    progressShapeLayer_.strokeEnd =
+        isIndeterminate ? kIndeterminateArcSize : progress_;
+  }
+                      completionHandler:nil];
 }
 
 - (void)setProgress:(CGFloat)progress {
@@ -68,6 +75,24 @@
                                   NSAccessibilityValueChangedNotification);
 }
 
+- (void)setPaused:(BOOL)paused {
+  if (paused_ == paused)
+    return;
+  paused_ = paused;
+  if (paused_) {
+    if (CAAnimation* indeterminateAnimation =
+            [progressShapeLayer_ animationForKey:kIndeterminateAnimationKey]) {
+      [progressShapeLayer_ setValue:[progressShapeLayer_.presentationLayer
+                                        valueForKeyPath:@"transform.rotation.z"]
+                         forKeyPath:@"transform.rotation.z"];
+      [progressShapeLayer_ removeAnimationForKey:kIndeterminateAnimationKey];
+    }
+  } else {
+    [progressShapeLayer_ setValue:@0 forKey:@"transform.rotation.z"];
+    [self updateProgress];
+  }
+}
+
 - (void)hideAnimated:(void (^)(CAAnimation*))block {
   // Set the progress layer's model to hidden, but also add a fade out
   // animation (which is friendly to being reversed and repeated by -complete).
@@ -80,6 +105,8 @@
                                     fromValue:@NO
                                       toValue:@NO],
   ];
+  animGroup.timingFunction =
+      CAMediaTimingFunction.cr_materialEaseInOutTimingFunction;
   block(animGroup);
   progressShapeLayer_.hidden = YES;
   [progressShapeLayer_ addAnimation:animGroup forKey:nil];
diff --git a/chrome/browser/ui/cocoa/download/md_download_item_view.mm b/chrome/browser/ui/cocoa/download/md_download_item_view.mm
index 3f7cabe8..59d06db 100644
--- a/chrome/browser/ui/cocoa/download/md_download_item_view.mm
+++ b/chrome/browser/ui/cocoa/download/md_download_item_view.mm
@@ -13,6 +13,7 @@
 #import "chrome/browser/ui/cocoa/download/md_download_item_progress_indicator.h"
 #import "chrome/browser/ui/cocoa/harmony_button.h"
 #import "chrome/browser/ui/cocoa/md_hover_button.h"
+#import "chrome/browser/ui/cocoa/md_util.h"
 #import "chrome/browser/ui/cocoa/nsview_additions.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
 #include "chrome/grit/generated_resources.h"
@@ -415,6 +416,7 @@
                                    download.GetFileNameToReportUser().value())];
 
   progressIndicator_.progress = downloadModel->PercentComplete() / 100.0;
+  progressIndicator_.paused = download.IsPaused();
 
   button_.enabled = ^{
     switch (download.GetState()) {
@@ -452,7 +454,9 @@
   BOOL hasStatus = statusString.length != 0;
   if (hasStatus == statusTextView_.hidden) {
     [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) {
-      context.duration = 0.3;
+      context.duration = 0.25;
+      context.timingFunction =
+          CAMediaTimingFunction.cr_materialEaseInOutTimingFunction;
       // Explicitly animate position.y so that x position isn't animated for
       // a new download (which would happen with view.animator).
       [filenameView_.layer
diff --git a/chrome/browser/ui/cocoa/md_util.h b/chrome/browser/ui/cocoa/md_util.h
new file mode 100644
index 0000000..b5272aa3
--- /dev/null
+++ b/chrome/browser/ui/cocoa/md_util.h
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
+#define CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
+
+#import <QuartzCore/QuartzCore.h>
+
+@interface CAMediaTimingFunction (ChromeBrowserMDUtil)
+@property(class, readonly)
+    CAMediaTimingFunction* cr_materialEaseInOutTimingFunction;
+@property(class, readonly)
+    CAMediaTimingFunction* cr_materialEaseOutTimingFunction;
+@end
+
+#endif  // CHROME_BROWSER_UI_COCOA_MD_UTIL_H_
diff --git a/chrome/browser/ui/cocoa/md_util.mm b/chrome/browser/ui/cocoa/md_util.mm
new file mode 100644
index 0000000..0042364
--- /dev/null
+++ b/chrome/browser/ui/cocoa/md_util.mm
@@ -0,0 +1,17 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/md_util.h"
+
+@implementation CAMediaTimingFunction (ChromeBrowserMDUtil)
++ (CAMediaTimingFunction*)cr_materialEaseInOutTimingFunction {
+  return [[[CAMediaTimingFunction alloc] initWithControlPoints:0.4:0.0:0.2:1]
+      autorelease];
+}
+
++ (CAMediaTimingFunction*)cr_materialEaseOutTimingFunction {
+  return [[[CAMediaTimingFunction alloc] initWithControlPoints:0.0:0.0:0.2:1]
+      autorelease];
+}
+@end
diff --git a/chrome/browser/ui/cocoa/spinner_view.mm b/chrome/browser/ui/cocoa/spinner_view.mm
index afc314b..d2845c09 100644
--- a/chrome/browser/ui/cocoa/spinner_view.mm
+++ b/chrome/browser/ui/cocoa/spinner_view.mm
@@ -6,8 +6,9 @@
 
 #import <QuartzCore/QuartzCore.h>
 
-#include "base/mac/sdk_forward_declarations.h"
 #include "base/mac/scoped_cftyperef.h"
+#include "base/mac/sdk_forward_declarations.h"
+#import "chrome/browser/ui/cocoa/md_util.h"
 #include "skia/ext/skia_utils_mac.h"
 #include "ui/base/theme_provider.h"
 #include "ui/native_theme/native_theme.h"
@@ -182,7 +183,7 @@
   // Create the first half of the arc animation, where it grows from a short
   // block to its full length.
   base::scoped_nsobject<CAMediaTimingFunction> timingFunction(
-      [[CAMediaTimingFunction alloc] initWithControlPoints:0.4 :0.0 :0.2 :1]);
+      [CAMediaTimingFunction.cr_materialEaseInOutTimingFunction retain]);
   base::scoped_nsobject<CAKeyframeAnimation> firstHalfAnimation(
       [[CAKeyframeAnimation alloc] init]);
   [firstHalfAnimation setTimingFunction:timingFunction];
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 01294c7..04b8cf4 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -61,6 +61,7 @@
 #include "ppapi/features/features.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
 #include "ui/resources/grit/ui_resources.h"
@@ -457,7 +458,7 @@
 
   // If the setting is not managed by the user, hide the "Manage" button.
   if (info.source != SETTING_SOURCE_USER)
-    set_manage_text(base::string16());
+    set_manage_text_style(ContentSettingBubbleModel::ManageTextStyle::kNone);
 
   // The user cannot manually run Flash on the BLOCK setting when either holds:
   //  - The setting is from Policy. User cannot override admin intent.
@@ -609,8 +610,17 @@
   else
     title = base::UTF8ToUTF16(url.spec());
 
-  return ListItem(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-                      IDR_DEFAULT_FAVICON),
+  const bool use_md = ui::MaterialDesignController::IsSecondaryUiMaterial();
+  if (use_md) {
+    // Format the title to inlude the unicode single dot bullet code-point
+    // \u2022 and two spaces.
+    title = l10n_util::GetStringFUTF16(IDS_LIST_BULLET, title);
+  }
+
+  return ListItem(use_md
+                      ? gfx::Image()
+                      : ui::ResourceBundle::GetSharedInstance().GetImageNamed(
+                            IDR_DEFAULT_FAVICON),
                   title, true, id);
 }
 
@@ -1050,6 +1060,10 @@
   ~ContentSettingMixedScriptBubbleModel() override {}
 
  private:
+  void SetManageText();
+
+  // ContentSettingBubbleModel:
+  void OnLearnMoreClicked() override;
   void OnCustomLinkClicked() override;
 
   DISALLOW_COPY_AND_ASSIGN(ContentSettingMixedScriptBubbleModel);
@@ -1067,6 +1081,16 @@
   content_settings::RecordMixedScriptAction(
       content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_BUBBLE);
   set_custom_link_enabled(true);
+  set_show_learn_more(true);
+  SetManageText();
+}
+
+void ContentSettingMixedScriptBubbleModel::OnLearnMoreClicked() {
+  if (delegate())
+    delegate()->ShowLearnMorePage(content_type());
+
+  content_settings::RecordMixedScriptAction(
+      content_settings::MIXED_SCRIPT_ACTION_CLICKED_LEARN_MORE);
 }
 
 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() {
@@ -1092,6 +1116,11 @@
       web_contents()->GetLastCommittedURL());
 }
 
+// Don't set any manage text since none is displayed.
+void ContentSettingMixedScriptBubbleModel::SetManageText() {
+  set_manage_text_style(ContentSettingBubbleModel::ManageTextStyle::kNone);
+}
+
 // ContentSettingRPHBubbleModel ------------------------------------------------
 
 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel(
@@ -1275,7 +1304,7 @@
           subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)
           ? IDS_ALWAYS_ALLOW_ADS
           : IDS_ALLOW_ADS));
-  set_show_manage_text_as_checkbox(true);
+  set_manage_text_style(ContentSettingBubbleModel::ManageTextStyle::kCheckbox);
 }
 
 void ContentSettingSubresourceFilterBubbleModel::SetMessage() {
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.h b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
index a487d10f..516e4ddad 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.h
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.h
@@ -120,6 +120,15 @@
   };
   typedef std::map<content::MediaStreamType, MediaMenu> MediaMenuMap;
 
+  enum class ManageTextStyle {
+    // No Manage button or checkbox is displayed.
+    kNone,
+    // Manage text is displayed as a non-prominent button.
+    kButton,
+    // Manage text is used as a checkbox title.
+    kCheckbox,
+  };
+
   struct BubbleContent {
     BubbleContent();
     ~BubbleContent();
@@ -133,7 +142,7 @@
     base::string16 custom_link;
     bool custom_link_enabled = false;
     base::string16 manage_text;
-    bool show_manage_text_as_checkbox = false;
+    ManageTextStyle manage_text_style = ManageTextStyle::kButton;
     MediaMenuMap media_menus;
     bool show_learn_more = false;
     base::string16 done_button_text;
@@ -236,8 +245,8 @@
   void set_manage_text(const base::string16& text) {
     bubble_content_.manage_text = text;
   }
-  void set_show_manage_text_as_checkbox(bool show_manage_text_as_checkbox) {
-    bubble_content_.show_manage_text_as_checkbox = show_manage_text_as_checkbox;
+  void set_manage_text_style(ManageTextStyle manage_text_style) {
+    bubble_content_.manage_text_style = manage_text_style;
   }
   void add_media_menu(content::MediaStreamType type, const MediaMenu& menu) {
     bubble_content_.media_menus[type] = menu;
@@ -254,9 +263,6 @@
   rappor::RapporServiceImpl* rappor_service() const { return rappor_service_; }
 
  private:
-  virtual void SetTitle() = 0;
-  virtual void SetManageText() = 0;
-
   content::WebContents* web_contents_;
   Profile* profile_;
   Owner* owner_;
@@ -285,8 +291,8 @@
 
  private:
   // ContentSettingBubbleModel implementation.
-  void SetTitle() override;
-  void SetManageText() override;
+  void SetTitle();
+  void SetManageText();
   void OnManageButtonClicked() override;
   void SetCustomLink();
   void OnCustomLinkClicked() override;
@@ -337,10 +343,10 @@
 
  private:
   void SetMessage();
+  void SetTitle();
+  void SetManageText();
 
   // ContentSettingBubbleModel:
-  void SetTitle() override;
-  void SetManageText() override;
   void OnManageCheckboxChecked(bool is_checked) override;
   ContentSettingSubresourceFilterBubbleModel* AsSubresourceFilterBubbleModel()
       override;
@@ -371,9 +377,8 @@
   bool MicrophoneAccessed() const;
   bool CameraAccessed() const;
 
-  // ContentSettingBubbleModel:
-  void SetTitle() override;
-  void SetManageText() override;
+  void SetTitle();
+  void SetManageText();
 
   // Sets the data for the radio buttons of the bubble.
   void SetRadioGroup();
@@ -421,11 +426,11 @@
 
  private:
   void SetRadioGroup();
+  void SetTitle();
+  void SetManageText();
 
   // ContentSettingBubbleModel overrides:
   void OnRadioClicked(int radio_index) override;
-  void SetTitle() override;
-  void SetManageText() override;
   void OnManageButtonClicked() override;
 
   int selected_item_ = 0;
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.cc b/chrome/browser/ui/views/content_setting_bubble_contents.cc
index 26e7ace..83ef7d66 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.cc
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.cc
@@ -42,6 +42,7 @@
 #include "ui/views/controls/button/image_button.h"
 #include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/controls/button/label_button_border.h"
+#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/button/radio_button.h"
 #include "ui/views/controls/combobox/combobox.h"
@@ -50,7 +51,9 @@
 #include "ui/views/controls/link.h"
 #include "ui/views/controls/menu/menu_config.h"
 #include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/separator.h"
+#include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/native_cursor.h"
 #include "ui/views/window/dialog_client_view.h"
@@ -69,6 +72,9 @@
 // narrow bubbles with lots of line-wrapping.
 const int kMinMultiLineContentsWidth = 250;
 
+// Display a maximum of 4 visible items in a list before scrolling.
+const int kMaxVisibleListItems = 4;
+
 }  // namespace
 
 using content::PluginService;
@@ -184,12 +190,10 @@
   using Row = std::pair<views::ImageView*, views::Label*>;
 
   void ResetLayout();
-  void AddRowToLayout(const Row& row, bool padding_above);
+  void AddRowToLayout(const Row& row);
 
   ContentSettingBubbleContents* parent_;
 
-  int icon_column_width_;
-
   // Our controls representing list items, so we can add or remove
   // these dynamically. Each pair represetns one list item.
   std::vector<Row> list_item_views_;
@@ -199,7 +203,7 @@
 
 ContentSettingBubbleContents::ListItemContainer::ListItemContainer(
     ContentSettingBubbleContents* parent)
-        : parent_(parent), icon_column_width_(0) {
+    : parent_(parent) {
   ResetLayout();
 }
 
@@ -218,10 +222,8 @@
     icon->SetImage(item.image.AsImageSkia());
     label = new views::Label(item.title);
   }
-  icon_column_width_ = std::max(icon->GetPreferredSize().width(),
-                                icon_column_width_);
   list_item_views_.push_back(Row(icon, label));
-  AddRowToLayout(list_item_views_.back(), list_item_views_.size() > 1);
+  AddRowToLayout(list_item_views_.back());
 }
 
 void ContentSettingBubbleContents::ListItemContainer::RemoveRowAtIndex(
@@ -234,7 +236,7 @@
   // As views::GridLayout can't remove rows, we have to rebuild it entirely.
   ResetLayout();
   for (size_t i = 0; i < list_item_views_.size(); i++)
-    AddRowToLayout(list_item_views_[i], i > 0);
+    AddRowToLayout(list_item_views_[i]);
 }
 
 int ContentSettingBubbleContents::ListItemContainer::GetRowIndexOf(
@@ -259,22 +261,30 @@
   item_list_column_set->AddPaddingColumn(0, related_control_horizontal_spacing);
   item_list_column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
                                   GridLayout::USE_PREF, 0, 0);
+  auto* scroll_view = views::ScrollView::GetScrollViewForContents(this);
+  // When this function is called from the constructor, the view has not yet
+  // been placed into a ScrollView.
+  if (scroll_view)
+    scroll_view->ClipHeightTo(-1, -1);
 }
 
 void ContentSettingBubbleContents::ListItemContainer::AddRowToLayout(
-    const Row& row,
-    bool padding_above) {
+    const Row& row) {
   views::GridLayout* layout =
       static_cast<views::GridLayout*>(GetLayoutManager());
   DCHECK(layout);
-  if (padding_above) {
-    const int vertical_padding = ChromeLayoutProvider::Get()->GetDistanceMetric(
-        views::DISTANCE_RELATED_CONTROL_VERTICAL);
-    layout->AddPaddingRow(0, vertical_padding);
-  }
   layout->StartRow(0, 0);
   layout->AddView(row.first);
   layout->AddView(row.second);
+
+  auto* scroll_view = views::ScrollView::GetScrollViewForContents(this);
+  DCHECK(scroll_view);
+  if (!scroll_view->is_bounded()) {
+    scroll_view->ClipHeightTo(
+        0, std::max(row.first->GetPreferredSize().height(),
+                    row.second->GetPreferredSize().height()) *
+               kMaxVisibleListItems);
+  }
 }
 
 // ContentSettingBubbleContents -----------------------------------------------
@@ -289,6 +299,7 @@
       content_setting_bubble_model_(content_setting_bubble_model),
       list_item_container_(nullptr),
       custom_link_(nullptr),
+      manage_button_(nullptr),
       manage_checkbox_(nullptr),
       learn_more_button_(nullptr) {
   // Compensate for built-in vertical padding in the anchor view's image.
@@ -340,6 +351,14 @@
     StyleLearnMoreButton(theme);
 }
 
+base::string16 ContentSettingBubbleContents::GetWindowTitle() const {
+  return content_setting_bubble_model_->bubble_content().title;
+}
+
+bool ContentSettingBubbleContents::ShouldShowCloseButton() const {
+  return ChromeLayoutProvider::Get()->IsHarmonyMode();
+}
+
 void ContentSettingBubbleContents::Init() {
   using views::GridLayout;
 
@@ -364,13 +383,9 @@
       content_setting_bubble_model_->bubble_content();
   bool bubble_content_empty = true;
 
-  if (!bubble_content.title.empty()) {
-    const int title_context =
-        provider->IsHarmonyMode()
-            ? static_cast<int>(views::style::CONTEXT_DIALOG_TITLE)
-            : CONTEXT_BODY_TEXT_SMALL;
+  if (!provider->IsHarmonyMode() && !bubble_content.title.empty()) {
     views::Label* title_label =
-        new views::Label(bubble_content.title, title_context);
+        new views::Label(bubble_content.title, CONTEXT_BODY_TEXT_SMALL);
     title_label->SetMultiLine(true);
     title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     layout->StartRow(0, kSingleColumnSetId);
@@ -394,7 +409,7 @@
   if (!bubble_content.list_items.empty()) {
     const int kItemListColumnSetId = 2;
     views::ColumnSet* column_set = layout->AddColumnSet(kItemListColumnSetId);
-    column_set->AddColumn(GridLayout::LEADING, GridLayout::FILL, 1,
+    column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                           GridLayout::USE_PREF, 0, 0);
 
     for (const ContentSettingBubbleModel::ListItem& list_item :
@@ -404,8 +419,10 @@
           layout->AddPaddingRow(0, related_control_vertical_spacing);
 
         list_item_container_ = new ListItemContainer(this);
+        views::ScrollView* scroll_view = new views::ScrollView();
+        scroll_view->SetContents(list_item_container_);
         layout->StartRow(0, kItemListColumnSetId);
-        layout->AddView(list_item_container_);
+        layout->AddView(scroll_view);
       }
 
       list_item_container_->AddItem(list_item);
@@ -515,7 +532,8 @@
     bubble_content_empty = false;
   }
 
-  if (bubble_content.show_manage_text_as_checkbox) {
+  if (bubble_content.manage_text_style ==
+      ContentSettingBubbleModel::ManageTextStyle::kCheckbox) {
     layout->AddPaddingRow(0, related_control_vertical_spacing);
     layout->StartRow(0, kIndentedSingleColumnSetId);
     manage_checkbox_ = new views::Checkbox(bubble_content.manage_text);
@@ -536,21 +554,42 @@
 }
 
 views::View* ContentSettingBubbleContents::CreateExtraView() {
+  const auto& bubble_content = content_setting_bubble_model_->bubble_content();
+  const auto* layout = ChromeLayoutProvider::Get();
+  std::vector<View*> extra_views;
+  // Optionally add a "Manage" button if the view wants to use a button to
+  // invoke a separate management UI related to the dialog content.
+  if (bubble_content.manage_text_style ==
+      ContentSettingBubbleModel::ManageTextStyle::kButton) {
+    base::string16 title = bubble_content.manage_text;
+    if (title.empty())
+      title = l10n_util::GetStringUTF16(IDS_MANAGE);
+    manage_button_ = views::MdTextButton::CreateSecondaryUiButton(this, title);
+    manage_button_->SetMinSize(gfx::Size(
+        layout->GetDistanceMetric(views::DISTANCE_DIALOG_BUTTON_MINIMUM_WIDTH),
+        0));
+    extra_views.push_back(manage_button_);
+  }
   // Optionally add a help icon if the view wants to link to a help page.
-  if (!content_setting_bubble_model_->bubble_content().show_learn_more)
+  if (bubble_content.show_learn_more) {
+    learn_more_button_ = views::CreateVectorImageButton(this);
+    learn_more_button_->SetFocusForPlatform();
+    learn_more_button_->SetTooltipText(
+        l10n_util::GetStringUTF16(IDS_LEARN_MORE));
+    StyleLearnMoreButton(GetNativeTheme());
+    extra_views.push_back(learn_more_button_);
+  }
+  if (extra_views.empty())
     return nullptr;
-
-  learn_more_button_ = views::CreateVectorImageButton(this);
-  learn_more_button_->SetFocusForPlatform();
-  learn_more_button_->SetTooltipText(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
-  StyleLearnMoreButton(GetNativeTheme());
-  return learn_more_button_;
-}
-
-// Note: The cancel button is really the "Manage" button.
-bool ContentSettingBubbleContents::Cancel() {
-  content_setting_bubble_model_->OnManageButtonClicked();
-  return true;
+  if (extra_views.size() == 1)
+    return extra_views.front();
+  views::View* container = new views::View();
+  container->SetLayoutManager(new views::BoxLayout(
+      views::BoxLayout::kHorizontal, gfx::Insets(),
+      layout->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_HORIZONTAL)));
+  for (auto* extra_view : extra_views)
+    container->AddChildView(extra_view);
+  return container;
 }
 
 bool ContentSettingBubbleContents::Accept() {
@@ -563,31 +602,14 @@
 }
 
 int ContentSettingBubbleContents::GetDialogButtons() const {
-  int buttons = ui::DIALOG_BUTTON_OK;
-
-  // Use the CANCEL button as a manage button.
-  const ContentSettingBubbleModel::BubbleContent& bubble_content =
-      content_setting_bubble_model_->bubble_content();
-  if (!bubble_content.manage_text.empty() &&
-      !bubble_content.show_manage_text_as_checkbox) {
-    buttons |= ui::DIALOG_BUTTON_CANCEL;
-  }
-  return buttons;
+  return ui::DIALOG_BUTTON_OK;
 }
 
 base::string16 ContentSettingBubbleContents::GetDialogButtonLabel(
     ui::DialogButton button) const {
-  const ContentSettingBubbleModel::BubbleContent& bubble_content =
-      content_setting_bubble_model_->bubble_content();
-  if (button == ui::DIALOG_BUTTON_OK) {
-    return bubble_content.done_button_text.empty()
-               ? l10n_util::GetStringUTF16(IDS_DONE)
-               : bubble_content.done_button_text;
-  }
-  DCHECK_EQ(ui::DIALOG_BUTTON_CANCEL, button);
-  DCHECK(!bubble_content.show_manage_text_as_checkbox);
-  DCHECK(!bubble_content.manage_text.empty());
-  return bubble_content.manage_text;
+  const base::string16& done_text =
+      content_setting_bubble_model_->bubble_content().done_button_text;
+  return done_text.empty() ? l10n_util::GetStringUTF16(IDS_DONE) : done_text;
 }
 
 void ContentSettingBubbleContents::StyleLearnMoreButton(
@@ -622,8 +644,11 @@
     GetDialogClientView()->UpdateDialogButtons();
     GetDialogClientView()->Layout();
   } else if (sender == learn_more_button_) {
-    content_setting_bubble_model_->OnLearnMoreClicked();
     GetWidget()->Close();
+    content_setting_bubble_model_->OnLearnMoreClicked();
+  } else if (sender == manage_button_) {
+    GetWidget()->Close();
+    content_setting_bubble_model_->OnManageButtonClicked();
   } else {
     RadioGroup::const_iterator i(
         std::find(radio_group_.begin(), radio_group_.end(), sender));
diff --git a/chrome/browser/ui/views/content_setting_bubble_contents.h b/chrome/browser/ui/views/content_setting_bubble_contents.h
index 12b7ba7..76604fd76 100644
--- a/chrome/browser/ui/views/content_setting_bubble_contents.h
+++ b/chrome/browser/ui/views/content_setting_bubble_contents.h
@@ -64,10 +64,13 @@
   void OnListItemRemovedAt(int index) override;
 
  protected:
+  // views::WidgetDelegate:
+  base::string16 GetWindowTitle() const override;
+  bool ShouldShowCloseButton() const override;
+
   // views::BubbleDialogDelegateView:
   void Init() override;
   View* CreateExtraView() override;
-  bool Cancel() override;
   bool Accept() override;
   bool Close() override;
   int GetDialogButtons() const override;
diff --git a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
index 4efd5d54..87c6d756 100644
--- a/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/content_setting_bubble_dialog_browsertest.cc
@@ -3,11 +3,13 @@
 // found in the LICENSE file.
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
 #include "chrome/browser/download/download_request_limiter.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/content_settings/content_setting_image_model.h"
@@ -16,7 +18,9 @@
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "content/public/test/browser_test_utils.h"
 #include "ui/events/event.h"
 #include "ui/events/event_constants.h"
 #include "ui/views/view.h"
@@ -61,6 +65,22 @@
           ->SetDownloadStatusAndNotify(
               DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED);
       break;
+    case CONTENT_SETTINGS_TYPE_POPUPS: {
+      GURL url(
+          embedded_test_server()->GetURL("/popup_blocker/popup-many-10.html"));
+      ui_test_utils::NavigateToURL(browser(), url);
+      EXPECT_TRUE(content::ExecuteScript(web_contents, std::string()));
+      auto* helper = PopupBlockerTabHelper::FromWebContents(web_contents);
+      // popup-many-10.html should generate 10 blocked popups.
+      EXPECT_EQ(10u, helper->GetBlockedPopupsCount());
+      break;
+    }
+    case CONTENT_SETTINGS_TYPE_PLUGINS: {
+      const base::string16 plugin_name = base::ASCIIToUTF16("plugin_name");
+      content_settings->OnContentBlockedWithDetail(content_type, plugin_name);
+      break;
+    }
+
     default:
       // For all other content_types passed in, mark them as blocked.
       content_settings->OnContentBlocked(content_type);
@@ -120,6 +140,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ContentSettingBubbleDialogTest, InvokeDialog_popups) {
+  ASSERT_TRUE(embedded_test_server()->Start());
   RunDialog();
 }
 
diff --git a/chrome/browser/vr/elements/url_bar_texture.cc b/chrome/browser/vr/elements/url_bar_texture.cc
index ac08e4f..bff7309e 100644
--- a/chrome/browser/vr/elements/url_bar_texture.cc
+++ b/chrome/browser/vr/elements/url_bar_texture.cc
@@ -28,7 +28,7 @@
 static constexpr float kHeight = 0.088;
 static constexpr float kFontHeight = 0.027;
 static constexpr float kBackButtonWidth = kHeight;
-static constexpr float kBackIconHeight = 0.0375;
+static constexpr float kBackIconSize = 0.0375;
 static constexpr float kBackIconOffset = 0.005;
 static constexpr float kFieldSpacing = 0.014;
 static constexpr float kSecurityIconSize = 0.03;
@@ -78,7 +78,7 @@
   }
 }
 
-gfx::PointF percentToMeters(const gfx::PointF& percent) {
+gfx::PointF PercentToMeters(const gfx::PointF& percent) {
   return gfx::PointF(percent.x() * kWidth, percent.y() * kHeight);
 }
 
@@ -99,9 +99,10 @@
 }
 
 void UrlBarTexture::SetHistoryButtonsEnabled(bool can_go_back) {
-  if (can_go_back != can_go_back_)
-    set_dirty();
+  if (can_go_back == can_go_back_)
+    return;
   can_go_back_ = can_go_back;
+  set_dirty();
 }
 
 float UrlBarTexture::ToPixels(float meters) const {
@@ -113,20 +114,20 @@
 }
 
 bool UrlBarTexture::HitsBackButton(const gfx::PointF& position) const {
-  const gfx::PointF& meters = percentToMeters(position);
-  return back_button_hit_region_.Contains(meters) &&
-         !HitsTransparentRegion(meters, true);
+  const gfx::PointF& meters = PercentToMeters(position);
+  const gfx::RectF region(0, 0, kBackButtonWidth, kHeight);
+  return region.Contains(meters) && !HitsTransparentRegion(meters, true);
 }
 
 bool UrlBarTexture::HitsUrlBar(const gfx::PointF& position) const {
-  const gfx::PointF& meters = percentToMeters(position);
+  const gfx::PointF& meters = PercentToMeters(position);
   gfx::RectF rect(gfx::PointF(kBackButtonWidth, 0),
                   gfx::SizeF(kWidth - kBackButtonWidth, kHeight));
   return rect.Contains(meters) && !HitsTransparentRegion(meters, false);
 }
 
 bool UrlBarTexture::HitsSecurityRegion(const gfx::PointF& position) const {
-  return security_hit_region_.Contains(percentToMeters(position));
+  return security_hit_region_.Contains(PercentToMeters(position));
 }
 
 bool UrlBarTexture::HitsTransparentRegion(const gfx::PointF& meters,
@@ -152,15 +153,12 @@
   back_pressed_ = pressed;
 }
 
-SkColor UrlBarTexture::GetLeftCornerColor() const {
-  SkColor color = color_scheme().element_background;
-  if (can_go_back_) {
-    if (back_pressed_)
-      color = color_scheme().element_background_down;
-    else if (back_hovered_)
-      color = color_scheme().element_background_hover;
-  }
-  return color;
+SkColor UrlBarTexture::BackButtonColor() const {
+  if (can_go_back_ && back_pressed_)
+    return color_scheme().element_background_down;
+  if (can_go_back_ && back_hovered_)
+    return color_scheme().element_background_hover;
+  return color_scheme().element_background;
 }
 
 void UrlBarTexture::OnSetMode() {
@@ -176,88 +174,71 @@
   rendered_url_text_rect_ = gfx::Rect();
   rendered_security_text_ = base::string16();
   rendered_security_text_rect_ = gfx::Rect();
+  security_hit_region_.SetRect(0, 0, 0, 0);
 
-  canvas->save();
-  canvas->scale(size_.width() / kWidth, size_.width() / kWidth);
+  float height = ToPixels(kHeight);
+  float width = ToPixels(kWidth);
 
   // Make a gfx canvas to support utility drawing methods.
   cc::SkiaPaintCanvas paint_canvas(canvas);
   gfx::Canvas gfx_canvas(&paint_canvas, 1.0f);
 
-  // Left rounded corner of URL bar.
+  // Back button region.
   SkRRect round_rect;
-  SkVector rounded_corner = {kHeight / 2, kHeight / 2};
+  SkVector rounded_corner = {height / 2, height / 2};
   SkVector left_corners[4] = {rounded_corner, {0, 0}, {0, 0}, rounded_corner};
-  round_rect.setRectRadii({0, 0, kHeight, kHeight}, left_corners);
+  round_rect.setRectRadii({0, 0, height, height}, left_corners);
   SkPaint paint;
-  paint.setColor(GetLeftCornerColor());
+  paint.setColor(BackButtonColor());
   canvas->drawRRect(round_rect, paint);
 
-  // URL area.
-  paint.setColor(color_scheme().element_background);
-
-  SkVector right_corners[4] = {{0, 0}, rounded_corner, rounded_corner, {0, 0}};
-  round_rect.setRectRadii({kHeight, 0, kWidth, kHeight}, right_corners);
-  canvas->drawRRect(round_rect, paint);
-
-  back_button_hit_region_.SetRect(0, 0, 0, 0);
-  security_hit_region_.SetRect(0, 0, 0, 0);
-
-  // Keep track of a left edge as we selectively render components of the URL
-  // bar left-to-right.
-  float left_edge = 0;
-
-  // Back button / URL separator vertical line.
-  paint.setColor(color_scheme().separator);
-  canvas->drawRect(
-      SkRect::MakeXYWH(kBackButtonWidth, 0, kSeparatorWidth, kHeight), paint);
-
   // Back button icon.
   canvas->save();
-  canvas->translate(kBackButtonWidth / 2 + kBackIconOffset, kHeight / 2);
-  canvas->translate(-kBackIconHeight / 2, -kBackIconHeight / 2);
-  float icon_scale = kBackIconHeight /
-                     GetDefaultSizeOfVectorIcon(vector_icons::kBackArrowIcon);
-  canvas->scale(icon_scale, icon_scale);
+  canvas->translate(
+      ToPixels((kBackButtonWidth - kBackIconSize) / 2 + kBackIconOffset),
+      ToPixels((kHeight - kBackIconSize) / 2));
   PaintVectorIcon(&gfx_canvas, vector_icons::kBackArrowIcon,
+                  ToPixels(kBackIconSize),
                   can_go_back_ ? color_scheme().element_foreground
                                : color_scheme().disabled);
   canvas->restore();
 
-  back_button_hit_region_.SetRect(left_edge, 0, left_edge + kBackButtonWidth,
-                                  kHeight);
-  left_edge += kBackButtonWidth + kSeparatorWidth;
+  // Security indicator and URL area.
+  paint.setColor(color_scheme().element_background);
+  SkVector right_corners[4] = {{0, 0}, rounded_corner, rounded_corner, {0, 0}};
+  round_rect.setRectRadii({height, 0, width, height}, right_corners);
+  canvas->drawRRect(round_rect, paint);
+
+  // Back button / URL separator vertical line.
+  paint.setColor(color_scheme().separator);
+  canvas->drawRect(SkRect::MakeXYWH(ToPixels(kBackButtonWidth), 0,
+                                    ToPixels(kSeparatorWidth), height),
+                   paint);
+
+  // Keep track of horizontal position as elements are added left to right.
+  float left_edge = kBackButtonWidth + kSeparatorWidth + kFieldSpacing;
 
   // Site security state icon.
-  left_edge += kFieldSpacing;
   if ((state_.security_level != security_state::NONE || state_.offline_page) &&
       state_.vector_icon != nullptr && state_.should_display_url) {
     gfx::RectF icon_region(left_edge, kHeight / 2 - kSecurityIconSize / 2,
                            kSecurityIconSize, kSecurityIconSize);
     canvas->save();
-    canvas->translate(icon_region.x(), icon_region.y());
-    const gfx::VectorIcon& icon = *state_.vector_icon;
-    float icon_scale = kSecurityIconSize / GetDefaultSizeOfVectorIcon(icon);
-    canvas->scale(icon_scale, icon_scale);
-    PaintVectorIcon(&gfx_canvas, icon,
+    canvas->translate(ToPixels(icon_region.x()), ToPixels(icon_region.y()));
+    PaintVectorIcon(&gfx_canvas, *state_.vector_icon,
+                    ToPixels(kSecurityIconSize),
                     GetSecurityChipColor(state_.security_level,
                                          state_.offline_page, color_scheme()));
     canvas->restore();
-
     security_hit_region_ = icon_region;
     left_edge += kSecurityIconSize + kFieldSpacing;
   }
 
-  canvas->restore();
-
+  // Possibly draw security chip text (eg. "Not secure") next to the icon.
   // The security chip text consumes a significant percentage of URL bar text
   // space, so it is currently disabled (see crbug.com/734206). The offline
   // state is an exception, and must be shown (see crbug.com/735770).
-  bool draw_security_chip = state_.offline_page;
-
-  // Possibly draw security chip text (eg. "Not secure") next to the security
-  // icon.
-  if (draw_security_chip && state_.should_display_url) {
+  if (state_.offline_page && state_.should_display_url) {
     float chip_max_width = kWidth - left_edge - kUrlRightMargin;
     gfx::Rect text_bounds(ToPixels(left_edge), 0, ToPixels(chip_max_width),
                           ToPixels(kHeight));
diff --git a/chrome/browser/vr/elements/url_bar_texture.h b/chrome/browser/vr/elements/url_bar_texture.h
index 3ffddf5..0ad70297 100644
--- a/chrome/browser/vr/elements/url_bar_texture.h
+++ b/chrome/browser/vr/elements/url_bar_texture.h
@@ -60,7 +60,8 @@
 
   std::unique_ptr<gfx::RenderText> url_render_text_;
 
-  // Rendered state for test purposes.
+  // Rendered state for test purposes. The text rectangles represent regions
+  // available to text, not the smaller area of the actual rendered text.
   base::string16 rendered_url_text_;
   gfx::Rect rendered_url_text_rect_;
   base::string16 rendered_security_text_;
@@ -73,7 +74,7 @@
   bool HitsTransparentRegion(const gfx::PointF& meters, bool left) const;
   void RenderUrl(const gfx::Size& texture_size, const gfx::Rect& text_bounds);
   void OnSetMode() override;
-  SkColor GetLeftCornerColor() const;
+  SkColor BackButtonColor() const;
 
   gfx::SizeF size_;
   bool back_hovered_ = false;
@@ -86,7 +87,6 @@
 
   base::Callback<void(UiUnsupportedMode)> failure_callback_;
   gfx::RectF security_hit_region_ = gfx::RectF(0, 0, 0, 0);
-  gfx::RectF back_button_hit_region_ = gfx::RectF(0, 0, 0, 0);
 
   DISALLOW_COPY_AND_ASSIGN(UrlBarTexture);
 };
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index b6fa102a..727b0f3 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -23,6 +23,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/task_scheduler/scheduler_worker_pool_params.h"
 #include "base/task_scheduler/task_scheduler.h"
 #include "base/threading/sequenced_worker_pool.h"
@@ -154,16 +155,6 @@
   main_message_loop_ = message_loop;
   service_process_state_.reset(state);
   network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
-  base::Thread::Options options;
-  options.message_loop_type = base::MessageLoop::TYPE_IO;
-  io_thread_.reset(new ServiceIOThread("ServiceProcess_IO"));
-  file_thread_.reset(new base::Thread("ServiceProcess_File"));
-  if (!io_thread_->StartWithOptions(options) ||
-      !file_thread_->StartWithOptions(options)) {
-    NOTREACHED();
-    Teardown();
-    return false;
-  }
 
   // Initialize TaskScheduler and redirect SequencedWorkerPool tasks to it.
   constexpr int kMaxBackgroundThreads = 1;
@@ -183,12 +174,15 @@
 
   base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
 
-  // Since SequencedWorkerPool is redirected to TaskScheduler, the value of
-  // |kMaxBlockingPoolThreads| is ignored.
-  constexpr int kMaxBlockingPoolThreads = 3;
-  blocking_pool_ =
-      new base::SequencedWorkerPool(kMaxBlockingPoolThreads, "ServiceBlocking",
-                                    base::TaskPriority::USER_VISIBLE);
+  // Initialize the IO and FILE threads.
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_IO;
+  io_thread_.reset(new ServiceIOThread("ServiceProcess_IO"));
+  if (!io_thread_->StartWithOptions(options)) {
+    NOTREACHED();
+    Teardown();
+    return false;
+  }
 
   // Initialize Mojo early so things can use it.
   mojo::edk::Init();
@@ -202,10 +196,11 @@
   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
   base::FilePath pref_path =
       user_data_dir.Append(chrome::kServiceStateFileName);
-  service_prefs_.reset(new ServiceProcessPrefs(
+  service_prefs_ = std::make_unique<ServiceProcessPrefs>(
       pref_path,
-      JsonPrefStore::GetTaskRunnerForFile(pref_path, blocking_pool_.get())
-          .get()));
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})
+          .get());
   service_prefs_->ReadPrefs();
 
   // This switch it required to run connector with test gaia.
@@ -276,17 +271,6 @@
   // background threads can cleanup.
   shutdown_event_.Signal();
   io_thread_.reset();
-  file_thread_.reset();
-
-  if (blocking_pool_.get()) {
-    // The goal is to make it impossible for chrome to 'infinite loop' during
-    // shutdown, but to reasonably expect that all BLOCKING_SHUTDOWN tasks
-    // queued during shutdown get run. There's nothing particularly scientific
-    // about the number chosen.
-    const int kMaxNewShutdownBlockingTasks = 1000;
-    blocking_pool_->Shutdown(kMaxNewShutdownBlockingTasks);
-    blocking_pool_ = NULL;
-  }
 
   if (base::TaskScheduler::GetInstance())
     base::TaskScheduler::GetInstance()->Shutdown();
diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h
index f299333..21363d1 100644
--- a/chrome/service/service_process.h
+++ b/chrome/service/service_process.h
@@ -24,7 +24,6 @@
 
 namespace base {
 class CommandLine;
-class SequencedWorkerPool;
 class WaitableEvent;
 }
 
@@ -65,14 +64,6 @@
     return io_thread_ ? io_thread_->task_runner() : nullptr;
   }
 
-  // Returns the SingleThreadTaskRunner for the service process file thread.
-  // Used to do I/O operations (not network requests or even file: URL requests)
-  // to avoid blocking the main thread. Returns null before Initialize is
-  // called and after Teardown is called.
-  scoped_refptr<base::SingleThreadTaskRunner> file_task_runner() {
-    return file_thread_ ? file_thread_->task_runner() : nullptr;
-  }
-
   // A global event object that is signalled when the main thread's message
   // loop exits. This gives background threads a way to observe the main
   // thread shutting down.
@@ -121,8 +112,6 @@
 
   std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
   std::unique_ptr<base::Thread> io_thread_;
-  std::unique_ptr<base::Thread> file_thread_;
-  scoped_refptr<base::SequencedWorkerPool> blocking_pool_;
   std::unique_ptr<cloud_print::CloudPrintProxy> cloud_print_proxy_;
   std::unique_ptr<ServiceProcessPrefs> service_prefs_;
   std::unique_ptr<ServiceIPCServer> ipc_server_;
diff --git a/chrome/test/android/BUILD.gn b/chrome/test/android/BUILD.gn
index 4a0f359..a3567b70 100644
--- a/chrome/test/android/BUILD.gn
+++ b/chrome/test/android/BUILD.gn
@@ -31,7 +31,6 @@
     "javatests/src/org/chromium/chrome/test/util/ApplicationData.java",
     "javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java",
     "javatests/src/org/chromium/chrome/test/util/BookmarkTestUtil.java",
-    "javatests/src/org/chromium/chrome/test/util/browser/compositor/layouts/DisableChromeAnimations.java",
     "javatests/src/org/chromium/chrome/test/util/browser/contextmenu/ContextMenuUtils.java",
     "javatests/src/org/chromium/chrome/test/util/browser/Features.java",
     "javatests/src/org/chromium/chrome/test/util/browser/LocationSettingsTestUtil.java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/compositor/layouts/DisableChromeAnimations.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/compositor/layouts/DisableChromeAnimations.java
deleted file mode 100644
index 78b7356..0000000
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/compositor/layouts/DisableChromeAnimations.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.test.util.browser.compositor.layouts;
-
-import org.junit.rules.ExternalResource;
-
-import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
-
-/**
- * JUnit 4 rule that disables animations in ChromeAnimation for tests.
- */
-public class DisableChromeAnimations extends ExternalResource {
-    private float mOldAnimationMultiplier;
-
-    @Override
-    protected void before() {
-        mOldAnimationMultiplier = ChromeAnimation.Animation.getAnimationMultiplier();
-        ChromeAnimation.Animation.setAnimationMultiplierForTesting(0f);
-    }
-
-    @Override
-    protected void after() {
-        ChromeAnimation.Animation.setAnimationMultiplierForTesting(mOldAnimationMultiplier);
-    }
-}
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_minimal_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_minimal_snippet_narrow.Nexus_5-19.png
index 64713b13..c403f19 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_minimal_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_minimal_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet.Nexus_5-19.png
index c2a498212..73c6df0 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet_narrow.Nexus_5-19.png
index 371c62d..1989174 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.long_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.minimal_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.minimal_snippet.Nexus_5-19.png
index 588f62f..9d6a0c6 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.minimal_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.minimal_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_placeholder.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_placeholder.Nexus_5-19.png
deleted file mode 100644
index c8c6e40..0000000
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_placeholder.Nexus_5-19.png
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_thumbnail.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_thumbnail.Nexus_5-19.png
deleted file mode 100644
index 7ef2460..0000000
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-download_snippet_thumbnail.Nexus_5-19.png
+++ /dev/null
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_minimal_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_minimal_snippet_narrow.Nexus_5-19.png
index 497357bb..b234b9c3 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_minimal_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_minimal_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet.Nexus_5-19.png
index 4532bf1..a64ec7e2 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet_narrow.Nexus_5-19.png
index a4ec836..0c9976e 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-long_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-minimal_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-minimal_snippet.Nexus_5-19.png
index 545a9266..278fda1 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-minimal_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-minimal_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_minimal_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_minimal_snippet_narrow.Nexus_5-19.png
index 59ba15f..4e3c553 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_minimal_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_minimal_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet.Nexus_5-19.png
index 35994f29..004217a 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet_narrow.Nexus_5-19.png
index a544a6f..ed017224 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-short_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets.Nexus_5-19.png
new file mode 100644
index 0000000..37cf850
--- /dev/null
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets_narrow.Nexus_5-19.png
new file mode 100644
index 0000000..62f5cec0
--- /dev/null
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.modern-snippets_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_minimal_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_minimal_snippet_narrow.Nexus_5-19.png
index 032ffcf..80b83f7 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_minimal_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_minimal_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet.Nexus_5-19.png
index a6521d80..6ecb081 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet_narrow.Nexus_5-19.png
index ccb8345c..4f5beac5 100644
--- a/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet_narrow.Nexus_5-19.png
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.short_snippet_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets.Nexus_5-19.png
new file mode 100644
index 0000000..3ac74fa
--- /dev/null
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets_narrow.Nexus_5-19.png b/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets_narrow.Nexus_5-19.png
new file mode 100644
index 0000000..0520677
--- /dev/null
+++ b/chrome/test/data/android/render_tests/ArticleSnippetsTest.snippets_narrow.Nexus_5-19.png
Binary files differ
diff --git a/chrome/test/data/popup_blocker/popup-many-10.html b/chrome/test/data/popup_blocker/popup-many-10.html
new file mode 100644
index 0000000..c93d380
--- /dev/null
+++ b/chrome/test/data/popup_blocker/popup-many-10.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<title>Popup created using window.open</title>
+<script>
+function popup(name) {
+  window.open("popup-success" + name + ".html",
+  name, "menubar=1, resizable=1, width=350, height=250");
+}
+
+function test() {
+  for (i = 0; i < 10; i++) {
+    popup('window' + i);
+  }
+}
+</script>
+</head>
+<body onload="test()">
+pop-up test page
+</body>
+</html>
\ No newline at end of file
diff --git a/components/cronet/cronet_prefs_manager.cc b/components/cronet/cronet_prefs_manager.cc
index 32acc7bb..953cdf6 100644
--- a/components/cronet/cronet_prefs_manager.cc
+++ b/components/cronet/cronet_prefs_manager.cc
@@ -292,11 +292,6 @@
   http_server_properties_manager_->ShutdownOnPrefSequence();
   if (network_qualities_prefs_manager_)
     network_qualities_prefs_manager_->ShutdownOnPrefSequence();
-
-  // TODO(crbug.com/758711): revisit to see whether the logic can be simplified
-  // after SDCH is removed. Destroy |host_cache_persistence_manager_| before the
-  // caller destroys UrlRequestContext.
-  host_cache_persistence_manager_.reset(nullptr);
 }
 
 }  // namespace cronet
diff --git a/components/exo/keyboard_unittest.cc b/components/exo/keyboard_unittest.cc
index ba7ff9b..1fab3ec3 100644
--- a/components/exo/keyboard_unittest.cc
+++ b/components/exo/keyboard_unittest.cc
@@ -216,6 +216,12 @@
   keyboard.reset();
 }
 
+// Test fails consistently on CrOS: crbug.com/764338
+#if defined(OS_CHROMEOS)
+#define MAYBE_OnKeyboardTypeChanged DISABLED_OnKeyboardTypeChanged
+#else
+#define MAYBE_OnKeyboardTypeChanged OnKeyboardTypeChanged
+#endif
 TEST_F(KeyboardTest, OnKeyboardTypeChanged) {
   std::unique_ptr<Surface> surface(new Surface);
   std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
diff --git a/components/ntp_snippets/features.h b/components/ntp_snippets/features.h
index e092a09a..130e97d 100644
--- a/components/ntp_snippets/features.h
+++ b/components/ntp_snippets/features.h
@@ -46,10 +46,10 @@
 // Feature to allow the new Google favicon server for fetching publisher icons.
 extern const base::Feature kPublisherFaviconsFromNewServerFeature;
 
-// Feature for simple experimental comparision and validation of changes since
+// Feature for simple experimental comparison and validation of changes since
 // M58: enabling this brings back the M58 Stable fetching schedule (which is
 // suitable for Holdback groups).
-// TODO(jkrcal): Remove when the comparision is done (probably after M62).
+// TODO(jkrcal): Remove when the comparison is done (probably after M62).
 extern const base::Feature kRemoteSuggestionsEmulateM58FetchingSchedule;
 
 // Parameter and its values for the kCategoryRanker feature flag.
@@ -123,11 +123,6 @@
 // have been fetched.
 extern const base::Feature kKeepPrefetchedContentSuggestions;
 
-// Whether remote categories (except articles) which are not present in the last
-// fetch response should be deleted. This feature implicitly depends on
-// kArticleSuggestionsFeature.
-extern const base::Feature kDeleteRemoteCategoriesNotPresentInLastFetch;
-
 }  // namespace ntp_snippets
 
 #endif  // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
index 543ccb0..3837597b 100644
--- a/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_scheduler_impl.cc
@@ -70,7 +70,7 @@
 const double kDefaultFetchingIntervalHoursActiveSuggestionsConsumer[] = {
     48.0, 24.0, 12.0, 12.0, 1.0, 1.0};
 
-// For a simple comparision: fetching intervals that emulate the state really
+// For a simple comparison: fetching intervals that emulate the state really
 // rolled out to 100% M58 Stable. Used for evaluation of later changes. DBL_MAX
 // values simulate this interval being disabled.
 // TODO(jkrcal): Remove when not needed any more, incl. the feature. Probably
@@ -140,11 +140,6 @@
 
 const int kBlockBackgroundFetchesMinutesAfterClearingHistory = 30;
 
-const char kSnippetSoftFetchingIntervalOnUsageEventDeprecated[] =
-    "ntp_snippets.soft_fetching_interval_on_usage_event";
-const char kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated[] =
-    "ntp_snippets.soft_fetching_interval_on_ntp_opened";
-
 // Returns the time interval to use for scheduling remote suggestion fetches for
 // the given interval and user_class.
 base::TimeDelta GetDesiredFetchingInterval(
@@ -461,10 +456,6 @@
   DCHECK(user_classifier);
   DCHECK(profile_prefs);
 
-  // Cleanup procedure in M59. Remove for M62.
-  profile_prefs_->ClearPref(kSnippetSoftFetchingIntervalOnUsageEventDeprecated);
-  profile_prefs_->ClearPref(kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated);
-
   LoadLastFetchingSchedule();
 }
 
@@ -482,12 +473,6 @@
   registry->RegisterInt64Pref(prefs::kSnippetShownFetchingIntervalWifi, 0);
   registry->RegisterInt64Pref(prefs::kSnippetShownFetchingIntervalFallback, 0);
   registry->RegisterInt64Pref(prefs::kSnippetLastFetchAttempt, 0);
-
-  // Cleanup procedure in M59. Remove for M62.
-  registry->RegisterInt64Pref(
-      kSnippetSoftFetchingIntervalOnUsageEventDeprecated, 0);
-  registry->RegisterInt64Pref(kSnippetSoftFetchingIntervalOnNtpOpenedDeprecated,
-                              0);
 }
 
 void RemoteSuggestionsSchedulerImpl::SetProvider(
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 53ca290..f22e769 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -339,7 +339,7 @@
 std::unique_ptr<blink::WebURLLoader>
 WebViewPlugin::WebViewHelper::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // TODO(yhirano): Stop using Platform::CreateURLLoader() here.
   return blink::Platform::Current()->CreateURLLoader(request, task_runner);
 }
diff --git a/components/plugins/renderer/webview_plugin.h b/components/plugins/renderer/webview_plugin.h
index b6bac6f3..d8ea6d5 100644
--- a/components/plugins/renderer/webview_plugin.h
+++ b/components/plugins/renderer/webview_plugin.h
@@ -178,7 +178,7 @@
     void ScheduleAnimation() override;
     std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
         const blink::WebURLRequest& request,
-        base::SingleThreadTaskRunner* task_runner) override;
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
 
     // WebFrameClient methods:
     void DidClearWindowObject() override;
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 18469953..b030aafd 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -709,7 +709,7 @@
   void FrameDetached(DetachType detach_type) override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   service_manager::InterfaceProvider* GetInterfaceProvider() override;
 
   void CallOnReady();
@@ -896,9 +896,10 @@
 std::unique_ptr<blink::WebURLLoader>
 PrepareFrameAndViewForPrint::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // TODO(yhirano): Stop using Platform::CreateURLLoader() here.
-  return blink::Platform::Current()->CreateURLLoader(request, task_runner);
+  return blink::Platform::Current()->CreateURLLoader(request,
+                                                     std::move(task_runner));
 }
 
 service_manager::InterfaceProvider*
diff --git a/components/resources/default_100_percent/autofill/cc-generic.png b/components/resources/default_100_percent/autofill/cc-generic.png
index 4b699db..1ee634be 100644
--- a/components/resources/default_100_percent/autofill/cc-generic.png
+++ b/components/resources/default_100_percent/autofill/cc-generic.png
Binary files differ
diff --git a/components/resources/default_200_percent/autofill/cc-generic.png b/components/resources/default_200_percent/autofill/cc-generic.png
index c0af2dd..5eadeec 100644
--- a/components/resources/default_200_percent/autofill/cc-generic.png
+++ b/components/resources/default_200_percent/autofill/cc-generic.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/amex.png b/components/resources/default_300_percent/autofill/amex.png
new file mode 100644
index 0000000..99584118
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/amex.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/cc-generic.png b/components/resources/default_300_percent/autofill/cc-generic.png
new file mode 100644
index 0000000..1a556d0
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/cc-generic.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/diners.png b/components/resources/default_300_percent/autofill/diners.png
new file mode 100644
index 0000000..b3eaa4e
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/diners.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/discover.png b/components/resources/default_300_percent/autofill/discover.png
new file mode 100644
index 0000000..9ba9a63f
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/discover.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/jcb.png b/components/resources/default_300_percent/autofill/jcb.png
new file mode 100644
index 0000000..5a924a2
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/jcb.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/mastercard.png b/components/resources/default_300_percent/autofill/mastercard.png
new file mode 100644
index 0000000..4769517
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/mastercard.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/mir.png b/components/resources/default_300_percent/autofill/mir.png
new file mode 100644
index 0000000..41b8cc5
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/mir.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/unionpay.png b/components/resources/default_300_percent/autofill/unionpay.png
new file mode 100644
index 0000000..98cc3a7
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/unionpay.png
Binary files differ
diff --git a/components/resources/default_300_percent/autofill/visa.png b/components/resources/default_300_percent/autofill/visa.png
new file mode 100644
index 0000000..189d94e
--- /dev/null
+++ b/components/resources/default_300_percent/autofill/visa.png
Binary files differ
diff --git a/components/viz/common/resources/platform_color.h b/components/viz/common/resources/platform_color.h
index 5a6caba5..9c0fa1e 100644
--- a/components/viz/common/resources/platform_color.h
+++ b/components/viz/common/resources/platform_color.h
@@ -60,7 +60,6 @@
       case RED_8:
       case LUMINANCE_F16:
       case RGBA_F16:
-      case R16_EXT:
         NOTREACHED();
         return false;
     }
diff --git a/components/viz/common/resources/platform_color_unittest.cc b/components/viz/common/resources/platform_color_unittest.cc
index feab684..f8012176 100644
--- a/components/viz/common/resources/platform_color_unittest.cc
+++ b/components/viz/common/resources/platform_color_unittest.cc
@@ -33,7 +33,6 @@
       case RED_8:
       case LUMINANCE_F16:
       case RGBA_F16:
-      case R16_EXT:
         break;
     }
   }
diff --git a/components/viz/common/resources/resource_format.h b/components/viz/common/resources/resource_format.h
index 265a064cb..1e90781 100644
--- a/components/viz/common/resources/resource_format.h
+++ b/components/viz/common/resources/resource_format.h
@@ -20,8 +20,7 @@
   RED_8,
   LUMINANCE_F16,
   RGBA_F16,
-  R16_EXT,
-  RESOURCE_FORMAT_MAX = R16_EXT,
+  RESOURCE_FORMAT_MAX = RGBA_F16,
 };
 
 }  // namespace viz
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
index 161290a..4cee8649 100644
--- a/components/viz/common/resources/resource_format_utils.cc
+++ b/components/viz/common/resources/resource_format_utils.cc
@@ -29,7 +29,6 @@
     case ETC1:
     case RED_8:
     case LUMINANCE_F16:
-    case R16_EXT:
       return kN32_SkColorType;
     case RGBA_F16:
       return kRGBA_F16_SkColorType;
@@ -48,7 +47,6 @@
     case RGBA_4444:
     case RGB_565:
     case LUMINANCE_F16:
-    case R16_EXT:
       return 16;
     case ALPHA_8:
     case LUMINANCE_8:
@@ -74,7 +72,6 @@
       GL_UNSIGNED_BYTE,           // RED_8
       GL_HALF_FLOAT_OES,          // LUMINANCE_F16
       GL_HALF_FLOAT_OES,          // RGBA_F16
-      GL_UNSIGNED_SHORT,          // R16_EXT
   };
   static_assert(arraysize(format_gl_data_type) == (RESOURCE_FORMAT_MAX + 1),
                 "format_gl_data_type does not handle all cases.");
@@ -95,7 +92,6 @@
       GL_RED_EXT,        // RED_8
       GL_LUMINANCE,      // LUMINANCE_F16
       GL_RGBA,           // RGBA_F16
-      GL_R16_EXT,        // R16_EXT
   };
   static_assert(arraysize(format_gl_data_format) == (RESOURCE_FORMAT_MAX + 1),
                 "format_gl_data_format does not handle all cases.");
@@ -127,7 +123,6 @@
       GL_LUMINANCE,  // RED_8
       GL_LUMINANCE,  // LUMINANCE_F16
       GL_RGBA,       // RGBA_F16
-      GL_LUMINANCE,  // R16_EXT
   };
   static_assert(arraysize(format_gl_data_format) == (RESOURCE_FORMAT_MAX + 1),
                 "format_gl_data_format does not handle all cases.");
@@ -140,8 +135,6 @@
       return gfx::BufferFormat::BGRA_8888;
     case RED_8:
       return gfx::BufferFormat::R_8;
-    case R16_EXT:
-      return gfx::BufferFormat::R_16;
     case RGBA_4444:
       return gfx::BufferFormat::RGBA_4444;
     case RGBA_8888:
@@ -194,7 +187,6 @@
     case ETC1:
     case RED_8:
     case LUMINANCE_F16:
-    case R16_EXT:
       return false;
   }
   NOTREACHED();
diff --git a/components/viz/common/resources/resource_settings.h b/components/viz/common/resources/resource_settings.h
index 4ace644..31ab9d0 100644
--- a/components/viz/common/resources/resource_settings.h
+++ b/components/viz/common/resources/resource_settings.h
@@ -21,9 +21,6 @@
 
   size_t texture_id_allocation_chunk_size = 64;
   bool use_gpu_memory_buffer_resources = false;
-  bool high_bit_for_testing = false;
-  // TODO(riju): Remove after r16 is used without the flag. crbug.com/759456
-  bool use_r16_texture = false;
   BufferToTextureTargetMap buffer_to_texture_target_map;
 };
 
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index aae0db5..31a250f 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -328,12 +328,25 @@
 MSVC_DISABLE_OPTIMIZE()
 MSVC_PUSH_DISABLE_WARNING(4748)
 
+NOINLINE void ResetThread_DB() {
+  volatile int inhibit_comdat = __LINE__;
+  ALLOW_UNUSED_LOCAL(inhibit_comdat);
+  BrowserThreadImpl::StopRedirectionOfThreadID(BrowserThread::DB);
+}
+
 NOINLINE void ResetThread_FILE() {
   volatile int inhibit_comdat = __LINE__;
   ALLOW_UNUSED_LOCAL(inhibit_comdat);
   BrowserThreadImpl::StopRedirectionOfThreadID(BrowserThread::FILE);
 }
 
+NOINLINE void ResetThread_FILE_USER_BLOCKING() {
+  volatile int inhibit_comdat = __LINE__;
+  ALLOW_UNUSED_LOCAL(inhibit_comdat);
+  BrowserThreadImpl::StopRedirectionOfThreadID(
+      BrowserThread::FILE_USER_BLOCKING);
+}
+
 #if defined(OS_ANDROID)
 NOINLINE void ResetThread_PROCESS_LAUNCHER(
     std::unique_ptr<BrowserProcessSubThread> thread) {
@@ -349,6 +362,21 @@
 }
 #endif  // defined(OS_ANDROID)
 
+#if defined(OS_WIN)
+NOINLINE void ResetThread_CACHE(
+    std::unique_ptr<BrowserProcessSubThread> thread) {
+  volatile int inhibit_comdat = __LINE__;
+  ALLOW_UNUSED_LOCAL(inhibit_comdat);
+    thread.reset();
+}
+#else   // defined(OS_WIN)
+NOINLINE void ResetThread_CACHE() {
+  volatile int inhibit_comdat = __LINE__;
+  ALLOW_UNUSED_LOCAL(inhibit_comdat);
+  BrowserThreadImpl::StopRedirectionOfThreadID(BrowserThread::CACHE);
+}
+#endif  // defined(OS_WIN)
+
 NOINLINE void ResetThread_IO(std::unique_ptr<BrowserProcessSubThread> thread) {
   volatile int inhibit_comdat = __LINE__;
   ALLOW_UNUSED_LOCAL(inhibit_comdat);
@@ -1031,6 +1059,18 @@
         base::TaskShutdownBehavior::BLOCK_SHUTDOWN};
 
     switch (thread_id) {
+      case BrowserThread::DB:
+        TRACE_EVENT_BEGIN1("startup",
+            "BrowserMainLoop::CreateThreads:start",
+            "Thread", "BrowserThread::DB");
+        non_ui_non_io_task_runner_traits = kUserVisibleTraits;
+        break;
+      case BrowserThread::FILE_USER_BLOCKING:
+        TRACE_EVENT_BEGIN1("startup",
+            "BrowserMainLoop::CreateThreads:start",
+            "Thread", "BrowserThread::FILE_USER_BLOCKING");
+        non_ui_non_io_task_runner_traits = kUserBlockingTraits;
+        break;
       case BrowserThread::FILE:
         TRACE_EVENT_BEGIN1("startup",
             "BrowserMainLoop::CreateThreads:start",
@@ -1052,6 +1092,23 @@
         non_ui_non_io_task_runner_traits = kUserBlockingTraits;
 #endif  // defined(OS_ANDROID)
         break;
+      case BrowserThread::CACHE:
+        TRACE_EVENT_BEGIN1("startup",
+            "BrowserMainLoop::CreateThreads:start",
+            "Thread", "BrowserThread::CACHE");
+#if defined(OS_WIN)
+        // TaskScheduler doesn't support async I/O on Windows as CACHE thread is
+        // the only user and this use case is going away in
+        // https://codereview.chromium.org/2216583003/.
+        // TODO(gavinp): Remove this ifdef (and thus enable redirection of the
+        // CACHE thread on Windows) once that CL lands.
+        thread_to_start = &cache_thread_;
+        options = io_message_loop_options;
+        options.timer_slack = base::TIMER_SLACK_MAXIMUM;
+#else  // OS_WIN
+        non_ui_non_io_task_runner_traits = kUserBlockingTraits;
+#endif  // OS_WIN
+        break;
       case BrowserThread::IO:
         TRACE_EVENT_BEGIN1("startup",
             "BrowserMainLoop::CreateThreads:start",
@@ -1249,7 +1306,14 @@
       // - The PROCESS_LAUNCHER thread must be stopped after IO in case
       //   the IO thread posted a task to terminate a process on the
       //   process launcher thread.
+      //
+      // - (Not sure why DB stops last.)
       switch (thread_id) {
+        case BrowserThread::DB: {
+          TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:DBThread");
+          ResetThread_DB();
+          break;
+        }
         case BrowserThread::FILE: {
           TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:FileThread");
           // Clean up state that lives on or uses the FILE thread before it goes
@@ -1259,6 +1323,12 @@
           ResetThread_FILE();
           break;
         }
+        case BrowserThread::FILE_USER_BLOCKING: {
+          TRACE_EVENT0("shutdown",
+                       "BrowserMainLoop::Subsystem:FileUserBlockingThread");
+          ResetThread_FILE_USER_BLOCKING();
+          break;
+        }
         case BrowserThread::PROCESS_LAUNCHER: {
           TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:LauncherThread");
 #if defined(OS_ANDROID)
@@ -1268,6 +1338,15 @@
 #endif  // defined(OS_ANDROID)
           break;
         }
+        case BrowserThread::CACHE: {
+          TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:CacheThread");
+#if defined(OS_WIN)
+          ResetThread_CACHE(std::move(cache_thread_));
+#else   // defined(OS_WIN)
+          ResetThread_CACHE();
+#endif  // defined(OS_WIN)
+          break;
+        }
         case BrowserThread::IO: {
           TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread");
           ResetThread_IO(std::move(io_thread_));
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index fa962f29..d341e72d 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -316,6 +316,13 @@
   // On Android, the PROCESS_LAUNCHER thread is handled by Java,
   // |process_launcher_thread_| is merely a proxy to the real message loop.
   std::unique_ptr<BrowserProcessSubThread> process_launcher_thread_;
+#elif defined(OS_WIN)
+  // TaskScheduler doesn't support async I/O on Windows as CACHE thread is
+  // the only user and this use case is going away in
+  // https://codereview.chromium.org/2216583003/.
+  // TODO(gavinp): Remove this (and thus enable redirection of the CACHE thread
+  // on Windows) once that CL lands.
+  std::unique_ptr<BrowserProcessSubThread> cache_thread_;
 #endif
 
   // Members initialized in |BrowserThreadsStarted()| --------------------------
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index a222c790..8bb84ee 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -34,8 +34,11 @@
 // Friendly names for the well-known threads.
 static const char* const g_browser_thread_names[BrowserThread::ID_COUNT] = {
   "",  // UI (name assembled in browser_main.cc).
+  "Chrome_DBThread",  // DB
   "Chrome_FileThread",  // FILE
+  "Chrome_FileUserBlockingThread",  // FILE_USER_BLOCKING
   "Chrome_ProcessLauncherThread",  // PROCESS_LAUNCHER
+  "Chrome_CacheThread",  // CACHE
   "Chrome_IOThread",  // IO
 };
 
@@ -208,8 +211,11 @@
   }
 #endif  // DCHECK_IS_ON()
 
-  if (identifier_ == BrowserThread::FILE ||
-      identifier_ == BrowserThread::PROCESS_LAUNCHER) {
+  if (identifier_ == BrowserThread::DB ||
+      identifier_ == BrowserThread::FILE ||
+      identifier_ == BrowserThread::FILE_USER_BLOCKING ||
+      identifier_ == BrowserThread::PROCESS_LAUNCHER ||
+      identifier_ == BrowserThread::CACHE) {
     // Nesting and task observers are not allowed on redirected threads.
     base::RunLoop::DisallowNestingOnCurrentThread();
     message_loop()->DisallowTaskObservers();
@@ -234,12 +240,25 @@
   CHECK_GT(line_number, 0);
 }
 
+NOINLINE void BrowserThreadImpl::DBThreadRun(base::RunLoop* run_loop) {
+  volatile int line_number = __LINE__;
+  Thread::Run(run_loop);
+  CHECK_GT(line_number, 0);
+}
+
 NOINLINE void BrowserThreadImpl::FileThreadRun(base::RunLoop* run_loop) {
   volatile int line_number = __LINE__;
   Thread::Run(run_loop);
   CHECK_GT(line_number, 0);
 }
 
+NOINLINE void BrowserThreadImpl::FileUserBlockingThreadRun(
+    base::RunLoop* run_loop) {
+  volatile int line_number = __LINE__;
+  Thread::Run(run_loop);
+  CHECK_GT(line_number, 0);
+}
+
 NOINLINE void BrowserThreadImpl::ProcessLauncherThreadRun(
     base::RunLoop* run_loop) {
   volatile int line_number = __LINE__;
@@ -247,6 +266,12 @@
   CHECK_GT(line_number, 0);
 }
 
+NOINLINE void BrowserThreadImpl::CacheThreadRun(base::RunLoop* run_loop) {
+  volatile int line_number = __LINE__;
+  Thread::Run(run_loop);
+  CHECK_GT(line_number, 0);
+}
+
 NOINLINE void BrowserThreadImpl::IOThreadRun(base::RunLoop* run_loop) {
   volatile int line_number = __LINE__;
   Thread::Run(run_loop);
@@ -273,10 +298,16 @@
   switch (identifier_) {
     case BrowserThread::UI:
       return UIThreadRun(run_loop);
+    case BrowserThread::DB:
+      return DBThreadRun(run_loop);
     case BrowserThread::FILE:
       return FileThreadRun(run_loop);
+    case BrowserThread::FILE_USER_BLOCKING:
+      return FileUserBlockingThreadRun(run_loop);
     case BrowserThread::PROCESS_LAUNCHER:
       return ProcessLauncherThreadRun(run_loop);
+    case BrowserThread::CACHE:
+      return CacheThreadRun(run_loop);
     case BrowserThread::IO:
       return IOThreadRun(run_loop);
     case BrowserThread::ID_COUNT:
diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h
index 050fae4e..00681000 100644
--- a/content/browser/browser_thread_impl.h
+++ b/content/browser/browser_thread_impl.h
@@ -78,8 +78,11 @@
   // The following are unique function names that makes it possible to tell
   // the thread id from the callstack alone in crash dumps.
   void UIThreadRun(base::RunLoop* run_loop);
+  void DBThreadRun(base::RunLoop* run_loop);
   void FileThreadRun(base::RunLoop* run_loop);
+  void FileUserBlockingThreadRun(base::RunLoop* run_loop);
   void ProcessLauncherThreadRun(base::RunLoop* run_loop);
+  void CacheThreadRun(base::RunLoop* run_loop);
   void IOThreadRun(base::RunLoop* run_loop);
 
   static bool PostTaskHelper(BrowserThread::ID identifier,
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index 886e0ec..fbcb30c 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -56,6 +56,19 @@
 
 const char kRecordBytesLabel[] = "DiskCache.CacheStorage";
 
+// The range of the padding added to response sizes for opaque resources.
+// Increment padding version if changed.
+const uint64_t kPaddingRange = 14431 * 1024;
+
+// If the way that a cache's padding is calculated changes increment this
+// version.
+//
+// History:
+//
+//   1: Uniform random 400K.
+//   2: Uniform random 14,431K.
+const int32_t kCachePaddingAlgorithmVersion = 2;
+
 // This class ensures that the cache and the entry have a lifetime as long as
 // the blob that is created to contain them.
 class CacheStorageCacheDataHandle
@@ -291,20 +304,10 @@
                                !response->url_list.empty());
 }
 
-// If the way that a cache's padding is calculated changes increment this
-// version.
-//
-// History:
-//
-//   1: Uniform random 400K.
-const int32_t kCachePaddingAlgorithmVersion = 1;
-
 int64_t CalculateResponsePaddingInternal(
     const std::string& response_url,
     const crypto::SymmetricKey* padding_key,
     int side_data_size) {
-  const uint64_t kPaddingRange = 400 * 1024;  // Increment version if changed.
-
   DCHECK(!response_url.empty());
 
   crypto::HMAC hmac(crypto::HMAC::SHA256);
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index f4df62df..67a9d8b 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -206,27 +206,27 @@
 void DispatchNotificationClickEventOnWorker(
     const scoped_refptr<ServiceWorkerVersion>& service_worker,
     const NotificationDatabaseData& notification_database_data,
-    int action_index,
-    const base::NullableString16& reply,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
     const ServiceWorkerVersion::StatusCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   int request_id = service_worker->StartRequest(
       ServiceWorkerMetrics::EventType::NOTIFICATION_CLICK, callback);
 
-  base::Optional<base::string16> optional_reply;
-  if (!reply.is_null())
-    optional_reply = reply.string();
+  int action_index_int = -1 /* no value */;
+  if (action_index.has_value())
+    action_index_int = action_index.value();
 
   service_worker->event_dispatcher()->DispatchNotificationClickEvent(
       notification_database_data.notification_id,
-      notification_database_data.notification_data, action_index,
-      optional_reply, service_worker->CreateSimpleEventCallback(request_id));
+      notification_database_data.notification_data, action_index_int, reply,
+      service_worker->CreateSimpleEventCallback(request_id));
 }
 
 // Dispatches the notification click event on the |service_worker_registration|.
 void DoDispatchNotificationClickEvent(
-    int action_index,
-    const base::NullableString16& reply,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
     const NotificationDispatchCompleteCallback& dispatch_complete_callback,
     const scoped_refptr<PlatformNotificationContext>& notification_context,
     const ServiceWorkerRegistration* service_worker_registration,
@@ -368,8 +368,8 @@
     BrowserContext* browser_context,
     const std::string& notification_id,
     const GURL& origin,
-    int action_index,
-    const base::NullableString16& reply,
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply,
     const NotificationDispatchCompleteCallback& dispatch_complete_callback) {
   DispatchNotificationEvent(
       browser_context, notification_id, origin,
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.h b/content/browser/notifications/notification_event_dispatcher_impl.h
index 3e19af6..761783f 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.h
+++ b/content/browser/notifications/notification_event_dispatcher_impl.h
@@ -25,8 +25,8 @@
       BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& origin,
-      int action_index,
-      const base::NullableString16& reply,
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply,
       const NotificationDispatchCompleteCallback& dispatch_complete_callback)
       override;
   void DispatchNotificationCloseEvent(
diff --git a/content/child/service_worker/service_worker_network_provider.cc b/content/child/service_worker/service_worker_network_provider.cc
index 65ff2b6..90562ea 100644
--- a/content/child/service_worker/service_worker_network_provider.cc
+++ b/content/child/service_worker/service_worker_network_provider.cc
@@ -97,7 +97,7 @@
 
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override {
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
     // ChildThreadImpl is nullptr in some tests.
     if (!ChildThreadImpl::current())
       return nullptr;
@@ -125,7 +125,8 @@
     // Create our own SubresourceLoader to route the request
     // to the controller ServiceWorker.
     return base::MakeUnique<WebURLLoaderImpl>(
-        ChildThreadImpl::current()->resource_dispatcher(), task_runner,
+        ChildThreadImpl::current()->resource_dispatcher(),
+        std::move(task_runner),
         provider_->context()->subresource_loader_factory());
   }
 
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index bf393b7..678b0d0d 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -208,7 +208,7 @@
 
 std::unique_ptr<blink::WebURLLoader> PpapiBlinkPlatformImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   NOTREACHED();
   return NULL;
 }
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.h b/content/ppapi_plugin/ppapi_blink_platform_impl.h
index f768451..8dd81b5 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.h
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.h
@@ -44,7 +44,7 @@
   blink::WebThemeEngine* ThemeEngine() override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   void GetPluginList(bool refresh,
                      const blink::WebSecurityOrigin& mainFrameOrigin,
                      blink::WebPluginListBuilder*) override;
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index 7a27813f..47bcbfc8 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -68,6 +68,9 @@
     // The main thread in the browser.
     UI,
 
+    // This is the thread that interacts with the database.
+    DB,
+
     // This is the thread that interacts with the file system.
     // DEPRECATED: prefer base/task_scheduler/post_task.h for new classes
     // requiring a background file I/O task runner, i.e.:
@@ -78,11 +81,23 @@
     //         is visible but non-blocking to the user.
     FILE,
 
+    // Used for file system operations that block user interactions.
+    // Responsiveness of this thread affect users.
+    // DEPRECATED: prefer base/task_scheduler/post_task.h for new classes
+    // requiring a user-blocking file I/O task runner, i.e.:
+    //   base::CreateSequencedTaskRunnerWithTraits(
+    //       {base::MayBlock(), base::TaskPriority::USER_BLOCKING})
+    FILE_USER_BLOCKING,
+
     // Used to launch and terminate Chrome processes.
     PROCESS_LAUNCHER,
 
+    // This is the thread to handle slow HTTP cache operations.
+    CACHE,
+
     // This is the thread that processes non-blocking IO, i.e. IPC and network.
-    // Blocking IO should happen in TaskScheduler.
+    // Blocking IO should happen on other threads like DB, FILE,
+    // FILE_USER_BLOCKING and CACHE depending on the usage.
     IO,
 
     // NOTE: do not add new threads here that are only used by a small number of
@@ -306,6 +321,7 @@
   struct DeleteOnUIThread : public DeleteOnThread<UI> { };
   struct DeleteOnIOThread : public DeleteOnThread<IO> { };
   struct DeleteOnFileThread : public DeleteOnThread<FILE> { };
+  struct DeleteOnDBThread : public DeleteOnThread<DB> { };
 
   // Returns an appropriate error message for when DCHECK_CURRENTLY_ON() fails.
   static std::string GetDCheckCurrentlyOnErrorMessage(ID expected);
diff --git a/content/public/browser/notification_event_dispatcher.h b/content/public/browser/notification_event_dispatcher.h
index 5ffdc6f..7ea8e1fd 100644
--- a/content/public/browser/notification_event_dispatcher.h
+++ b/content/public/browser/notification_event_dispatcher.h
@@ -8,15 +8,13 @@
 #include <string>
 
 #include "base/callback_forward.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/common/content_export.h"
 #include "content/public/common/persistent_notification_status.h"
 
 class GURL;
 
-namespace base {
-class NullableString16;
-}
-
 namespace content {
 
 class BrowserContext;
@@ -42,8 +40,8 @@
       BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& origin,
-      int action_index,
-      const base::NullableString16& reply,
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply,
       const NotificationDispatchCompleteCallback&
           dispatch_complete_callback) = 0;
 
diff --git a/content/public/renderer/render_frame.h b/content/public/renderer/render_frame.h
index 5a4b1ec..56edee3e 100644
--- a/content/public/renderer/render_frame.h
+++ b/content/public/renderer/render_frame.h
@@ -263,9 +263,11 @@
 
   // Renderer scheduler frame-specific task queues handles.
   // See third_party/WebKit/Source/platform/WebFrameScheduler.h for details.
-  virtual base::SingleThreadTaskRunner* GetTimerTaskRunner() = 0;
-  virtual base::SingleThreadTaskRunner* GetLoadingTaskRunner() = 0;
-  virtual base::SingleThreadTaskRunner* GetUnthrottledTaskRunner() = 0;
+  virtual scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner() = 0;
+  virtual scoped_refptr<base::SingleThreadTaskRunner>
+  GetLoadingTaskRunner() = 0;
+  virtual scoped_refptr<base::SingleThreadTaskRunner>
+  GetUnthrottledTaskRunner() = 0;
 
   // Bitwise-ORed set of extra bindings that have been enabled.  See
   // BindingsPolicy for details.
diff --git a/content/public/test/test_browser_thread_bundle.cc b/content/public/test/test_browser_thread_bundle.cc
index 864e1b9..461c80e 100644
--- a/content/public/test/test_browser_thread_bundle.cc
+++ b/content/public/test/test_browser_thread_bundle.cc
@@ -45,10 +45,16 @@
   base::RunLoop().RunUntilIdle();
   io_thread_->Stop();
   base::RunLoop().RunUntilIdle();
+  cache_thread_->Stop();
+  base::RunLoop().RunUntilIdle();
   process_launcher_thread_->Stop();
   base::RunLoop().RunUntilIdle();
+  file_user_blocking_thread_->Stop();
+  base::RunLoop().RunUntilIdle();
   file_thread_->Stop();
   base::RunLoop().RunUntilIdle();
+  db_thread_->Stop();
+  base::RunLoop().RunUntilIdle();
   // This is the point at which we normally shut down the thread pool. So flush
   // it again in case any shutdown tasks have been posted to the pool from the
   // threads above.
@@ -129,6 +135,14 @@
 void TestBrowserThreadBundle::CreateBrowserThreads() {
   CHECK(!threads_created_);
 
+  if (options_ & REAL_DB_THREAD) {
+    db_thread_ = base::MakeUnique<TestBrowserThread>(BrowserThread::DB);
+    db_thread_->Start();
+  } else {
+    db_thread_ = base::MakeUnique<TestBrowserThread>(
+        BrowserThread::DB, base::MessageLoop::current());
+  }
+
   if (options_ & REAL_FILE_THREAD) {
     file_thread_ = base::MakeUnique<TestBrowserThread>(BrowserThread::FILE);
     file_thread_->Start();
@@ -137,8 +151,12 @@
         BrowserThread::FILE, base::MessageLoop::current());
   }
 
+  file_user_blocking_thread_ = base::MakeUnique<TestBrowserThread>(
+      BrowserThread::FILE_USER_BLOCKING, base::MessageLoop::current());
   process_launcher_thread_ = base::MakeUnique<TestBrowserThread>(
       BrowserThread::PROCESS_LAUNCHER, base::MessageLoop::current());
+  cache_thread_ = base::MakeUnique<TestBrowserThread>(
+      BrowserThread::CACHE, base::MessageLoop::current());
 
   if (options_ & REAL_IO_THREAD) {
     io_thread_ = base::MakeUnique<TestBrowserThread>(BrowserThread::IO);
diff --git a/content/public/test/test_browser_thread_bundle.h b/content/public/test/test_browser_thread_bundle.h
index dd33ee53..079e339 100644
--- a/content/public/test/test_browser_thread_bundle.h
+++ b/content/public/test/test_browser_thread_bundle.h
@@ -113,9 +113,10 @@
   enum Options {
     DEFAULT = 0,
     IO_MAINLOOP = 1 << 0,
-    REAL_FILE_THREAD = 1 << 1,
-    REAL_IO_THREAD = 1 << 2,
-    DONT_CREATE_BROWSER_THREADS = 1 << 3,
+    REAL_DB_THREAD = 1 << 1,
+    REAL_FILE_THREAD = 1 << 2,
+    REAL_IO_THREAD = 1 << 3,
+    DONT_CREATE_BROWSER_THREADS = 1 << 4,
   };
 
   TestBrowserThreadBundle();
@@ -132,8 +133,11 @@
 
   std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment_;
   std::unique_ptr<TestBrowserThread> ui_thread_;
+  std::unique_ptr<TestBrowserThread> db_thread_;
   std::unique_ptr<TestBrowserThread> file_thread_;
+  std::unique_ptr<TestBrowserThread> file_user_blocking_thread_;
   std::unique_ptr<TestBrowserThread> process_launcher_thread_;
+  std::unique_ptr<TestBrowserThread> cache_thread_;
   std::unique_ptr<TestBrowserThread> io_thread_;
 
   int options_;
diff --git a/content/renderer/fetchers/resource_fetcher_impl.cc b/content/renderer/fetchers/resource_fetcher_impl.cc
index ffac69c9..a3cc4bf 100644
--- a/content/renderer/fetchers/resource_fetcher_impl.cc
+++ b/content/renderer/fetchers/resource_fetcher_impl.cc
@@ -66,12 +66,12 @@
   void Start(const ResourceRequest& request,
              mojom::URLLoaderFactory* url_loader_factory,
              const net::NetworkTrafficAnnotationTag& annotation_tag,
-             base::SingleThreadTaskRunner* task_runner) {
+             scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
     status_ = Status::kStarted;
     response_.SetURL(request.url);
 
     mojom::URLLoaderClientPtr client;
-    client_binding_.Bind(mojo::MakeRequest(&client), task_runner);
+    client_binding_.Bind(mojo::MakeRequest(&client), std::move(task_runner));
 
     url_loader_factory->CreateLoaderAndStart(
         mojo::MakeRequest(&loader_), kRoutingId,
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 925475a..9a176ac3 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -59,7 +59,6 @@
 #include "content/renderer/input/input_handler_manager.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
-#include "media/base/media_switches.h"
 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
 #include "third_party/WebKit/public/platform/WebCompositeAndReadbackAsyncCallback.h"
 #include "third_party/WebKit/public/platform/WebCompositorMutatorClient.h"
@@ -351,9 +350,6 @@
     bool is_threaded) {
   cc::LayerTreeSettings settings;
 
-  settings.resource_settings.use_r16_texture =
-      base::FeatureList::IsEnabled(media::kUseR16Texture);
-
   settings.commit_to_active_tree = !is_threaded;
   settings.is_layer_tree_for_subframe = is_for_subframe;
 
diff --git a/content/renderer/media_capture_from_element/html_video_element_capturer_source.cc b/content/renderer/media_capture_from_element/html_video_element_capturer_source.cc
index cf94000f..f2b57ba 100644
--- a/content/renderer/media_capture_from_element/html_video_element_capturer_source.cc
+++ b/content/renderer/media_capture_from_element/html_video_element_capturer_source.cc
@@ -153,15 +153,16 @@
 
   if (libyuv::ConvertToI420(
           static_cast<uint8*>(bitmap_.getPixels()), bitmap_.getSize(),
-          frame->data(media::VideoFrame::kYPlane),
+          frame->visible_data(media::VideoFrame::kYPlane),
           frame->stride(media::VideoFrame::kYPlane),
-          frame->data(media::VideoFrame::kUPlane),
+          frame->visible_data(media::VideoFrame::kUPlane),
           frame->stride(media::VideoFrame::kUPlane),
-          frame->data(media::VideoFrame::kVPlane),
+          frame->visible_data(media::VideoFrame::kVPlane),
           frame->stride(media::VideoFrame::kVPlane), 0 /* crop_x */,
-          0 /* crop_y */, bitmap_.info().width(), bitmap_.info().height(),
-          frame->coded_size().width(), frame->coded_size().height(),
-          libyuv::kRotate0, source_pixel_format) == 0) {
+          0 /* crop_y */, frame->visible_rect().size().width(),
+          frame->visible_rect().size().height(), bitmap_.info().width(),
+          bitmap_.info().height(), libyuv::kRotate0,
+          source_pixel_format) == 0) {
     // Success!
     io_task_runner_->PostTask(
         FROM_HERE, base::Bind(new_frame_callback_, frame, current_time));
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 60bba6f..0aa8441 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -6849,13 +6849,13 @@
 
 std::unique_ptr<blink::WebURLLoader> RenderFrameImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   UpdatePeakMemoryStats();
 
   ChildThreadImpl* child_thread = ChildThreadImpl::current();
   if (!child_thread) {
     return RenderThreadImpl::current()->blink_platform_impl()->CreateURLLoader(
-        request, task_runner);
+        request, std::move(task_runner));
   }
 
   mojom::URLLoaderFactory* factory = custom_url_loader_factory_.get();
@@ -6878,7 +6878,7 @@
     GetFrameHost()->IssueKeepAliveHandle(mojo::MakeRequest(&keep_alive_handle));
   }
   return base::MakeUnique<WebURLLoaderImpl>(child_thread->resource_dispatcher(),
-                                            task_runner, factory,
+                                            std::move(task_runner), factory,
                                             std::move(keep_alive_handle));
 }
 
@@ -6895,15 +6895,18 @@
   return browser_side_navigation_pending_;
 }
 
-base::SingleThreadTaskRunner* RenderFrameImpl::GetTimerTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderFrameImpl::GetTimerTaskRunner() {
   return GetWebFrame()->TimerTaskRunner();
 }
 
-base::SingleThreadTaskRunner* RenderFrameImpl::GetLoadingTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderFrameImpl::GetLoadingTaskRunner() {
   return GetWebFrame()->LoadingTaskRunner();
 }
 
-base::SingleThreadTaskRunner* RenderFrameImpl::GetUnthrottledTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderFrameImpl::GetUnthrottledTaskRunner() {
   return GetWebFrame()->UnthrottledTaskRunner();
 }
 
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index ecc3c4d..c699fb5 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -473,9 +473,10 @@
   bool IsPasting() const override;
   blink::WebPageVisibilityState GetVisibilityState() const override;
   bool IsBrowserSideNavigationPending() override;
-  base::SingleThreadTaskRunner* GetTimerTaskRunner() override;
-  base::SingleThreadTaskRunner* GetLoadingTaskRunner() override;
-  base::SingleThreadTaskRunner* GetUnthrottledTaskRunner() override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetTimerTaskRunner() override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetLoadingTaskRunner() override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetUnthrottledTaskRunner()
+      override;
   int GetEnabledBindings() const override;
   // Returns non-null.
   // It is invalid to call this in an incomplete env where
@@ -692,7 +693,7 @@
   blink::WebPageVisibilityState VisibilityState() const override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   void DraggableRegionsChanged() override;
 
   // WebFrameSerializerClient implementation:
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 2246aa9..624c856 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -322,7 +322,7 @@
 
 std::unique_ptr<blink::WebURLLoader> RendererBlinkPlatformImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   ChildThreadImpl* child_thread = ChildThreadImpl::current();
 
   if (!url_loader_factory_ && child_thread)
@@ -331,8 +331,8 @@
   // There may be no child thread in RenderViewTests.  These tests can still use
   // data URLs to bypass the ResourceDispatcher.
   return base::MakeUnique<WebURLLoaderImpl>(
-      child_thread ? child_thread->resource_dispatcher() : nullptr, task_runner,
-      url_loader_factory_.get());
+      child_thread ? child_thread->resource_dispatcher() : nullptr,
+      std::move(task_runner), url_loader_factory_.get());
 }
 
 scoped_refptr<ChildURLLoaderFactoryGetter>
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 18ab5e6..53a75aa 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -244,7 +244,7 @@
 
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
 
   void RequestPurgeMemory() override;
 
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 481fcd68..04bf032 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -116,13 +116,13 @@
 
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override {
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
     RenderThreadImpl* child_thread = RenderThreadImpl::current();
     if (child_thread && provider_->script_loader_factory() &&
         ServiceWorkerUtils::IsServicificationEnabled() &&
         IsScriptRequest(request)) {
       return base::MakeUnique<WebURLLoaderImpl>(
-          child_thread->resource_dispatcher(), task_runner,
+          child_thread->resource_dispatcher(), std::move(task_runner),
           provider_->script_loader_factory());
     }
     return nullptr;
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index 754ae2f..661e190 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -24,9 +24,9 @@
 ServiceWorkerFetchContextImpl::~ServiceWorkerFetchContextImpl() {}
 
 void ServiceWorkerFetchContextImpl::InitializeOnWorkerThread(
-    base::SingleThreadTaskRunner* loading_task_runner) {
-  resource_dispatcher_ =
-      base::MakeUnique<ResourceDispatcher>(nullptr, loading_task_runner);
+    scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
+  resource_dispatcher_ = base::MakeUnique<ResourceDispatcher>(
+      nullptr, std::move(loading_task_runner));
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
 }
@@ -34,14 +34,14 @@
 std::unique_ptr<blink::WebURLLoader>
 ServiceWorkerFetchContextImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   if (request.Url().ProtocolIs(url::kBlobScheme)) {
     return base::MakeUnique<content::WebURLLoaderImpl>(
-        resource_dispatcher_.get(), task_runner,
+        resource_dispatcher_.get(), std::move(task_runner),
         url_loader_factory_getter_->GetBlobLoaderFactory());
   }
   return base::MakeUnique<content::WebURLLoaderImpl>(
-      resource_dispatcher_.get(), task_runner,
+      resource_dispatcher_.get(), std::move(task_runner),
       url_loader_factory_getter_->GetNetworkLoaderFactory());
 }
 
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index 0a740cc..2ab942b 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -26,10 +26,11 @@
   ~ServiceWorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  void InitializeOnWorkerThread(base::SingleThreadTaskRunner*) override;
+  void InitializeOnWorkerThread(
+      scoped_refptr<base::SingleThreadTaskRunner>) override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   void WillSendRequest(blink::WebURLRequest&) override;
   bool IsControlledByServiceWorker() const override;
   void SetDataSaverEnabled(bool enabled) override;
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.cc b/content/renderer/service_worker/worker_fetch_context_impl.cc
index d404b57..45ae379 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/worker_fetch_context_impl.cc
@@ -28,12 +28,12 @@
 WorkerFetchContextImpl::~WorkerFetchContextImpl() {}
 
 void WorkerFetchContextImpl::InitializeOnWorkerThread(
-    base::SingleThreadTaskRunner* loading_task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> loading_task_runner) {
   DCHECK(loading_task_runner->RunsTasksInCurrentSequence());
   DCHECK(!resource_dispatcher_);
   DCHECK(!binding_.is_bound());
-  resource_dispatcher_ =
-      base::MakeUnique<ResourceDispatcher>(nullptr, loading_task_runner);
+  resource_dispatcher_ = base::MakeUnique<ResourceDispatcher>(
+      nullptr, std::move(loading_task_runner));
 
   url_loader_factory_getter_ = url_loader_factory_getter_info_.Bind();
 
@@ -43,14 +43,14 @@
 
 std::unique_ptr<blink::WebURLLoader> WorkerFetchContextImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   if (request.Url().ProtocolIs(url::kBlobScheme)) {
     return base::MakeUnique<content::WebURLLoaderImpl>(
-        resource_dispatcher_.get(), task_runner,
+        resource_dispatcher_.get(), std::move(task_runner),
         url_loader_factory_getter_->GetBlobLoaderFactory());
   }
   return base::MakeUnique<content::WebURLLoaderImpl>(
-      resource_dispatcher_.get(), task_runner,
+      resource_dispatcher_.get(), std::move(task_runner),
       url_loader_factory_getter_->GetNetworkLoaderFactory());
 }
 
diff --git a/content/renderer/service_worker/worker_fetch_context_impl.h b/content/renderer/service_worker/worker_fetch_context_impl.h
index 8f8e344..4890303 100644
--- a/content/renderer/service_worker/worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/worker_fetch_context_impl.h
@@ -43,10 +43,11 @@
   ~WorkerFetchContextImpl() override;
 
   // blink::WebWorkerFetchContext implementation:
-  void InitializeOnWorkerThread(base::SingleThreadTaskRunner*) override;
+  void InitializeOnWorkerThread(
+      scoped_refptr<base::SingleThreadTaskRunner>) override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   void WillSendRequest(blink::WebURLRequest&) override;
   bool IsControlledByServiceWorker() const override;
   void SetDataSaverEnabled(bool) override;
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.cc b/content/shell/browser/layout_test/layout_test_message_filter.cc
index 5c8ba5b..558994a 100644
--- a/content/shell/browser/layout_test/layout_test_message_filter.cc
+++ b/content/shell/browser/layout_test/layout_test_message_filter.cc
@@ -133,8 +133,8 @@
 
 void LayoutTestMessageFilter::OnSimulateWebNotificationClick(
     const std::string& title,
-    int action_index,
-    const base::NullableString16& reply) {
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   LayoutTestNotificationManager* manager =
       LayoutTestContentBrowserClient::Get()->GetLayoutTestNotificationManager();
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.h b/content/shell/browser/layout_test/layout_test_message_filter.h
index 6dabd303..105a5a76 100644
--- a/content/shell/browser/layout_test/layout_test_message_filter.h
+++ b/content/shell/browser/layout_test/layout_test_message_filter.h
@@ -10,6 +10,8 @@
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
 
@@ -17,7 +19,6 @@
 
 namespace base {
 class DictionaryValue;
-class NullableString16;
 }
 
 namespace net {
@@ -59,9 +60,10 @@
   void OnGrantWebNotificationPermission(const GURL& origin,
                                         bool permission_granted);
   void OnClearWebNotificationPermissions();
-  void OnSimulateWebNotificationClick(const std::string& title,
-                                      int action_index,
-                                      const base::NullableString16& reply);
+  void OnSimulateWebNotificationClick(
+      const std::string& title,
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply);
   void OnSimulateWebNotificationClose(const std::string& title, bool by_user);
   void OnSetPushMessagingPermission(const GURL& origin, bool allowed);
   void OnClearPushMessagingPermissions();
diff --git a/content/shell/common/layout_test/layout_test_messages.h b/content/shell/common/layout_test/layout_test_messages.h
index 6936917..73360ddd 100644
--- a/content/shell/common/layout_test/layout_test_messages.h
+++ b/content/shell/common/layout_test/layout_test_messages.h
@@ -6,6 +6,8 @@
 #include <string>
 #include <vector>
 
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/public/common/common_param_traits_macros.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_platform_file.h"
@@ -26,8 +28,8 @@
                     int /* quota */)
 IPC_MESSAGE_ROUTED3(LayoutTestHostMsg_SimulateWebNotificationClick,
                     std::string /* title */,
-                    int /* action_index */,
-                    base::NullableString16 /* reply */)
+                    base::Optional<int> /* action_index */,
+                    base::Optional<base::string16> /* reply */)
 IPC_MESSAGE_ROUTED2(LayoutTestHostMsg_SimulateWebNotificationClose,
                     std::string /* title */,
                     bool /* by_user */)
diff --git a/content/shell/renderer/layout_test/blink_test_runner.cc b/content/shell/renderer/layout_test/blink_test_runner.cc
index ef408dd..95cd5fd 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.cc
+++ b/content/shell/renderer/layout_test/blink_test_runner.cc
@@ -462,8 +462,8 @@
 
 void BlinkTestRunner::SimulateWebNotificationClick(
     const std::string& title,
-    int action_index,
-    const base::NullableString16& reply) {
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply) {
   Send(new LayoutTestHostMsg_SimulateWebNotificationClick(routing_id(), title,
                                                           action_index, reply));
 }
diff --git a/content/shell/renderer/layout_test/blink_test_runner.h b/content/shell/renderer/layout_test/blink_test_runner.h
index 2dee80e..d9ceec16 100644
--- a/content/shell/renderer/layout_test/blink_test_runner.h
+++ b/content/shell/renderer/layout_test/blink_test_runner.h
@@ -12,6 +12,8 @@
 #include "base/containers/circular_deque.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/public/common/page_state.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/renderer/render_view_observer_tracker.h"
@@ -98,8 +100,8 @@
   void SetDatabaseQuota(int quota) override;
   void SimulateWebNotificationClick(
       const std::string& title,
-      int action_index,
-      const base::NullableString16& reply) override;
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply) override;
   void SimulateWebNotificationClose(const std::string& title,
                                     bool by_user) override;
   void SetDeviceScaleFactor(float factor) override;
diff --git a/content/shell/test_runner/test_runner.cc b/content/shell/test_runner/test_runner.cc
index f65f947..3ba6e00 100644
--- a/content/shell/test_runner/test_runner.cc
+++ b/content/shell/test_runner/test_runner.cc
@@ -253,10 +253,7 @@
   void SetWindowIsKey(bool value);
   void SetXSSAuditorEnabled(bool enabled);
   void ShowWebInspector(gin::Arguments* args);
-  void SimulateWebNotificationClick(const std::string& title, int action_index);
-  void SimulateWebNotificationClickWithReply(const std::string& title,
-                                             int action_index,
-                                             const std::string& reply);
+  void SimulateWebNotificationClick(gin::Arguments* args);
   void SimulateWebNotificationClose(const std::string& title, bool by_user);
   void UseUnfortunateSynchronousResizeMode();
   void WaitForPolicyDelegate();
@@ -609,8 +606,6 @@
       .SetMethod("showWebInspector", &TestRunnerBindings::ShowWebInspector)
       .SetMethod("simulateWebNotificationClick",
                  &TestRunnerBindings::SimulateWebNotificationClick)
-      .SetMethod("simulateWebNotificationClickWithReply",
-                 &TestRunnerBindings::SimulateWebNotificationClickWithReply)
       .SetMethod("simulateWebNotificationClose",
                  &TestRunnerBindings::SimulateWebNotificationClose)
       .SetProperty("tooltipText", &TestRunnerBindings::TooltipText)
@@ -1377,23 +1372,34 @@
   }
 }
 
-void TestRunnerBindings::SimulateWebNotificationClick(const std::string& title,
-                                                      int action_index) {
+void TestRunnerBindings::SimulateWebNotificationClick(gin::Arguments* args) {
+  DCHECK_GE(args->Length(), 1);
   if (!runner_)
     return;
-  runner_->SimulateWebNotificationClick(title, action_index,
-                                        base::NullableString16());
-}
 
-void TestRunnerBindings::SimulateWebNotificationClickWithReply(
-    const std::string& title,
-    int action_index,
-    const std::string& reply) {
-  if (!runner_)
-    return;
-  runner_->SimulateWebNotificationClick(
-      title, action_index,
-      base::NullableString16(base::UTF8ToUTF16(reply), false /* is_null */));
+  std::string title;
+  base::Optional<int> action_index;
+  base::Optional<base::string16> reply;
+
+  args->GetNext(&title);
+
+  // Optional |action_index| argument.
+  if (args->Length() >= 2) {
+    int action_index_int;
+    args->GetNext(&action_index_int);
+
+    action_index = action_index_int;
+  }
+
+  // Optional |reply| argument.
+  if (args->Length() >= 3) {
+    std::string reply_string;
+    args->GetNext(&reply_string);
+
+    reply = base::UTF8ToUTF16(reply_string);
+  }
+
+  runner_->SimulateWebNotificationClick(title, action_index, reply);
 }
 
 void TestRunnerBindings::SimulateWebNotificationClose(const std::string& title,
@@ -2761,8 +2767,8 @@
 
 void TestRunner::SimulateWebNotificationClick(
     const std::string& title,
-    int action_index,
-    const base::NullableString16& reply) {
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply) {
   delegate_->SimulateWebNotificationClick(title, action_index, reply);
 }
 
diff --git a/content/shell/test_runner/test_runner.h b/content/shell/test_runner/test_runner.h
index e7fe912..44a65d2 100644
--- a/content/shell/test_runner/test_runner.h
+++ b/content/shell/test_runner/test_runner.h
@@ -15,6 +15,8 @@
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/shell/test_runner/layout_test_runtime_flags.h"
 #include "content/shell/test_runner/test_runner_export.h"
 #include "content/shell/test_runner/web_test_runner.h"
@@ -26,10 +28,6 @@
 class GURL;
 class SkBitmap;
 
-namespace base {
-class NullableString16;
-}
-
 namespace blink {
 class WebContentSettingsClient;
 class WebFrame;
@@ -532,9 +530,10 @@
   void SetMIDIAccessorResult(midi::mojom::Result result);
 
   // Simulates a click on a Web Notification.
-  void SimulateWebNotificationClick(const std::string& title,
-                                    int action_index,
-                                    const base::NullableString16& reply);
+  void SimulateWebNotificationClick(
+      const std::string& title,
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply);
 
   // Simulates closing a Web Notification.
   void SimulateWebNotificationClose(const std::string& title, bool by_user);
diff --git a/content/shell/test_runner/web_test_delegate.h b/content/shell/test_runner/web_test_delegate.h
index 871cab772..55697c8 100644
--- a/content/shell/test_runner/web_test_delegate.h
+++ b/content/shell/test_runner/web_test_delegate.h
@@ -11,6 +11,8 @@
 
 #include "base/callback_forward.h"
 #include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebURL.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
@@ -150,8 +152,8 @@
   // Controls Web Notifications.
   virtual void SimulateWebNotificationClick(
       const std::string& title,
-      int action_index,
-      const base::NullableString16& reply) = 0;
+      const base::Optional<int>& action_index,
+      const base::Optional<base::string16>& reply) = 0;
   virtual void SimulateWebNotificationClose(const std::string& title,
                                             bool by_user) = 0;
 
diff --git a/content/test/mock_platform_notification_service.cc b/content/test/mock_platform_notification_service.cc
index e5c8304..be6cdaf 100644
--- a/content/test/mock_platform_notification_service.cc
+++ b/content/test/mock_platform_notification_service.cc
@@ -95,8 +95,8 @@
 
 void MockPlatformNotificationService::SimulateClick(
     const std::string& title,
-    int action_index,
-    const base::NullableString16& reply) {
+    const base::Optional<int>& action_index,
+    const base::Optional<base::string16>& reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   const auto notification_id_iter = notification_id_map_.find(title);
   if (notification_id_iter == notification_id_map_.end())
@@ -116,8 +116,9 @@
         notification.browser_context, notification_id, notification.origin,
         action_index, reply, base::Bind(&OnEventDispatchComplete));
   } else if (non_persistent_iter != non_persistent_notifications_.end()) {
-    DCHECK_EQ(action_index, -1) << "Action buttons are only supported for "
-                                   "persistent notifications";
+    DCHECK(!action_index.has_value())
+        << "Action buttons are only supported for "
+           "persistent notifications";
     NotificationEventDispatcher::GetInstance()->DispatchNonPersistentClickEvent(
         notification_id);
   }
diff --git a/content/test/mock_platform_notification_service.h b/content/test/mock_platform_notification_service.h
index 076d016..466166b 100644
--- a/content/test/mock_platform_notification_service.h
+++ b/content/test/mock_platform_notification_service.h
@@ -13,14 +13,12 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/strings/string16.h"
 #include "content/public/browser/platform_notification_service.h"
 #include "third_party/WebKit/public/platform/modules/permissions/permission_status.mojom.h"
 #include "url/gurl.h"
 
-namespace base {
-  class NullableString16;
-}
-
 namespace content {
 
 struct NotificationResources;
@@ -34,12 +32,11 @@
   ~MockPlatformNotificationService() override;
 
   // Simulates a click on the notification titled |title|. |action_index|
-  // indicates which action was clicked, or -1 if the main notification body was
-  // clicked. |reply| indicates the user reply, if any.
+  // indicates which action was clicked. |reply| indicates the user reply.
   // Must be called on the UI thread.
   void SimulateClick(const std::string& title,
-                     int action_index,
-                     const base::NullableString16& reply);
+                     const base::Optional<int>& action_index,
+                     const base::Optional<base::string16>& reply);
 
   // Simulates the closing a notification titled |title|. Must be called on
   // the UI thread.
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index c19d608..23a374a4 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -191,7 +191,7 @@
 std::unique_ptr<blink::WebURLLoader>
 TestBlinkWebUnitTestSupport::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   // This loader should be used only for process-local resources such as
   // data URLs.
   auto default_loader =
diff --git a/content/test/test_blink_web_unit_test_support.h b/content/test/test_blink_web_unit_test_support.h
index 556242d76..93df7c8c 100644
--- a/content/test/test_blink_web_unit_test_support.h
+++ b/content/test/test_blink_web_unit_test_support.h
@@ -43,7 +43,7 @@
 
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
   blink::WebString UserAgent() override;
   blink::WebString QueryLocalizedString(
       blink::WebLocalizedString::Name name) override;
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 5490e1e..d9005b19 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -127,7 +127,7 @@
 
 std::unique_ptr<blink::WebURLLoader> TestRenderFrame::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   return base::MakeUnique<WebURLLoaderImpl>(
       nullptr, base::ThreadTaskRunnerHandle::Get(), nullptr);
 }
diff --git a/content/test/test_render_frame.h b/content/test/test_render_frame.h
index cc888aa..2391218 100644
--- a/content/test/test_render_frame.h
+++ b/content/test/test_render_frame.h
@@ -56,7 +56,7 @@
 
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) override;
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) override;
 
   mojom::FrameHostAssociatedPtr GetFrameHost() override;
 
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 7b1974f..69f1f87 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -1425,16 +1425,20 @@
 }
 
 - (void)showReportAnIssue {
-  if (_settingsNavigationController)
-    return;
-  _settingsNavigationController =
-      [SettingsNavigationController newUserFeedbackController:_mainBrowserState
-                                                     delegate:self
-                                           feedbackDataSource:self];
-  [[self topPresentedViewController]
-      presentViewController:_settingsNavigationController
-                   animated:YES
-                 completion:nil];
+  // This dispatch is necessary to give enough time for the tools menu to
+  // disappear before taking a screenshot.
+  dispatch_async(dispatch_get_main_queue(), ^{
+    if (_settingsNavigationController)
+      return;
+    _settingsNavigationController = [SettingsNavigationController
+        newUserFeedbackController:_mainBrowserState
+                         delegate:self
+               feedbackDataSource:self];
+    [[self topPresentedViewController]
+        presentViewController:_settingsNavigationController
+                     animated:YES
+                   completion:nil];
+  });
 }
 
 - (void)openURL:(OpenUrlCommand*)command {
@@ -1454,6 +1458,18 @@
   }
 }
 
+- (void)showSignin:(ShowSigninCommand*)command {
+  if (command.operation == AUTHENTICATION_OPERATION_DISMISS) {
+    [self dismissSigninInteractionController];
+  } else {
+    [self showSigninWithOperation:command.operation
+                         identity:command.identity
+                      accessPoint:command.accessPoint
+                      promoAction:command.promoAction
+                         callback:command.callback];
+  }
+}
+
 #pragma mark - ApplicationSettingsCommands
 
 - (void)showAccountsSettings {
@@ -1509,20 +1525,6 @@
   NSInteger command = [sender tag];
 
   switch (command) {
-    case IDC_SHOW_SIGNIN_IOS: {
-      ShowSigninCommand* command =
-          base::mac::ObjCCastStrict<ShowSigninCommand>(sender);
-      if (command.operation == AUTHENTICATION_OPERATION_DISMISS) {
-        [self dismissSigninInteractionController];
-      } else {
-        [self showSigninWithOperation:command.operation
-                             identity:command.identity
-                          accessPoint:command.accessPoint
-                          promoAction:command.promoAction
-                             callback:command.callback];
-      }
-      break;
-    }
     case IDC_SHOW_MAIL_COMPOSER:
       [self.currentBVC chromeExecuteCommand:sender];
       break;
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index e5c6f2d..7705683 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -800,6 +800,9 @@
       <message name="IDS_IOS_OPTIONS_ACCOUNTS_GOOGLE_TITLE" desc="Title of the Google Activity Controls button on the accounts settings screen [Length: 50em]">
         Google Activity Controls
       </message>
+      <message name="IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR" desc="Text informing the user that sync isn't working properly [iOS only] [60em]">
+        Sync isn't working. Tap to fix.
+      </message>
       <message name="IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF" desc="Text informing the user that sync is off [iOS only] [60em]">
         Off
       </message>
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 2eb4da2..011b747 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -28,14 +28,6 @@
     "validation_rules_storage_factory.h",
   ]
   deps = [
-    "resources:autofill_card_american_express",
-    "resources:autofill_card_diners",
-    "resources:autofill_card_discover",
-    "resources:autofill_card_generic",
-    "resources:autofill_card_jcb",
-    "resources:autofill_card_mastercard",
-    "resources:autofill_card_unionpay",
-    "resources:autofill_card_visa",
     "resources:autofill_close",
     "resources:autofill_close_pressed",
     "resources:autofill_keyboard_background",
diff --git a/ios/chrome/browser/autofill/form_suggestion_label.mm b/ios/chrome/browser/autofill/form_suggestion_label.mm
index 490becb3..aae0c37 100644
--- a/ios/chrome/browser/autofill/form_suggestion_label.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_label.mm
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
+#include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/credit_card.h"
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "ios/chrome/browser/autofill/form_suggestion_view_client.h"
@@ -53,18 +54,6 @@
   NSString* image_name;
 };
 
-const IconImageMap kCreditCardIconImageMap[] = {
-    {autofill::kAmericanExpressCard, @"autofill_card_american_express"},
-    {autofill::kDiscoverCard, @"autofill_card_discover"},
-    {autofill::kMasterCard, @"autofill_card_mastercard"},
-    {autofill::kMirCard, @"autofill_card_mir"},
-    {autofill::kVisaCard, @"autofill_card_visa"},
-    {autofill::kDinersCard, @"autofill_card_diners"},
-    {autofill::kGenericCard, @"autofill_card_generic"},
-    {autofill::kJCBCard, @"autofill_card_jcb"},
-    {autofill::kUnionPay, @"autofill_card_unionpay"},
-};
-
 // Creates a label with the given |text| and |alpha| suitable for use in a
 // suggestion button in the keyboard accessory view.
 UILabel* TextLabel(NSString* text, CGFloat alpha, BOOL bold) {
@@ -82,12 +71,6 @@
 
 }  // namespace
 
-@interface FormSuggestionLabel ()
-
-// Returns the name of the image for credit card icon.
-+ (NSString*)imageNameForCreditCardIcon:(NSString*)icon;
-@end
-
 @implementation FormSuggestionLabel {
   // Client of this view.
   __weak id<FormSuggestionViewClient> client_;
@@ -109,22 +92,17 @@
     const CGFloat frameHeight = CGRectGetHeight(proposedFrame);
     CGFloat currentX = kBorderWidth;
 
-    // [UIImage imageNamed:] writes error message if nil is passed. Prevent
-    // console spam by checking the name first.
-    NSString* iconImageName =
-        [FormSuggestionLabel imageNameForCreditCardIcon:suggestion.icon];
-    UIImage* iconImage = nil;
-    if (iconImageName)
-      iconImage = [UIImage imageNamed:iconImageName];
-    if (iconImage) {
-      UIImageView* iconView = [[UIImageView alloc] initWithImage:iconImage];
-      const CGFloat iconY =
-          std::floor((frameHeight - iconImage.size.height) / 2.0f);
-      iconView.frame = CGRectMake(currentX, iconY, iconImage.size.width,
-                                  iconImage.size.height);
-      [self addSubview:iconView];
-      currentX += CGRectGetWidth(iconView.frame) + kSpacing;
-    }
+    const int iconImageID = autofill::data_util::GetPaymentRequestData(
+                                base::SysNSStringToUTF8(suggestion.icon))
+                                .icon_resource_id;
+    UIImage* iconImage = NativeImage(iconImageID);
+    UIImageView* iconView = [[UIImageView alloc] initWithImage:iconImage];
+    const CGFloat iconY =
+        std::floor((frameHeight - iconImage.size.height) / 2.0f);
+    iconView.frame = CGRectMake(currentX, iconY, iconImage.size.width,
+                                iconImage.size.height);
+    [self addSubview:iconView];
+    currentX += CGRectGetWidth(iconView.frame) + kSpacing;
 
     UILabel* label = TextLabel(suggestion.value, kMainLabelAlpha, YES);
     const CGFloat labelY =
@@ -190,20 +168,4 @@
   [client_ didSelectSuggestion:suggestion_];
 }
 
-#pragma mark -
-#pragma mark Private
-
-+ (NSString*)imageNameForCreditCardIcon:(NSString*)icon {
-  if (!icon || [icon length] == 0) {
-    return nil;
-  }
-  std::string iconName(base::SysNSStringToUTF8(icon));
-  for (size_t i = 0; i < arraysize(kCreditCardIconImageMap); ++i) {
-    if (iconName.compare(kCreditCardIconImageMap[i].icon_name) == 0) {
-      return kCreditCardIconImageMap[i].image_name;
-    }
-  }
-  return nil;
-}
-
 @end
diff --git a/ios/chrome/browser/autofill/resources/BUILD.gn b/ios/chrome/browser/autofill/resources/BUILD.gn
index ace0eff..7651f0cf 100644
--- a/ios/chrome/browser/autofill/resources/BUILD.gn
+++ b/ios/chrome/browser/autofill/resources/BUILD.gn
@@ -4,94 +4,6 @@
 
 import("//build/config/ios/imageset.gni")
 
-imageset("autofill_card_american_express") {
-  sources = [
-    "autofill_card_american_express.imageset/Contents.json",
-    "autofill_card_american_express.imageset/autofill_card_american_express.png",
-    "autofill_card_american_express.imageset/autofill_card_american_express@2x.png",
-    "autofill_card_american_express.imageset/autofill_card_american_express@2x~ipad.png",
-    "autofill_card_american_express.imageset/autofill_card_american_express@3x.png",
-    "autofill_card_american_express.imageset/autofill_card_american_express~ipad.png",
-  ]
-}
-
-imageset("autofill_card_diners") {
-  sources = [
-    "autofill_card_diners.imageset/Contents.json",
-    "autofill_card_diners.imageset/autofill_card_diners.png",
-    "autofill_card_diners.imageset/autofill_card_diners@2x.png",
-    "autofill_card_diners.imageset/autofill_card_diners@2x~ipad.png",
-    "autofill_card_diners.imageset/autofill_card_diners@3x.png",
-    "autofill_card_diners.imageset/autofill_card_diners~ipad.png",
-  ]
-}
-
-imageset("autofill_card_discover") {
-  sources = [
-    "autofill_card_discover.imageset/Contents.json",
-    "autofill_card_discover.imageset/autofill_card_discover.png",
-    "autofill_card_discover.imageset/autofill_card_discover@2x.png",
-    "autofill_card_discover.imageset/autofill_card_discover@2x~ipad.png",
-    "autofill_card_discover.imageset/autofill_card_discover@3x.png",
-    "autofill_card_discover.imageset/autofill_card_discover~ipad.png",
-  ]
-}
-
-imageset("autofill_card_generic") {
-  sources = [
-    "autofill_card_generic.imageset/Contents.json",
-    "autofill_card_generic.imageset/autofill_card_generic.png",
-    "autofill_card_generic.imageset/autofill_card_generic@2x.png",
-    "autofill_card_generic.imageset/autofill_card_generic@2x~ipad.png",
-    "autofill_card_generic.imageset/autofill_card_generic@3x.png",
-    "autofill_card_generic.imageset/autofill_card_generic~ipad.png",
-  ]
-}
-
-imageset("autofill_card_jcb") {
-  sources = [
-    "autofill_card_jcb.imageset/Contents.json",
-    "autofill_card_jcb.imageset/autofill_card_jcb.png",
-    "autofill_card_jcb.imageset/autofill_card_jcb@2x.png",
-    "autofill_card_jcb.imageset/autofill_card_jcb@2x~ipad.png",
-    "autofill_card_jcb.imageset/autofill_card_jcb@3x.png",
-    "autofill_card_jcb.imageset/autofill_card_jcb~ipad.png",
-  ]
-}
-
-imageset("autofill_card_mastercard") {
-  sources = [
-    "autofill_card_mastercard.imageset/Contents.json",
-    "autofill_card_mastercard.imageset/autofill_card_mastercard.png",
-    "autofill_card_mastercard.imageset/autofill_card_mastercard@2x.png",
-    "autofill_card_mastercard.imageset/autofill_card_mastercard@2x~ipad.png",
-    "autofill_card_mastercard.imageset/autofill_card_mastercard@3x.png",
-    "autofill_card_mastercard.imageset/autofill_card_mastercard~ipad.png",
-  ]
-}
-
-imageset("autofill_card_unionpay") {
-  sources = [
-    "autofill_card_unionpay.imageset/Contents.json",
-    "autofill_card_unionpay.imageset/autofill_card_unionpay.png",
-    "autofill_card_unionpay.imageset/autofill_card_unionpay@2x.png",
-    "autofill_card_unionpay.imageset/autofill_card_unionpay@2x~ipad.png",
-    "autofill_card_unionpay.imageset/autofill_card_unionpay@3x.png",
-    "autofill_card_unionpay.imageset/autofill_card_unionpay~ipad.png",
-  ]
-}
-
-imageset("autofill_card_visa") {
-  sources = [
-    "autofill_card_visa.imageset/Contents.json",
-    "autofill_card_visa.imageset/autofill_card_visa.png",
-    "autofill_card_visa.imageset/autofill_card_visa@2x.png",
-    "autofill_card_visa.imageset/autofill_card_visa@2x~ipad.png",
-    "autofill_card_visa.imageset/autofill_card_visa@3x.png",
-    "autofill_card_visa.imageset/autofill_card_visa~ipad.png",
-  ]
-}
-
 imageset("autofill_close") {
   sources = [
     "autofill_close.imageset/Contents.json",
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/Contents.json
deleted file mode 100644
index 0c5a0cd0..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_american_express.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_american_express@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_american_express@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_american_express@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_american_express~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express.png b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express.png
deleted file mode 100644
index 8278131..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x.png
deleted file mode 100644
index 265c359..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x~ipad.png
deleted file mode 100644
index e05aa9a2..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@3x.png
deleted file mode 100644
index beac46e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express~ipad.png
deleted file mode 100644
index 3d8babd4..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_american_express.imageset/autofill_card_american_express~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/Contents.json
deleted file mode 100644
index 9bc9b67..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_diners.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_diners@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_diners@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_diners@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_diners~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners.png b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners.png
deleted file mode 100644
index 0e6d38b..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x.png
deleted file mode 100644
index e21d3d9..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x~ipad.png
deleted file mode 100644
index ae7033fa5..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@3x.png
deleted file mode 100644
index 656e76ad..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners~ipad.png
deleted file mode 100644
index e0e607e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_diners.imageset/autofill_card_diners~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/Contents.json
deleted file mode 100644
index 76a0e979..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_discover.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_discover@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_discover@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_discover@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_discover~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover.png b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover.png
deleted file mode 100644
index df7d5d90..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x.png
deleted file mode 100644
index 5bd7e21..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x~ipad.png
deleted file mode 100644
index 53588e1..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@3x.png
deleted file mode 100644
index 096cc1e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover~ipad.png
deleted file mode 100644
index 43820c3..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_discover.imageset/autofill_card_discover~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/Contents.json
deleted file mode 100644
index 496f7ce..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_generic.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_generic@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_generic@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_generic@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_generic~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic.png b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic.png
deleted file mode 100644
index e6e1a2e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x.png
deleted file mode 100644
index d38ff3d..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x~ipad.png
deleted file mode 100644
index dedbf6f..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@3x.png
deleted file mode 100644
index 018f0d1..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic~ipad.png
deleted file mode 100644
index 612e78c5..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_generic.imageset/autofill_card_generic~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/Contents.json
deleted file mode 100644
index 545eb0e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_jcb.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_jcb@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_jcb@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_jcb@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_jcb~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb.png b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb.png
deleted file mode 100644
index 6109fa37..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x.png
deleted file mode 100644
index 663a0207..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x~ipad.png
deleted file mode 100644
index bdbc7a2c6..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@3x.png
deleted file mode 100644
index a1aad617..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb~ipad.png
deleted file mode 100644
index f5c4c02..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_jcb.imageset/autofill_card_jcb~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/Contents.json
deleted file mode 100644
index 4003df3..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_mastercard.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_mastercard@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_mastercard@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_mastercard@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_mastercard~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard.png b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard.png
deleted file mode 100644
index c39ceb4..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x.png
deleted file mode 100644
index 4a8ca13..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x~ipad.png
deleted file mode 100644
index fa859b3..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@3x.png
deleted file mode 100644
index 3b9d9d21..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard~ipad.png
deleted file mode 100644
index 09c274bd..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_mastercard.imageset/autofill_card_mastercard~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/Contents.json
deleted file mode 100644
index 488111b5..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_unionpay.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_unionpay@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_unionpay@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_unionpay@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_unionpay~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay.png b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay.png
deleted file mode 100644
index e88df40..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x.png
deleted file mode 100644
index cda7f25..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x~ipad.png
deleted file mode 100644
index ee3bd30..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@3x.png
deleted file mode 100644
index 2c0e508..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay~ipad.png
deleted file mode 100644
index 31e79ac..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_unionpay.imageset/autofill_card_unionpay~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/Contents.json b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/Contents.json
deleted file mode 100644
index 1cfc085..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/Contents.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "iphone",
-            "scale": "1x",
-            "filename": "autofill_card_visa.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "2x",
-            "filename": "autofill_card_visa@2x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "2x",
-            "filename": "autofill_card_visa@2x~ipad.png"
-        },
-        {
-            "idiom": "iphone",
-            "scale": "3x",
-            "filename": "autofill_card_visa@3x.png"
-        },
-        {
-            "idiom": "ipad",
-            "scale": "1x",
-            "filename": "autofill_card_visa~ipad.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa.png b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa.png
deleted file mode 100644
index 42b21e98..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x.png b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x.png
deleted file mode 100644
index 01df838..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x~ipad.png
deleted file mode 100644
index 506e145e..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@2x~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@3x.png b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@3x.png
deleted file mode 100644
index 12a5fc98..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa~ipad.png b/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa~ipad.png
deleted file mode 100644
index 10a3fb4..0000000
--- a/ios/chrome/browser/autofill/resources/autofill_card_visa.imageset/autofill_card_visa~ipad.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/passwords/credential_manager.h b/ios/chrome/browser/passwords/credential_manager.h
index 64dd23e..29c921b 100644
--- a/ios/chrome/browser/passwords/credential_manager.h
+++ b/ios/chrome/browser/passwords/credential_manager.h
@@ -11,8 +11,6 @@
 class WebState;
 }
 
-namespace credential_manager {
-
 // Owned by PasswordController. It is responsible for registering and handling
 // callbacks for JS methods |navigator.credentials.*|.
 // TODO(crbug.com/435047): Implement JSCredentialManager responsible for
@@ -56,6 +54,4 @@
   DISALLOW_COPY_AND_ASSIGN(CredentialManager);
 };
 
-}  // namespace credential_manager
-
 #endif  // IOS_CHROME_BROWSER_PASSWORDS_CREDENTIAL_MANAGER_H_
diff --git a/ios/chrome/browser/passwords/credential_manager.mm b/ios/chrome/browser/passwords/credential_manager.mm
index ea6baa9..dd17df7 100644
--- a/ios/chrome/browser/passwords/credential_manager.mm
+++ b/ios/chrome/browser/passwords/credential_manager.mm
@@ -19,8 +19,6 @@
 using password_manager::CredentialType;
 using password_manager::CredentialMediationRequirement;
 
-namespace credential_manager {
-
 namespace {
 
 // Script command prefix for CM API calls. Possible commands to be sent from
@@ -58,7 +56,7 @@
   int promise_id = static_cast<int>(promise_id_double);
 
   if (!WebStateContentIsSecureHtml(web_state_)) {
-    RejectPromiseWithInvalidStateError(
+    RejectCredentialPromiseWithInvalidStateError(
         web_state_, promise_id,
         base::ASCIIToUTF16(
             "Credential Manager API called from insecure context"));
@@ -74,7 +72,7 @@
   if (command == "credentials.get") {
     CredentialMediationRequirement mediation;
     if (!ParseMediationRequirement(json, &mediation)) {
-      RejectPromiseWithTypeError(
+      RejectCredentialPromiseWithTypeError(
           web_state_, promise_id,
           base::ASCIIToUTF16(
               "CredentialRequestOptions: Invalid 'mediation' value."));
@@ -82,7 +80,7 @@
     }
     bool include_passwords;
     if (!ParseIncludePasswords(json, &include_passwords)) {
-      RejectPromiseWithTypeError(
+      RejectCredentialPromiseWithTypeError(
           web_state_, promise_id,
           base::ASCIIToUTF16(
               "CredentialRequestOptions: Invalid 'password' value."));
@@ -90,7 +88,7 @@
     }
     std::vector<GURL> federations;
     if (!ParseFederations(json, &federations)) {
-      RejectPromiseWithTypeError(
+      RejectCredentialPromiseWithTypeError(
           web_state_, promise_id,
           base::ASCIIToUTF16(
               "CredentialRequestOptions: invalid 'providers' value."));
@@ -106,7 +104,7 @@
     if (!ParseCredentialDictionary(json, &credential)) {
       // TODO(crbug.com/435047): Refactor ParseCredentialDictionary method to
       // provide more meaningful error message.
-      RejectPromiseWithTypeError(
+      RejectCredentialPromiseWithTypeError(
           web_state_, promise_id,
           base::ASCIIToUTF16("Invalid Credential object."));
       return false;
@@ -131,36 +129,34 @@
     const base::Optional<CredentialInfo>& info) {
   switch (error) {
     case CredentialManagerError::SUCCESS:
-      ResolvePromiseWithCredentialInfo(web_state_, promise_id, info);
+      ResolveCredentialPromiseWithCredentialInfo(web_state_, promise_id, info);
       break;
     case CredentialManagerError::DISABLED:
-      RejectPromiseWithInvalidStateError(
+      RejectCredentialPromiseWithInvalidStateError(
           web_state_, promise_id,
           base::ASCIIToUTF16("Credential Manager is disabled."));
       break;
     case CredentialManagerError::PENDINGREQUEST:
-      RejectPromiseWithInvalidStateError(
+      RejectCredentialPromiseWithInvalidStateError(
           web_state_, promise_id,
           base::ASCIIToUTF16("Pending 'get()' request."));
       break;
     case CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
-      RejectPromiseWithNotSupportedError(
+      RejectCredentialPromiseWithNotSupportedError(
           web_state_, promise_id,
           base::ASCIIToUTF16("Password store is unavailable."));
       break;
     case CredentialManagerError::UNKNOWN:
-      RejectPromiseWithNotSupportedError(
+      RejectCredentialPromiseWithNotSupportedError(
           web_state_, promise_id,
           base::ASCIIToUTF16("Unknown error has occurred."));
   }
 }
 
 void CredentialManager::SendPreventSilentAccessResponse(int promise_id) {
-  ResolvePromiseWithUndefined(web_state_, promise_id);
+  ResolveCredentialPromiseWithUndefined(web_state_, promise_id);
 }
 
 void CredentialManager::SendStoreResponse(int promise_id) {
-  ResolvePromiseWithUndefined(web_state_, promise_id);
+  ResolveCredentialPromiseWithUndefined(web_state_, promise_id);
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/credential_manager_features.cc b/ios/chrome/browser/passwords/credential_manager_features.cc
index 8c842392..a5f6784 100644
--- a/ios/chrome/browser/passwords/credential_manager_features.cc
+++ b/ios/chrome/browser/passwords/credential_manager_features.cc
@@ -4,13 +4,9 @@
 
 #include "ios/chrome/browser/passwords/credential_manager_features.h"
 
-namespace credential_manager {
-
 namespace features {
 
 const base::Feature kCredentialManager{"CredentialManager",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 }  // namespace features
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/credential_manager_features.h b/ios/chrome/browser/passwords/credential_manager_features.h
index a0dd300..d640a6df 100644
--- a/ios/chrome/browser/passwords/credential_manager_features.h
+++ b/ios/chrome/browser/passwords/credential_manager_features.h
@@ -7,8 +7,6 @@
 
 #include "base/feature_list.h"
 
-namespace credential_manager {
-
 namespace features {
 
 // Used to control the state of the Credential Manager API feature.
@@ -16,6 +14,4 @@
 
 }  // namespace features
 
-}  // namespace credential_manager
-
 #endif  // IOS_CHROME_BROWSER_PASSWORDS_CREDENTIAL_MANAGER_FEATURES_H_
diff --git a/ios/chrome/browser/passwords/credential_manager_unittest.mm b/ios/chrome/browser/passwords/credential_manager_unittest.mm
index b8022a73..24557d2 100644
--- a/ios/chrome/browser/passwords/credential_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/credential_manager_unittest.mm
@@ -37,8 +37,6 @@
 using testing::_;
 using url::Origin;
 
-namespace credential_manager {
-
 namespace {
 
 // Test hostname for cert verification.
@@ -798,5 +796,3 @@
   // return false.
   EXPECT_FALSE(WebStateContentIsSecureHtml(web_state()));
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/credential_manager_util.h b/ios/chrome/browser/passwords/credential_manager_util.h
index deb372a..c0b36241 100644
--- a/ios/chrome/browser/passwords/credential_manager_util.h
+++ b/ios/chrome/browser/passwords/credential_manager_util.h
@@ -12,8 +12,6 @@
 class WebState;
 }
 
-namespace credential_manager {
-
 // Keys for obtaining common Credential's fields from DictionaryValue
 // representing the Credential. Keys below correspond to JavaScript
 // Credential object fields as follows:
@@ -90,6 +88,4 @@
 // ignore API calls from insecure context.
 bool WebStateContentIsSecureHtml(const web::WebState* web_state);
 
-}  // namespace credential_manager
-
 #endif  // IOS_CHROME_BROWSER_PASSWORDS_CREDENTIAL_MANAGER_UTIL_H_
diff --git a/ios/chrome/browser/passwords/credential_manager_util.mm b/ios/chrome/browser/passwords/credential_manager_util.mm
index 32f283c..8d3d527 100644
--- a/ios/chrome/browser/passwords/credential_manager_util.mm
+++ b/ios/chrome/browser/passwords/credential_manager_util.mm
@@ -20,8 +20,6 @@
 // make sure there are no payments dependencies.
 using payments::OriginSecurityChecker;
 
-namespace credential_manager {
-
 namespace {
 
 security_state::SecurityLevel GetSecurityLevelForWebState(
@@ -206,5 +204,3 @@
       GetSecurityLevelForWebState(web_state);
   return OriginSecurityChecker::IsSSLCertificateValid(security_level);
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/credential_manager_util_unittest.cc b/ios/chrome/browser/passwords/credential_manager_util_unittest.cc
index 8d9b899..99bc9e11 100644
--- a/ios/chrome/browser/passwords/credential_manager_util_unittest.cc
+++ b/ios/chrome/browser/passwords/credential_manager_util_unittest.cc
@@ -16,8 +16,6 @@
 using password_manager::CredentialMediationRequirement;
 using password_manager::CredentialType;
 
-namespace credential_manager {
-
 namespace {
 
 constexpr char kTestWebOrigin[] = "https://example.com/";
@@ -241,5 +239,3 @@
   json.SetString(kCredentialRequestProvidersKey, kTestWebOrigin);
   EXPECT_FALSE(ParseFederations(json, &federations));
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/js_credential_manager.h b/ios/chrome/browser/passwords/js_credential_manager.h
index 5d2db8b..56c07b5 100644
--- a/ios/chrome/browser/passwords/js_credential_manager.h
+++ b/ios/chrome/browser/passwords/js_credential_manager.h
@@ -12,12 +12,10 @@
 class WebState;
 }
 
-namespace credential_manager {
-
 // Resolves the Promise identified by |promise_id| with either Credential or
 // undefined. |promise_id| is unique number of a pending promise resolver stored
 // in |__gCrWeb.credentialManager|.
-void ResolvePromiseWithCredentialInfo(
+void ResolveCredentialPromiseWithCredentialInfo(
     web::WebState* web_state,
     int promise_id,
     const base::Optional<password_manager::CredentialInfo>& info);
@@ -25,32 +23,33 @@
 // Resolves the Promise identified by |promise_id| with undefined. |promise_id|
 // is unique number of a pending promise resolver stored in
 // |__gCrWeb.credentialManager|.
-void ResolvePromiseWithUndefined(web::WebState* web_state, int promise_id);
+void ResolveCredentialPromiseWithUndefined(web::WebState* web_state,
+                                           int promise_id);
 
 // Rejects the Promise identified by |promise_id| with TypeError. This may be a
 // result of failed parsing of arguments passed to exposed API method.
 // |promise_id| is unique number of a pending promise rejecter stored in
 // |__gCrWeb.credentialManager|.
-void RejectPromiseWithTypeError(web::WebState* web_state,
-                                int promise_id,
-                                const base::StringPiece16& message);
+void RejectCredentialPromiseWithTypeError(web::WebState* web_state,
+                                          int promise_id,
+                                          const base::StringPiece16& message);
 
 // Rejects the Promise identified by |promise_id| with InvalidStateError. This
 // should happen when credential manager is disabled or there is a pending 'get'
 // request. |promise_id| is unique number of a pending promise rejecter stored
 // in |__gCrWeb.credentialManager|.
-void RejectPromiseWithInvalidStateError(web::WebState* web_state,
-                                        int promise_id,
-                                        const base::StringPiece16& message);
+void RejectCredentialPromiseWithInvalidStateError(
+    web::WebState* web_state,
+    int promise_id,
+    const base::StringPiece16& message);
 
 // Rejects the Promise identified by |promise_id| with NotSupportedError. This
 // should happen when password store is unavailable or an unknown error occurs.
 // |promise_id| is unique number of a pending promise rejecter stored in
 // |__gCrWeb.credentialManager|.
-void RejectPromiseWithNotSupportedError(web::WebState* web_state,
-                                        int promise_id,
-                                        const base::StringPiece16& message);
-
-}  // namespace credential_manager
+void RejectCredentialPromiseWithNotSupportedError(
+    web::WebState* web_state,
+    int promise_id,
+    const base::StringPiece16& message);
 
 #endif  // IOS_CHROME_BROWSER_PASSWORDS_JS_CREDENTIAL_MANAGER_H_
diff --git a/ios/chrome/browser/passwords/js_credential_manager.mm b/ios/chrome/browser/passwords/js_credential_manager.mm
index 1ff332f..0f33b2a 100644
--- a/ios/chrome/browser/passwords/js_credential_manager.mm
+++ b/ios/chrome/browser/passwords/js_credential_manager.mm
@@ -14,8 +14,6 @@
 #error "This file requires ARC support."
 #endif
 
-namespace credential_manager {
-
 namespace {
 
 // Takes CredentialInfo and returns string representing invocation of
@@ -59,7 +57,7 @@
 
 }  // namespace
 
-void ResolvePromiseWithCredentialInfo(
+void ResolveCredentialPromiseWithCredentialInfo(
     web::WebState* web_state,
     int promise_id,
     const base::Optional<password_manager::CredentialInfo>& info) {
@@ -71,15 +69,16 @@
                          credential_str);
 }
 
-void ResolvePromiseWithUndefined(web::WebState* web_state, int promise_id) {
+void ResolveCredentialPromiseWithUndefined(web::WebState* web_state,
+                                           int promise_id) {
   DCHECK(web_state);
   ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/true,
                          std::string());
 }
 
-void RejectPromiseWithTypeError(web::WebState* web_state,
-                                int promise_id,
-                                const base::StringPiece16& message) {
+void RejectCredentialPromiseWithTypeError(web::WebState* web_state,
+                                          int promise_id,
+                                          const base::StringPiece16& message) {
   DCHECK(web_state);
   std::string type_error_str = base::StringPrintf(
       "new TypeError(%s)", base::GetQuotedJSONString(message).c_str());
@@ -87,9 +86,10 @@
                          type_error_str);
 }
 
-void RejectPromiseWithInvalidStateError(web::WebState* web_state,
-                                        int promise_id,
-                                        const base::StringPiece16& message) {
+void RejectCredentialPromiseWithInvalidStateError(
+    web::WebState* web_state,
+    int promise_id,
+    const base::StringPiece16& message) {
   DCHECK(web_state);
   std::string invalid_state_err_str = base::StringPrintf(
       "Object.create(DOMException.prototype, "
@@ -99,9 +99,10 @@
                          invalid_state_err_str);
 }
 
-void RejectPromiseWithNotSupportedError(web::WebState* web_state,
-                                        int promise_id,
-                                        const base::StringPiece16& message) {
+void RejectCredentialPromiseWithNotSupportedError(
+    web::WebState* web_state,
+    int promise_id,
+    const base::StringPiece16& message) {
   DCHECK(web_state);
   std::string not_supported_err_str = base::StringPrintf(
       "Object.create(DOMException.prototype, "
@@ -110,5 +111,3 @@
   ResolveOrRejectPromise(web_state, promise_id, /*resolve=*/false,
                          not_supported_err_str);
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/js_credential_manager_unittest.mm b/ios/chrome/browser/passwords/js_credential_manager_unittest.mm
index 64a9e1c..5cf5128 100644
--- a/ios/chrome/browser/passwords/js_credential_manager_unittest.mm
+++ b/ios/chrome/browser/passwords/js_credential_manager_unittest.mm
@@ -10,8 +10,6 @@
 #include "ios/web/public/test/web_test_with_web_state.h"
 #include "url/origin.h"
 
-namespace credential_manager {
-
 namespace {
 
 constexpr char kTestIconUrl[] = "https://www.google.com/favicon.ico";
@@ -19,10 +17,10 @@
 
 }  // namespace
 
-// Tests for js_credential_manager.mm file. Its functions RejectPromiseWith* and
-// ResolvePromiseWith* are tested as follows:
-// 1. |credential_manager| early script is injected to the page.
-// 2. A Promise is created. Depending on a test, it's |resolve| or |reject|
+// Tests for js_credential_manager.mm file. Its functions
+// RejectCredentialPromiseWith* and ResolveCredentialPromiseWith* are tested as
+// follows: 1. |credential_manager| early script is injected to the page. 2. A
+// Promise is created. Depending on a test, it's |resolve| or |reject|
 //   function is expected to be called. That function stores the result or error
 //   in variable(s) with test_* prefix.
 // 3. To check if JavaScript executed by JsCredentialManager was correct, we
@@ -42,8 +40,8 @@
   DISALLOW_COPY_AND_ASSIGN(JsCredentialManagerTest);
 };
 
-// Tests that ResolvePromiseWithCredentialInfo resolves the promise with
-// JavaScript PasswordCredential object containing correct values.
+// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
+// with JavaScript PasswordCredential object containing correct values.
 TEST_F(JsCredentialManagerTest, ResolveWithPasswordCredential) {
   // Let requestId be 3.
   ExecuteJavaScript(
@@ -57,7 +55,7 @@
   credential.name = base::ASCIIToUTF16("Test User");
   credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
   credential.password = base::ASCIIToUTF16("32njk \\4 s3cr3t \\n' 1");
-  ResolvePromiseWithCredentialInfo(web_state(), 3, credential);
+  ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, credential);
   // Wait for Promise to be resolved before checking the values.
   WaitForCondition(^{
     return static_cast<bool>(
@@ -72,8 +70,8 @@
               ExecuteJavaScript(@"test_credential_.password"));
 }
 
-// Tests that ResolvePromiseWithCredentialInfo resolves the promise with
-// JavaScript FederatedCredential object containing correct values.
+// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
+// with JavaScript FederatedCredential object containing correct values.
 TEST_F(JsCredentialManagerTest, ResolveWithFederatedCredential) {
   // Let requestId be 3.
   ExecuteJavaScript(
@@ -87,7 +85,7 @@
   credential.name = base::ASCIIToUTF16("Test User");
   credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
   credential.federation = url::Origin(GURL(kTestWebOrigin));
-  ResolvePromiseWithCredentialInfo(web_state(), 3, credential);
+  ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, credential);
   // Wait for Promise to be resolved before checking the values.
   WaitForCondition(^{
     return static_cast<bool>(
@@ -102,8 +100,8 @@
               ExecuteJavaScript(@"test_credential_.provider"));
 }
 
-// Tests that ResolvePromiseWithCredentialInfo resolves the promise with void
-// when optional CredentialInfo is null.
+// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
+// with void when optional CredentialInfo is null.
 TEST_F(JsCredentialManagerTest, ResolveWithNullCredential) {
   // Let requestId be 3.
   ExecuteJavaScript(
@@ -112,7 +110,7 @@
        "  test_result_ = (result == undefined);"
        "});");
   base::Optional<password_manager::CredentialInfo> null_credential;
-  ResolvePromiseWithCredentialInfo(web_state(), 3, null_credential);
+  ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, null_credential);
   // Wait for Promise to be resolved before checking the values.
   WaitForCondition(^{
     return static_cast<bool>(
@@ -121,7 +119,8 @@
   EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
 }
 
-// Tests that ResolvePromiseWithUndefined resolves the promise with no value.
+// Tests that ResolveCredentialPromiseWithUndefined resolves the promise with no
+// value.
 TEST_F(JsCredentialManagerTest, ResolveWithUndefined) {
   // Let requestId be equal 5.
   // Only when the promise is resolved with undefined, will the
@@ -131,7 +130,7 @@
        "then(function(result) {"
        "  test_result_ = (result == undefined);"
        "});");
-  ResolvePromiseWithUndefined(web_state(), 5);
+  ResolveCredentialPromiseWithUndefined(web_state(), 5);
   // Wait for Promise to be resolved before checking the values.
   WaitForCondition(^{
     return static_cast<bool>(
@@ -140,8 +139,8 @@
   EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
 }
 
-// Tests that RejectPromiseWithTypeError rejects the promise with TypeError and
-// correct message.
+// Tests that RejectCredentialPromiseWithTypeError rejects the promise with
+// TypeError and correct message.
 TEST_F(JsCredentialManagerTest, RejectWithTypeError) {
   // Let requestId be equal 100.
   ExecuteJavaScript(
@@ -150,7 +149,7 @@
        "  test_result_valid_type_ = (reason instanceof TypeError);"
        "  test_result_message_ = reason.message;"
        "});");
-  RejectPromiseWithTypeError(
+  RejectCredentialPromiseWithTypeError(
       web_state(), 100, base::ASCIIToUTF16("message with \"quotation\" marks"));
   // Wait for Promise to be rejected before checking the values.
   WaitForCondition(^{
@@ -162,9 +161,9 @@
               ExecuteJavaScript(@"test_result_message_"));
 }
 
-// Tests that RejectPromiseWithInvalidStateError rejects the promise with
-// DOMException(message, INVALID_STATE_ERR), where |message| is correct message
-// taken as argument.
+// Tests that RejectCredentialPromiseWithInvalidStateError rejects the promise
+// with DOMException(message, INVALID_STATE_ERR), where |message| is correct
+// message taken as argument.
 TEST_F(JsCredentialManagerTest, RejectWithInvalidState) {
   // Let requestId be 0.
   ExecuteJavaScript(
@@ -174,7 +173,7 @@
        "    (reason.name == DOMException.INVALID_STATE_ERR);"
        "  test_result_message_ = reason.message;"
        "});");
-  RejectPromiseWithInvalidStateError(
+  RejectCredentialPromiseWithInvalidStateError(
       web_state(), 0, base::ASCIIToUTF16("A 'get()' request is pending"));
   // Wait for Promise to be rejected before checking the values.
   WaitForCondition(^{
@@ -186,9 +185,9 @@
               ExecuteJavaScript(@"test_result_message_"));
 }
 
-// Tests that RejectPromiseWithNotSupportedError rejects the promise with
-// DOMException(message, NOT_SUPPORTED_ERR), where |message| is correct message
-// taken as argument.
+// Tests that RejectCredentialPromiseWithNotSupportedError rejects the promise
+// with DOMException(message, NOT_SUPPORTED_ERR), where |message| is correct
+// message taken as argument.
 TEST_F(JsCredentialManagerTest, RejectWithNotSupportedError) {
   // Let requestId be 0.
   ExecuteJavaScript(
@@ -198,7 +197,7 @@
        "    (reason.name == DOMException.NOT_SUPPORTED_ERR);"
        "  test_result_message_ = reason.message;"
        "});");
-  RejectPromiseWithNotSupportedError(
+  RejectCredentialPromiseWithNotSupportedError(
       web_state(), 0,
       base::ASCIIToUTF16(
           "An error occured while talking to the credential manager."));
@@ -211,5 +210,3 @@
   EXPECT_NSEQ(@"An error occured while talking to the credential manager.",
               ExecuteJavaScript(@"test_result_message_"));
 }
-
-}  // namespace credential_manager
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index e27eec0..3365d05 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -33,6 +33,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#include "ios/chrome/browser/passwords/credential_manager.h"
+#include "ios/chrome/browser/passwords/credential_manager_features.h"
 #import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h"
 #import "ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.h"
 #import "ios/chrome/browser/passwords/js_password_manager.h"
@@ -261,6 +263,7 @@
   std::unique_ptr<PasswordGenerationManager> passwordGenerationManager_;
   std::unique_ptr<PasswordManagerClient> passwordManagerClient_;
   std::unique_ptr<PasswordManagerDriver> passwordManagerDriver_;
+  std::unique_ptr<CredentialManager> credentialManager_;
   PasswordGenerationAgent* passwordGenerationAgent_;
 
   __weak JsPasswordManager* passwordJsManager_;
@@ -318,6 +321,11 @@
     webStateObserverBridge_.reset(
         new web::WebStateObserverBridge(webState, self));
     sent_request_to_store_ = NO;
+
+    if (base::FeatureList::IsEnabled(features::kCredentialManager)) {
+      credentialManager_ = base::MakeUnique<CredentialManager>(
+          passwordManagerClient_.get(), webState_);
+    }
   }
   return self;
 }
@@ -351,6 +359,7 @@
   passwordManagerDriver_.reset();
   passwordManager_.reset();
   passwordManagerClient_.reset();
+  credentialManager_.reset();
 }
 
 #pragma mark -
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index cef118e..54c9ffb 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -96,7 +96,6 @@
 #import "ios/chrome/browser/web/external_app_launcher.h"
 #import "ios/chrome/browser/web/navigation_manager_util.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
-#include "ios/chrome/browser/web/print_observer.h"
 #import "ios/chrome/browser/web/tab_id_tab_helper.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
@@ -215,9 +214,6 @@
   // web page.
   WebControllerSnapshotHelper* _webControllerSnapshotHelper;
 
-  // Handles support for window.print JavaScript calls.
-  std::unique_ptr<PrintObserver> _printObserver;
-
   // WebStateImpl for this tab.
   web::WebStateImpl* _webStateImpl;
 
@@ -402,13 +398,6 @@
       self, favicon::WebFaviconDriver::FromWebState(self.webState));
 }
 
-// Attach any tab helpers which are dependent on the dispatcher having been
-// set on the tab.
-- (void)attachDispatcherDependentTabHelpers {
-  _printObserver =
-      base::MakeUnique<PrintObserver>(self.webState, self.dispatcher);
-}
-
 - (id<FindInPageControllerDelegate>)findInPageControllerDelegate {
   return self;
 }
@@ -638,12 +627,9 @@
   // should be nil, or the new value should be nil.
   DCHECK(!_dispatcher || !dispatcher);
   _dispatcher = dispatcher;
+
   // Forward the new dispatcher to tab helpers.
-  PasswordTabHelper::FromWebState(self.webState)
-      ->SetDispatcher(self.dispatcher);
-  // If the new dispatcher is nonnull, add tab helpers.
-  if (self.dispatcher)
-    [self attachDispatcherDependentTabHelpers];
+  PasswordTabHelper::FromWebState(self.webState)->SetDispatcher(_dispatcher);
 }
 
 - (void)saveTitleToHistoryDB {
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
index d04b952c..957e87f 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h
@@ -10,7 +10,7 @@
 #include "components/signin/core/browser/signin_metrics.h"
 #import "ios/chrome/browser/signin/constants.h"
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class ChromeIdentity;
 @class ChromeSigninViewController;
 
@@ -67,7 +67,7 @@
 // It is valid to set this in the |willStartSignIn:| method of the delegate.
 @property(nonatomic, assign) ShouldClearData shouldClearData;
 
-@property(nonatomic, weak, readonly) id<ApplicationSettingsCommands> dispatcher;
+@property(nonatomic, weak, readonly) id<ApplicationCommands> dispatcher;
 
 // Designated initializer.
 // * |browserState| is the current browser state.
@@ -82,8 +82,7 @@
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
                          promoAction:(signin_metrics::PromoAction)promoAction
                       signInIdentity:(ChromeIdentity*)identity
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher;
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Cancels the on-going authentication operation (if any). |delegate| will be
 // called with |didFailSignIn|.
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 38bb691d..890de74 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -171,8 +171,7 @@
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
                          promoAction:(signin_metrics::PromoAction)promoAction
                       signInIdentity:(ChromeIdentity*)identity
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
     _browserState = browserState;
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h
index ac882d30..2dec0b66 100644
--- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h
+++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.h
@@ -12,6 +12,8 @@
 #include "components/infobars/core/infobar.h"
 #include "ui/gfx/image/image.h"
 
+@protocol ApplicationCommands;
+
 namespace infobars {
 class InfoBarManager;
 }  // namespace infobars
@@ -25,21 +27,26 @@
 // A confirmation infobar prompting user to bring up the sign-in screen.
 class ReSignInInfoBarDelegate : public ConfirmInfoBarDelegate {
  public:
-  explicit ReSignInInfoBarDelegate(ios::ChromeBrowserState* browser_state);
+  ReSignInInfoBarDelegate(ios::ChromeBrowserState* browser_state,
+                          id<ApplicationCommands> dispatcher);
   ~ReSignInInfoBarDelegate() override;
 
   // Creates a re-sign-in error infobar and adds it to the |tab|. Returns
   // whether the infobar was actually added.
-  static bool Create(ios::ChromeBrowserState* browser_state, Tab* tab);
+  static bool Create(ios::ChromeBrowserState* browser_state,
+                     Tab* tab,
+                     id<ApplicationCommands> dispatcher);
 
   // Creates a re-sign-in error infobar, but does not add it to tab content.
   static std::unique_ptr<infobars::InfoBar> CreateInfoBar(
       infobars::InfoBarManager* infobar_manager,
-      ios::ChromeBrowserState* browser_state);
+      ios::ChromeBrowserState* browser_state,
+      id<ApplicationCommands> dispatcher);
 
   // Creates a re-sign-in error infobar delegate, visible for testing.
   static std::unique_ptr<ReSignInInfoBarDelegate> CreateInfoBarDelegate(
-      ios::ChromeBrowserState* browser_state);
+      ios::ChromeBrowserState* browser_state,
+      id<ApplicationCommands> dispatcher);
 
   // InfobarDelegate implementation.
   InfoBarIdentifier GetIdentifier() const override;
@@ -55,6 +62,7 @@
  private:
   ios::ChromeBrowserState* browser_state_;
   gfx::Image icon_;
+  id<ApplicationCommands> dispatcher_;
 
   DISALLOW_COPY_AND_ASSIGN(ReSignInInfoBarDelegate);
 };
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
index 51da525..1d61a65 100644
--- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
+++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate.mm
@@ -20,7 +20,7 @@
 #include "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/tabs/tab.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -31,14 +31,16 @@
 
 // static
 bool ReSignInInfoBarDelegate::Create(ios::ChromeBrowserState* browser_state,
-                                     Tab* tab) {
+                                     Tab* tab,
+                                     id<ApplicationCommands> dispatcher) {
   DCHECK(tab.webState);
   infobars::InfoBarManager* infobar_manager =
       InfoBarManagerImpl::FromWebState(tab.webState);
   DCHECK(infobar_manager);
 
   std::unique_ptr<infobars::InfoBar> infobar =
-      ReSignInInfoBarDelegate::CreateInfoBar(infobar_manager, browser_state);
+      ReSignInInfoBarDelegate::CreateInfoBar(infobar_manager, browser_state,
+                                             dispatcher);
   if (!infobar)
     return false;
   return !!infobar_manager->AddInfoBar(std::move(infobar));
@@ -47,10 +49,11 @@
 // static
 std::unique_ptr<infobars::InfoBar> ReSignInInfoBarDelegate::CreateInfoBar(
     infobars::InfoBarManager* infobar_manager,
-    ios::ChromeBrowserState* browser_state) {
+    ios::ChromeBrowserState* browser_state,
+    id<ApplicationCommands> dispatcher) {
   DCHECK(infobar_manager);
   std::unique_ptr<ReSignInInfoBarDelegate> delegate =
-      ReSignInInfoBarDelegate::CreateInfoBarDelegate(browser_state);
+      ReSignInInfoBarDelegate::CreateInfoBarDelegate(browser_state, dispatcher);
   if (!delegate)
     return nullptr;
   return infobar_manager->CreateConfirmInfoBar(std::move(delegate));
@@ -59,7 +62,8 @@
 // static
 std::unique_ptr<ReSignInInfoBarDelegate>
 ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-    ios::ChromeBrowserState* browser_state) {
+    ios::ChromeBrowserState* browser_state,
+    id<ApplicationCommands> dispatcher) {
   DCHECK(browser_state);
   // Do not ask user to sign in if current profile is incognito.
   if (browser_state->IsOffTheRecord())
@@ -78,13 +82,15 @@
       base::UserMetricsAction("Signin_Impression_FromReSigninInfobar"));
   // User needs to be reminded to sign in again. Creates a new infobar delegate
   // and returns it.
-  return base::MakeUnique<ReSignInInfoBarDelegate>(browser_state);
+  return base::MakeUnique<ReSignInInfoBarDelegate>(browser_state, dispatcher);
 }
 
 ReSignInInfoBarDelegate::ReSignInInfoBarDelegate(
-    ios::ChromeBrowserState* browser_state)
+    ios::ChromeBrowserState* browser_state,
+    id<ApplicationCommands> dispatcher)
     : browser_state_(browser_state),
-      icon_([UIImage imageNamed:@"infobar_warning"]) {
+      icon_([UIImage imageNamed:@"infobar_warning"]),
+      dispatcher_(dispatcher) {
   DCHECK(browser_state_);
   DCHECK(!browser_state_->IsOffTheRecord());
 }
@@ -123,7 +129,7 @@
       initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
             accessPoint:signin_metrics::AccessPoint::
                             ACCESS_POINT_RESIGNIN_INFOBAR];
-  [infobarView chromeExecuteCommand:command];
+  [dispatcher_ showSignin:command];
 
   // Stop displaying the infobar once user interacted with it.
   AuthenticationServiceFactory::GetForBrowserState(browser_state_)
diff --git a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm
index e64b076..1f5b044 100644
--- a/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/re_signin_infobar_delegate_unittest.mm
@@ -15,43 +15,19 @@
 #include "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/signin/authentication_service_fake.h"
-#include "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #include "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "testing/gtest_mac.h"
 #include "testing/platform_test.h"
+#include "third_party/ocmock/OCMock/OCMock.h"
+#include "third_party/ocmock/gtest_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-// View that intercepts and stores chrome commands sent up the responder chain.
-@interface CatchExecuteCommandView : UIView {
-}
-// Command sent up the responder chain and intercepted by this view.
-@property(nonatomic, strong) id command;
-@end
-
-@implementation CatchExecuteCommandView
-
-@synthesize command = _command;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-  }
-  return self;
-}
-
-- (void)chromeExecuteCommand:(id)command {
-  DCHECK(command);
-  DCHECK(!self.command);
-  self.command = command;
-}
-
-@end
-
 namespace {
 
 class ReSignInInfoBarDelegateTest : public PlatformTest {
@@ -104,7 +80,7 @@
   authService->SetPromptForSignIn(false);
   std::unique_ptr<ReSignInInfoBarDelegate> infobar_delegate =
       ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_.get());
+          chrome_browser_state_.get(), nil);
   // Infobar delegate should not be created.
   EXPECT_FALSE(infobar_delegate.get());
   EXPECT_FALSE(authService->ShouldPromptForSignIn());
@@ -119,7 +95,7 @@
   authService->SetPromptForSignIn(true);
   std::unique_ptr<ReSignInInfoBarDelegate> infobar_delegate =
       ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_.get());
+          chrome_browser_state_.get(), nil);
   // Infobar delegate should be created.
   EXPECT_TRUE(infobar_delegate.get());
   EXPECT_TRUE(authService->ShouldPromptForSignIn());
@@ -134,7 +110,7 @@
   authService->SetPromptForSignIn(true);
   std::unique_ptr<ReSignInInfoBarDelegate> infobar_delegate =
       ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_.get());
+          chrome_browser_state_.get(), nil);
   // Infobar delegate should not be created.
   EXPECT_FALSE(infobar_delegate.get());
   EXPECT_FALSE(authService->ShouldPromptForSignIn());
@@ -149,7 +125,7 @@
   authService->SetPromptForSignIn(true);
   std::unique_ptr<ReSignInInfoBarDelegate> infobar_delegate =
       ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_->GetOffTheRecordChromeBrowserState());
+          chrome_browser_state_->GetOffTheRecordChromeBrowserState(), nil);
   // Infobar delegate should not be created.
   EXPECT_FALSE(infobar_delegate.get());
   EXPECT_TRUE(authService->ShouldPromptForSignIn());
@@ -158,7 +134,7 @@
 TEST_F(ReSignInInfoBarDelegateTest, TestMessages) {
   SetUpMainChromeBrowserStateNotSignedIn();
   std::unique_ptr<ReSignInInfoBarDelegate> delegate(
-      new ReSignInInfoBarDelegate(chrome_browser_state_.get()));
+      new ReSignInInfoBarDelegate(chrome_browser_state_.get(), nil));
   EXPECT_EQ(ConfirmInfoBarDelegate::BUTTON_OK, delegate->GetButtons());
   base::string16 message_text = delegate->GetMessageText();
   EXPECT_GT(message_text.length(), 0U);
@@ -173,23 +149,26 @@
       AuthenticationServiceFactory::GetForBrowserState(
           chrome_browser_state_.get());
   authService->SetPromptForSignIn(true);
+
+  id dispatcher = OCMProtocolMock(@protocol(ApplicationCommands));
+  [[dispatcher expect]
+      showSignin:[OCMArg checkWithBlock:^BOOL(id command) {
+        EXPECT_TRUE([command isKindOfClass:[ShowSigninCommand class]]);
+        EXPECT_EQ(AUTHENTICATION_OPERATION_REAUTHENTICATE,
+                  static_cast<ShowSigninCommand*>(command).operation);
+        return YES;
+      }]];
+
   std::unique_ptr<infobars::InfoBar> infobar(
       CreateConfirmInfoBar(ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_.get())));
+          chrome_browser_state_.get(), dispatcher)));
   InfoBarIOS* infobarIOS = static_cast<InfoBarIOS*>(infobar.get());
   infobarIOS->Layout(CGRectZero);
-  CatchExecuteCommandView* view =
-      [[CatchExecuteCommandView alloc] initWithFrame:CGRectZero];
-  [view addSubview:infobarIOS->view()];
 
   ReSignInInfoBarDelegate* delegate =
       static_cast<ReSignInInfoBarDelegate*>(infobarIOS->delegate());
   EXPECT_TRUE(delegate->Accept());
   EXPECT_FALSE(authService->ShouldPromptForSignIn());
-  EXPECT_TRUE([view command]);
-  EXPECT_TRUE([[view command] isKindOfClass:[ShowSigninCommand class]]);
-  EXPECT_EQ(AUTHENTICATION_OPERATION_REAUTHENTICATE,
-            static_cast<ShowSigninCommand*>([view command]).operation);
 }
 
 TEST_F(ReSignInInfoBarDelegateTest, TestInfoBarDismissed) {
@@ -198,20 +177,20 @@
       AuthenticationServiceFactory::GetForBrowserState(
           chrome_browser_state_.get());
   authService->SetPromptForSignIn(true);
+
+  id dispatcher = OCMProtocolMock(@protocol(ApplicationCommands));
+  [[dispatcher reject] showSignin:[OCMArg any]];
+
   std::unique_ptr<infobars::InfoBar> infobar(
       CreateConfirmInfoBar(ReSignInInfoBarDelegate::CreateInfoBarDelegate(
-          chrome_browser_state_.get())));
+          chrome_browser_state_.get(), dispatcher)));
   InfoBarIOS* infobarIOS = static_cast<InfoBarIOS*>(infobar.get());
   infobarIOS->Layout(CGRectZero);
-  CatchExecuteCommandView* view =
-      [[CatchExecuteCommandView alloc] initWithFrame:CGRectZero];
-  [view addSubview:infobarIOS->view()];
 
   ReSignInInfoBarDelegate* delegate =
       static_cast<ReSignInInfoBarDelegate*>(infobarIOS->delegate());
   delegate->InfoBarDismissed();
   EXPECT_FALSE(authService->ShouldPromptForSignIn());
-  EXPECT_FALSE([view command]);
 }
 
 }  // namespace
diff --git a/ios/chrome/browser/ui/authentication/signin_interaction_controller.h b/ios/chrome/browser/ui/authentication/signin_interaction_controller.h
index e668d8e6..d175703 100644
--- a/ios/chrome/browser/ui/authentication/signin_interaction_controller.h
+++ b/ios/chrome/browser/ui/authentication/signin_interaction_controller.h
@@ -11,7 +11,7 @@
 #include "components/signin/core/browser/signin_metrics.h"
 #include "ios/chrome/browser/signin/constants.h"
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 namespace ios {
 class ChromeBrowserState;
 }
@@ -33,8 +33,7 @@
                isPresentedOnSettings:(BOOL)isPresentedOnSettings
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
                          promoAction:(signin_metrics::PromoAction)promoAction
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher;
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Starts user sign-in.
 // * |viewController| is the current view controller.
diff --git a/ios/chrome/browser/ui/authentication/signin_interaction_controller.mm b/ios/chrome/browser/ui/authentication/signin_interaction_controller.mm
index 59f90c87..b0ee778d 100644
--- a/ios/chrome/browser/ui/authentication/signin_interaction_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signin_interaction_controller.mm
@@ -49,7 +49,7 @@
   BOOL identityAdded_;
 }
 
-@property(nonatomic, weak, readonly) id<ApplicationSettingsCommands> dispatcher;
+@property(nonatomic, weak, readonly) id<ApplicationCommands> dispatcher;
 
 @end
 
@@ -67,8 +67,7 @@
                isPresentedOnSettings:(BOOL)isPresentedOnSettings
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
                          promoAction:(signin_metrics::PromoAction)promoAction
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
     DCHECK(browserState);
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
index 005c837d..5ff1dbd 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_delegate.h"
 
+@protocol ApplicationCommands;
 @class ChromeIdentity;
 @class SigninPromoViewConfigurator;
 @protocol SigninPromoViewConsumer;
@@ -57,6 +58,7 @@
 // ACCESS_POINT_RECENT_TABS, ACCESS_POINT_TAB_SWITCHER are supported.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                          accessPoint:(signin_metrics::AccessPoint)accessPoint
+                          dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 - (SigninPromoViewConfigurator*)createConfigurator;
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
index 6355a937..494dc17 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator.mm
@@ -18,7 +18,7 @@
 #include "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
@@ -239,6 +239,8 @@
 
 @interface SigninPromoViewMediator ()<ChromeIdentityServiceObserver,
                                       ChromeBrowserProviderObserver>
+// Dispatcher for sending commands.
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
 @end
 
 @implementation SigninPromoViewMediator {
@@ -253,14 +255,17 @@
 @synthesize consumer = _consumer;
 @synthesize defaultIdentity = _defaultIdentity;
 @synthesize signinPromoViewState = _signinPromoViewState;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-                         accessPoint:(signin_metrics::AccessPoint)accessPoint {
+                         accessPoint:(signin_metrics::AccessPoint)accessPoint
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
     DCHECK(IsSupportedAccessPoint(accessPoint));
     _accessPoint = accessPoint;
     _browserState = browserState;
+    _dispatcher = dispatcher;
     NSArray* identities = ios::GetChromeBrowserProvider()
                               ->GetChromeIdentityService()
                               ->GetAllIdentitiesSortedForDisplay();
@@ -467,7 +472,7 @@
                callback:^(BOOL succeeded) {
                  [weakSelf signinCallback];
                }];
-  [signinPromoView chromeExecuteCommand:command];
+  [self.dispatcher showSignin:command];
 }
 
 - (void)signinPromoViewDidTapSigninWithDefaultAccount:
@@ -485,7 +490,7 @@
                callback:^(BOOL succeeded) {
                  [weakSelf signinCallback];
                }];
-  [signinPromoView chromeExecuteCommand:command];
+  [self.dispatcher showSignin:command];
 }
 
 - (void)signinPromoViewDidTapSigninWithOtherAccount:
@@ -503,7 +508,7 @@
                callback:^(BOOL succeeded) {
                  [weakSelf signinCallback];
                }];
-  [signinPromoView chromeExecuteCommand:command];
+  [self.dispatcher showSignin:command];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
index d71522b..633e841 100644
--- a/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/authentication/signin_promo_view_mediator_unittest.mm
@@ -28,8 +28,8 @@
     consumer_ = OCMStrictProtocolMock(@protocol(SigninPromoViewConsumer));
     mediator_ = [[SigninPromoViewMediator alloc]
         initWithBrowserState:nil
-                 accessPoint:signin_metrics::AccessPoint::
-                                 ACCESS_POINT_SETTINGS];
+                 accessPoint:signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS
+                  dispatcher:nil];
     mediator_.consumer = consumer_;
 
     signin_promo_view_ = OCMStrictClassMock([SigninPromoView class]);
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.h b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.h
index f8b9a5a..e4eec73 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.h
@@ -17,6 +17,7 @@
 
 // TODO(crbug.com/753599) : Delete this file after new bookmarks ui is launched.
 
+@protocol ApplicationCommands;
 @class BookmarkCollectionView;
 class GURL;
 @protocol UrlLoader;
@@ -98,7 +99,8 @@
 
 // Designated initializer.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-                               frame:(CGRect)frame;
+                               frame:(CGRect)frame
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Callback whenever the collection view is scrolled.
 - (void)collectionViewScrolled;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
index a9849a6..f1e2a3f 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_collection_view.mm
@@ -36,6 +36,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_waiting_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_signin_promo_cell.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/sync/synced_sessions_bridge.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -130,6 +131,9 @@
 
 @property(nonatomic, assign) const bookmarks::BookmarkNode* folder;
 
+// Dispatcher for sending commands.
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
+
 // Section indices.
 @property(nonatomic, readonly, assign) NSInteger promoSection;
 @property(nonatomic, readonly, assign) NSInteger folderSection;
@@ -149,6 +153,7 @@
 @synthesize longPressRecognizer = _longPressRecognizer;
 @synthesize browserState = _browserState;
 @synthesize shadow = _shadow;
+@synthesize dispatcher = _dispatcher;
 
 + (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
   registry->RegisterIntegerPref(prefs::kIosBookmarkSigninPromoDisplayedCount,
@@ -210,10 +215,12 @@
 }
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-                               frame:(CGRect)frame {
+                               frame:(CGRect)frame
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super initWithFrame:frame];
   if (self) {
     _browserState = browserState;
+    _dispatcher = dispatcher;
 
     // Set up connection to the BookmarkModel.
     _bookmarkModel =
@@ -356,7 +363,8 @@
     _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
         initWithBrowserState:_browserState
                  accessPoint:signin_metrics::AccessPoint::
-                                 ACCESS_POINT_BOOKMARK_MANAGER];
+                                 ACCESS_POINT_BOOKMARK_MANAGER
+                  dispatcher:self.dispatcher];
     _signinPromoViewMediator.consumer = self;
     [_signinPromoViewMediator signinPromoViewVisible];
   }
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h b/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h
index 80c16e68..37c275e6 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.h
@@ -7,6 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
+@protocol ApplicationCommands;
 @class BookmarkHomeViewController;
 @class BookmarkHomeTabletNTPController;
 @protocol NewTabPagePanelProtocol;
@@ -23,13 +24,15 @@
 // Returns an instance of BookmarkHomeHandsetViewController.
 - (BookmarkHomeViewController*)
 bookmarkControllerWithBrowserState:(ios::ChromeBrowserState*)browserState
-                            loader:(id<UrlLoader>)loader;
+                            loader:(id<UrlLoader>)loader
+                        dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Returns an instance of a NewTabPagePanelProtocol that can navigate and edit
 // the bookmark hierarchy.
 - (BookmarkHomeTabletNTPController*)
 bookmarkPanelControllerForBrowserState:(ios::ChromeBrowserState*)browserState
-                                loader:(id<UrlLoader>)loader;
+                                loader:(id<UrlLoader>)loader
+                            dispatcher:(id<ApplicationCommands>)dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.mm b/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.mm
index a1b0af70..f80846ea 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_controller_factory.mm
@@ -8,6 +8,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -17,17 +18,21 @@
 
 - (BookmarkHomeViewController*)
 bookmarkControllerWithBrowserState:(ios::ChromeBrowserState*)browserState
-                            loader:(id<UrlLoader>)loader {
+                            loader:(id<UrlLoader>)loader
+                        dispatcher:(id<ApplicationCommands>)dispatcher {
   return (BookmarkHomeViewController*)[[BookmarkHomeHandsetViewController alloc]
       initWithLoader:loader
-        browserState:browserState];
+        browserState:browserState
+          dispatcher:dispatcher];
 }
 
 - (BookmarkHomeTabletNTPController*)
 bookmarkPanelControllerForBrowserState:(ios::ChromeBrowserState*)browserState
-                                loader:(id<UrlLoader>)loader {
+                                loader:(id<UrlLoader>)loader
+                            dispatcher:(id<ApplicationCommands>)dispatcher {
   return [[BookmarkHomeTabletNTPController alloc] initWithLoader:loader
-                                                    browserState:browserState];
+                                                    browserState:browserState
+                                                      dispatcher:dispatcher];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
index 57d005f..4c7fc19 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller.mm
@@ -82,8 +82,11 @@
 @synthesize cachedContentPosition = _cachedContentPosition;
 
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
-                  browserState:(ios::ChromeBrowserState*)browserState {
-  self = [super initWithLoader:loader browserState:browserState];
+                  browserState:(ios::ChromeBrowserState*)browserState
+                    dispatcher:(id<ApplicationCommands>)dispatcher {
+  self = [super initWithLoader:loader
+                  browserState:browserState
+                    dispatcher:dispatcher];
   if (self) {
     self.sideSwipingPossible = YES;
   }
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller_unittest.mm
index 683b0a9..4336b721 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_handset_view_controller_unittest.mm
@@ -50,7 +50,8 @@
     BookmarkHomeHandsetViewController* controller =
         [[BookmarkHomeHandsetViewController alloc]
             initWithLoader:nil
-              browserState:chrome_browser_state_.get()];
+              browserState:chrome_browser_state_.get()
+                dispatcher:nil];
 
     [controller resetEditNodes];
     [controller insertEditNode:f1 atIndexPath:nil];
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
index 7553733..7d9d31c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
@@ -10,6 +10,7 @@
 #include <set>
 #include <vector>
 
+@protocol ApplicationCommands;
 @protocol UrlLoader;
 class GURL;
 
@@ -57,6 +58,7 @@
 - (instancetype)init NS_UNAVAILABLE;
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
                   browserState:(ios::ChromeBrowserState*)browserState
+                    dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 // Setter to set _rootNode value.
@@ -67,6 +69,9 @@
 // cases.
 @property(nonatomic, weak) id<BookmarkHomeViewControllerDelegate> homeDelegate;
 
+// Dispatcher for sending commands.
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
+
 // Dismisses any modal interaction elements. Note that this
 // method is currently used in case of handset only. In the future it
 // will be used by both cases.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 0935f80e..fba72214 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -33,6 +33,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_table_view.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
@@ -91,6 +92,7 @@
 @synthesize bookmarksTableView = _bookmarksTableView;
 @synthesize contextBar = _contextBar;
 @synthesize contextBarState = _contextBarState;
+@synthesize dispatcher = _dispatcher;
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -99,7 +101,8 @@
 #pragma mark - Initializer
 
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
-                  browserState:(ios::ChromeBrowserState*)browserState {
+                  browserState:(ios::ChromeBrowserState*)browserState
+                    dispatcher:(id<ApplicationCommands>)dispatcher {
   DCHECK(browserState);
   self = [super initWithNibName:nil bundle:nil];
   if (self) {
@@ -108,6 +111,7 @@
 
     _browserState = browserState->GetOriginalChromeBrowserState();
     _loader = loader;
+    _dispatcher = dispatcher;
 
     _bookmarks = ios::BookmarkModelFactory::GetForBrowserState(browserState);
 
@@ -117,7 +121,8 @@
     // passed in, as it could be incognito.
     _bookmarkPromoController =
         [[BookmarkPromoController alloc] initWithBrowserState:browserState
-                                                     delegate:self];
+                                                     delegate:self
+                                                   dispatcher:self.dispatcher];
   }
   return self;
 }
@@ -387,7 +392,8 @@
   BookmarkHomeViewController* controller =
       (BookmarkHomeViewController*)[bookmarkControllerFactory
           bookmarkControllerWithBrowserState:self.browserState
-                                      loader:_loader];
+                                      loader:_loader
+                                  dispatcher:self.dispatcher];
   [controller setRootNode:folder];
   controller.homeDelegate = self.homeDelegate;
   [self.navigationController pushViewController:controller animated:YES];
@@ -905,7 +911,8 @@
   // Create folder view.
   BookmarkCollectionView* view =
       [[BookmarkCollectionView alloc] initWithBrowserState:self.browserState
-                                                     frame:CGRectZero];
+                                                     frame:CGRectZero
+                                                dispatcher:self.dispatcher];
   self.folderView = view;
   [self.folderView setEditing:self.editing animated:NO];
   self.folderView.autoresizingMask =
@@ -921,7 +928,8 @@
       [[BookmarkTableView alloc] initWithBrowserState:self.browserState
                                              delegate:self
                                              rootNode:_rootNode
-                                                frame:self.view.bounds];
+                                                frame:self.view.bounds
+                                           dispatcher:self.dispatcher];
   [self.bookmarksTableView
       setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
                           UIViewAutoresizingFlexibleHeight];
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
index 002f26a..c54b26e 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
@@ -16,7 +16,8 @@
   @autoreleasepool {
     BookmarkHomeViewController* controller = [[BookmarkHomeViewController alloc]
         initWithLoader:nil
-          browserState:chrome_browser_state_.get()];
+          browserState:chrome_browser_state_.get()
+            dispatcher:nil];
 
     EXPECT_EQ(nil, controller.menuView);
     EXPECT_EQ(nil, controller.panelView);
@@ -37,7 +38,8 @@
   @autoreleasepool {
     BookmarkHomeViewController* controller = [[BookmarkHomeViewController alloc]
         initWithLoader:nil
-          browserState:chrome_browser_state_.get()];
+          browserState:chrome_browser_state_.get()
+            dispatcher:nil];
 
     EXPECT_TRUE(controller.waitForModelView == nil);
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
index be861ba9..d12a394 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
@@ -6,6 +6,7 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol ApplicationCommands;
 @class Tab;
 @protocol UrlLoader;
 
@@ -18,10 +19,10 @@
 // point is called when the user taps on the star icon.
 @interface BookmarkInteractionController : NSObject
 
-
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                               loader:(id<UrlLoader>)loader
                     parentController:(UIViewController*)parentController
+                          dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index 420757c..f7c629ad 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -26,6 +26,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #include "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/browser/ui/url_loader.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -67,6 +68,8 @@
 
 @property(nonatomic, strong) BookmarkMediator* mediator;
 
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
+
 // Builds a controller and brings it on screen.
 - (void)presentBookmarkForTab:(Tab*)tab;
 
@@ -83,10 +86,12 @@
 @synthesize bookmarkEditor = _bookmarkEditor;
 @synthesize bookmarkModel = _bookmarkModel;
 @synthesize mediator = _mediator;
+@synthesize dispatcher = _dispatcher;
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                               loader:(id<UrlLoader>)loader
-                    parentController:(UIViewController*)parentController {
+                    parentController:(UIViewController*)parentController
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
     // Bookmarks are always opened with the main browser state, even in
@@ -95,6 +100,7 @@
     _browserState = browserState->GetOriginalChromeBrowserState();
     _loader = loader;
     _parentController = parentController;
+    _dispatcher = dispatcher;
     _bookmarkModel =
         ios::BookmarkModelFactory::GetForBrowserState(_browserState);
     _mediator = [[BookmarkMediator alloc] initWithBrowserState:_browserState];
@@ -166,7 +172,8 @@
       [[BookmarkControllerFactory alloc] init];
   self.bookmarkBrowser = [bookmarkControllerFactory
       bookmarkControllerWithBrowserState:_currentBrowserState
-                                  loader:_loader];
+                                  loader:_loader
+                              dispatcher:self.dispatcher];
   self.bookmarkBrowser.homeDelegate = self;
 
   if (base::FeatureList::IsEnabled(kBookmarkNewGeneration)) {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h
index 7e72fef..1393a1b1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+@protocol ApplicationCommands;
+
 namespace ios {
 class ChromeBrowserState;
 }  // namespace ios
@@ -37,7 +39,8 @@
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             delegate:
-                                (id<BookmarkPromoControllerDelegate>)delegate;
+                                (id<BookmarkPromoControllerDelegate>)delegate
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Presents the sign-in UI.
 - (void)showSignIn;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
index d4c54f926..83c3619a 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_promo_controller.mm
@@ -15,7 +15,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
-#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/ui_util.h"
 
@@ -52,6 +52,9 @@
   bool _promoDisplayedRecorded;
 }
 
+// Dispatcher for sending commands.
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
+
 // Records that the promo was displayed. Can be called several times per
 // instance but will effectively record the histogram only once per instance.
 - (void)recordPromoDisplayed;
@@ -94,6 +97,7 @@
 
 @synthesize delegate = _delegate;
 @synthesize promoState = _promoState;
+@synthesize dispatcher = _dispatcher;
 
 + (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
   registry->RegisterBooleanPref(prefs::kIosBookmarkPromoAlreadySeen, false);
@@ -101,10 +105,12 @@
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             delegate:
-                                (id<BookmarkPromoControllerDelegate>)delegate {
+                                (id<BookmarkPromoControllerDelegate>)delegate
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super init];
   if (self) {
     _delegate = delegate;
+    _dispatcher = dispatcher;
     // Incognito browserState can go away before this class is released, this
     // code avoids keeping a pointer to it.
     _isIncognito = browserState->IsOffTheRecord();
@@ -139,7 +145,7 @@
       initWithOperation:AUTHENTICATION_OPERATION_SIGNIN
             accessPoint:signin_metrics::AccessPoint::
                             ACCESS_POINT_BOOKMARK_MANAGER];
-  [self chromeExecuteCommand:command];
+  [self.dispatcher showSignin:command];
 }
 
 - (void)hidePromoCell {
@@ -179,12 +185,6 @@
 
 #pragma mark - Private
 
-- (void)chromeExecuteCommand:(id)sender {
-  id delegate = [[UIApplication sharedApplication] delegate];
-  if ([delegate respondsToSelector:@selector(chromeExecuteCommand:)])
-    [delegate chromeExecuteCommand:sender];
-}
-
 - (void)recordPromoDisplayed {
   if (_promoDisplayedRecorded)
     return;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
index c7858ba8..177c6a6 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.h
@@ -8,6 +8,7 @@
 #import <UIKit/UIKit.h>
 #include <set>
 
+@protocol ApplicationCommands;
 class GURL;
 
 namespace bookmarks {
@@ -71,7 +72,9 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             delegate:(id<BookmarkTableViewDelegate>)delegate
                             rootNode:(const bookmarks::BookmarkNode*)rootNode
-                               frame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
+                               frame:(CGRect)frame
+                          dispatcher:(id<ApplicationCommands>)dispatcher
+    NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
 - (instancetype)initWithFrame:(CGRect)frame
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
index 329b2fe8..4de4a8c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_table_view.mm
@@ -27,6 +27,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_cell.h"
 #import "ios/chrome/browser/ui/bookmarks/cells/bookmark_table_signin_promo_cell.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/sync/synced_sessions_bridge.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "skia/ext/skia_utils_ios.h"
@@ -104,6 +105,9 @@
 // The loading spinner background which appears when syncing.
 @property(nonatomic, strong) BookmarkHomeWaitingView* spinnerView;
 
+// Dispatcher for sending commands.
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
+
 // Section indices.
 @property(nonatomic, readonly, assign) NSInteger promoSection;
 @property(nonatomic, readonly, assign) NSInteger bookmarksSection;
@@ -120,6 +124,7 @@
 @synthesize emptyTableBackgroundView = _emptyTableBackgroundView;
 @synthesize spinnerView = _spinnerView;
 @synthesize editing = _editing;
+@synthesize dispatcher = _dispatcher;
 
 + (void)registerBrowserStatePrefs:(user_prefs::PrefRegistrySyncable*)registry {
   registry->RegisterIntegerPref(prefs::kIosBookmarkSigninPromoDisplayedCount,
@@ -129,13 +134,15 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             delegate:(id<BookmarkTableViewDelegate>)delegate
                             rootNode:(const BookmarkNode*)rootNode
-                               frame:(CGRect)frame {
+                               frame:(CGRect)frame
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super initWithFrame:frame];
   if (self) {
     DCHECK(rootNode);
     _browserState = browserState;
     _delegate = delegate;
     _currentRootNode = rootNode;
+    _dispatcher = dispatcher;
 
     // Set up connection to the BookmarkModel.
     _bookmarkModel =
@@ -215,7 +222,8 @@
     _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
         initWithBrowserState:_browserState
                  accessPoint:signin_metrics::AccessPoint::
-                                 ACCESS_POINT_BOOKMARK_MANAGER];
+                                 ACCESS_POINT_BOOKMARK_MANAGER
+                  dispatcher:self.dispatcher];
     _signinPromoViewMediator.consumer = self;
     [_signinPromoViewMediator signinPromoViewVisible];
   }
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index df93d269..97112110 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -171,8 +171,10 @@
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 #import "ios/chrome/browser/web/error_page_content.h"
 #import "ios/chrome/browser/web/passkit_dialog_provider.h"
+#include "ios/chrome/browser/web/print_tab_helper.h"
 #import "ios/chrome/browser/web/repost_form_tab_helper.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper.h"
+#include "ios/chrome/browser/web/web_state_printer.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
@@ -375,7 +377,8 @@
                                     UIGestureRecognizerDelegate,
                                     UpgradeCenterClientProtocol,
                                     VoiceSearchBarDelegate,
-                                    VoiceSearchBarOwner> {
+                                    VoiceSearchBarOwner,
+                                    WebStatePrinter> {
   // The dependency factory passed on initialization.  Used to vend objects used
   // by the BVC.
   BrowserViewControllerDependencyFactory* _dependencyFactory;
@@ -1581,7 +1584,7 @@
       InfoBarManagerImpl::FromWebState(webState);
   [[UpgradeCenter sharedInstance] addInfoBarToManager:infoBarManager
                                              forTabId:[tab tabId]];
-  if (!ReSignInInfoBarDelegate::Create(_browserState, tab)) {
+  if (!ReSignInInfoBarDelegate::Create(_browserState, tab, self.dispatcher)) {
     DisplaySyncErrors(_browserState, tab, self.dispatcher);
   }
 
@@ -1991,10 +1994,11 @@
 - (void)initializeBookmarkInteractionController {
   if (_bookmarkInteractionController)
     return;
-  _bookmarkInteractionController =
-      [[BookmarkInteractionController alloc] initWithBrowserState:_browserState
-                                                           loader:self
-                                                 parentController:self];
+  _bookmarkInteractionController = [[BookmarkInteractionController alloc]
+      initWithBrowserState:_browserState
+                    loader:self
+          parentController:self
+                dispatcher:self.dispatcher];
 }
 
 // Update the state of back and forward buttons, hiding the forward button if
@@ -2367,6 +2371,7 @@
   // BrowserViewController owns the coordinator that displays the Sad Tab.
   if (!SadTabTabHelper::FromWebState(tab.webState))
     SadTabTabHelper::CreateForWebState(tab.webState, _sadTabCoordinator);
+  PrintTabHelper::CreateForWebState(tab.webState, self);
 }
 
 - (void)uninstallDelegatesForTab:(Tab*)tab {
@@ -5106,4 +5111,11 @@
   [_toolbarController cancelOmniboxEdit];
 }
 
+#pragma mark - WebStatePrinter
+
+- (void)printWebState:(web::WebState*)webState {
+  if (webState == [_model currentTab].webState)
+    [self printTab];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index be2473b..9ddc083 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -9,6 +9,7 @@
 
 @class OpenNewTabCommand;
 @class OpenUrlCommand;
+@class ShowSigninCommand;
 @class StartVoiceSearchCommand;
 
 // This protocol groups commands that are part of ApplicationCommands, but
@@ -79,6 +80,9 @@
 // Opens the |command| URL.
 - (void)openURL:(OpenUrlCommand*)command;
 
+// Shows the signin UI.
+- (void)showSignin:(ShowSigninCommand*)command;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_APPLICATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/ios_command_ids.h b/ios/chrome/browser/ui/commands/ios_command_ids.h
index 23ec0a9..29be6982 100644
--- a/ios/chrome/browser/ui/commands/ios_command_ids.h
+++ b/ios/chrome/browser/ui/commands/ios_command_ids.h
@@ -13,7 +13,6 @@
 // also need to be updated.
 
 // clang-format off
-#define IDC_SHOW_SIGNIN_IOS                            40905
 #define IDC_SHOW_ADD_ACCOUNT                           40910
 #define IDC_CLEAR_BROWSING_DATA_IOS                    40924
 #define IDC_SHOW_MAIL_COMPOSER                         40926
diff --git a/ios/chrome/browser/ui/commands/show_signin_command.mm b/ios/chrome/browser/ui/commands/show_signin_command.mm
index e2fc2c6..584846d1 100644
--- a/ios/chrome/browser/ui/commands/show_signin_command.mm
+++ b/ios/chrome/browser/ui/commands/show_signin_command.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 
 #include "base/logging.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -30,7 +29,7 @@
                       promoAction:(signin_metrics::PromoAction)promoAction
                          callback:
                              (ShowSigninCommandCompletionCallback)callback {
-  if ((self = [super initWithTag:IDC_SHOW_SIGNIN_IOS])) {
+  if ((self = [super initWithTag:0])) {
     DCHECK(operation == AUTHENTICATION_OPERATION_SIGNIN || identity == nil);
     _operation = operation;
     _identity = identity;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 951a4157..6c7dd476 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -637,6 +637,8 @@
       break;
   }
 
+  if (IsIPadIdiom())
+    [self.headerSynchronizer unfocusOmnibox];
 }
 
 // Checks if the |section| is empty and add an empty element if it is the case.
diff --git a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h
index e3b85cc..d2d002b 100644
--- a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h
+++ b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.h
@@ -10,7 +10,7 @@
 extern NSString* const kSignInButtonAccessibilityIdentifier;
 extern NSString* const kSignInSkipButtonAccessibilityIdentifier;
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class FirstRunConfiguration;
 namespace ios {
 class ChromeBrowserState;
@@ -25,8 +25,7 @@
                             tabModel:(TabModel*)tabModel
                       firstRunConfig:(FirstRunConfiguration*)firstRunConfig
                       signInIdentity:(ChromeIdentity*)identity
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher;
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
index afc0f44..ffff472 100644
--- a/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_chrome_signin_view_controller.mm
@@ -45,8 +45,7 @@
                             tabModel:(TabModel*)tabModel
                       firstRunConfig:(FirstRunConfiguration*)firstRunConfig
                       signInIdentity:(ChromeIdentity*)identity
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super
        initWithBrowserState:browserState
       isPresentedOnSettings:NO
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.h b/ios/chrome/browser/ui/first_run/first_run_util.h
index 68ef0203..1e8f293 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.h
+++ b/ios/chrome/browser/ui/first_run/first_run_util.h
@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class FirstRunConfiguration;
 @class Tab;
 
@@ -47,7 +47,7 @@
 void FinishFirstRun(ios::ChromeBrowserState* browserState,
                     Tab* tab,
                     FirstRunConfiguration* config,
-                    id<ApplicationSettingsCommands> dispatcher);
+                    id<ApplicationCommands> dispatcher);
 
 // Records Product tour timing metrics using histogram.
 void RecordProductTourTimingMetrics(NSString* timer_name,
diff --git a/ios/chrome/browser/ui/first_run/first_run_util.mm b/ios/chrome/browser/ui/first_run/first_run_util.mm
index 8632104b..bbb68b5 100644
--- a/ios/chrome/browser/ui/first_run/first_run_util.mm
+++ b/ios/chrome/browser/ui/first_run/first_run_util.mm
@@ -160,7 +160,7 @@
 void FinishFirstRun(ios::ChromeBrowserState* browserState,
                     Tab* tab,
                     FirstRunConfiguration* config,
-                    id<ApplicationSettingsCommands> dispatcher) {
+                    id<ApplicationCommands> dispatcher) {
   [[NSNotificationCenter defaultCenter]
       postNotificationName:kChromeFirstRunUIWillFinishNotification
                     object:nil];
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h
index c8c4ebb..9b2a4931 100644
--- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h
+++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h
@@ -9,7 +9,7 @@
 
 extern NSString* const kUMAMetricsButtonAccessibilityIdentifier;
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class TabModel;
 
 namespace ios {
@@ -30,7 +30,7 @@
 // which can be nil.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             tabModel:(TabModel*)tabModel
-                          dispatcher:(id<ApplicationSettingsCommands>)dispatcher
+                          dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithNibName:(NSString*)nibNameOrNil
diff --git a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm
index b43a67e..688a4060 100644
--- a/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.mm
@@ -55,7 +55,7 @@
 // The animation which occurs at launch has run.
 @property(nonatomic, assign) BOOL ranLaunchAnimation;
 
-@property(nonatomic, readonly, weak) id<ApplicationSettingsCommands> dispatcher;
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
 
 @end
 
@@ -78,8 +78,7 @@
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                             tabModel:(TabModel*)tabModel
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   DCHECK(browserState);
   DCHECK(tabModel);
   self = [super initWithNibName:nil bundle:nil];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index d8f3373..fbeda141 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -576,7 +576,8 @@
           [[BookmarkControllerFactory alloc] init];
       _bookmarkController =
           [factory bookmarkPanelControllerForBrowserState:_browserState
-                                                   loader:_loader];
+                                                   loader:_loader
+                                               dispatcher:self.dispatcher];
     }
     panelController = _bookmarkController;
     [_bookmarkController setDelegate:self];
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 7f71f7d..41a81f00 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -816,7 +816,8 @@
         _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
             initWithBrowserState:_browserState
                      accessPoint:signin_metrics::AccessPoint::
-                                     ACCESS_POINT_RECENT_TABS];
+                                     ACCESS_POINT_RECENT_TABS
+                      dispatcher:self.dispatcher];
         _signinPromoViewMediator.consumer = self;
       }
       contentViewTopMargin = kSigninPromoViewTopMargin;
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h
index dd3cd6e..3793546 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h
@@ -7,7 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 
 namespace ios {
 class ChromeBrowserState;
@@ -19,7 +19,7 @@
 // Designated initializer.
 - (instancetype)initWithFrame:(CGRect)aRect
                  browserState:(ios::ChromeBrowserState*)browserState
-                   dispatcher:(id<ApplicationSettingsCommands>)dispatcher
+                   dispatcher:(id<ApplicationCommands>)dispatcher
     NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.mm
index 446ec4c..47323116 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.mm
@@ -5,7 +5,6 @@
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/fancy_ui/primary_action_button.h"
@@ -30,7 +29,7 @@
 
 @interface SignedInSyncOffView ()
 // Dispatcher for sending commands.
-@property(nonatomic, weak) id<ApplicationSettingsCommands> dispatcher;
+@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
 @end
 
 @implementation SignedInSyncOffView {
@@ -40,7 +39,7 @@
 
 - (instancetype)initWithFrame:(CGRect)aRect
                  browserState:(ios::ChromeBrowserState*)browserState
-                   dispatcher:(id<ApplicationSettingsCommands>)dispatcher {
+                   dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super initWithFrame:CGRectZero];
   if (self) {
     _browserState = browserState;
@@ -87,11 +86,11 @@
   SyncSetupService::SyncServiceState syncState =
       GetSyncStateForBrowserState(_browserState);
   if (ShouldShowSyncSignin(syncState)) {
-    [self chromeExecuteCommand:
-              [[ShowSigninCommand alloc]
-                  initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
-                        accessPoint:signin_metrics::AccessPoint::
-                                        ACCESS_POINT_UNKNOWN]];
+    [self.dispatcher
+        showSignin:[[ShowSigninCommand alloc]
+                       initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
+                             accessPoint:signin_metrics::AccessPoint::
+                                             ACCESS_POINT_UNKNOWN]];
   } else if (ShouldShowSyncSettings(syncState)) {
     [self.dispatcher showSyncSettings];
   } else if (ShouldShowSyncPassphraseSettings(syncState)) {
diff --git a/ios/chrome/browser/ui/omnibox/BUILD.gn b/ios/chrome/browser/ui/omnibox/BUILD.gn
index 5546fb47..9565206 100644
--- a/ios/chrome/browser/ui/omnibox/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/BUILD.gn
@@ -18,14 +18,21 @@
 source_set("omnibox_internal") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "autocomplete_match_formatter.h",
+    "autocomplete_match_formatter.mm",
+    "autocomplete_result_consumer.h",
+    "autocomplete_suggestion.h",
     "chrome_omnibox_client_ios.h",
     "chrome_omnibox_client_ios.mm",
+    "image_retriever.h",
     "location_bar_controller_impl.h",
     "location_bar_controller_impl.mm",
     "omnibox_popup_material_row.h",
     "omnibox_popup_material_row.mm",
     "omnibox_popup_material_view_controller.h",
     "omnibox_popup_material_view_controller.mm",
+    "omnibox_popup_mediator.h",
+    "omnibox_popup_mediator.mm",
     "omnibox_popup_positioner.h",
     "omnibox_popup_presenter.h",
     "omnibox_popup_presenter.mm",
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h
new file mode 100644
index 0000000..02ae678
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_MATCH_FORMATTER_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_MATCH_FORMATTER_H_
+
+#import "ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h"
+
+struct AutocompleteMatch;
+@interface AutocompleteMatchFormatter : NSObject<AutocompleteSuggestion>
+
+// This is a temporary solution for coloring strings.
+@property(nonatomic, assign, getter=isIncognito) BOOL incognito;
+@property(nonatomic, assign, getter=isStarred) BOOL starred;
+
+- (instancetype)initWithMatch:(const AutocompleteMatch&)match
+    NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+
+// Convenience constuctor.
++ (instancetype)formatterWithMatch:(const AutocompleteMatch&)match;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_MATCH_FORMATTER_H_
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm
new file mode 100644
index 0000000..275beb9
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.mm
@@ -0,0 +1,357 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/suggestion_answer.h"
+#include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// The color of the main text of a suggest cell.
+UIColor* SuggestionTextColor() {
+  return [UIColor colorWithWhite:(51 / 255.0) alpha:1.0];
+}
+// The color of the detail text of a suggest cell.
+UIColor* SuggestionDetailTextColor() {
+  return [UIColor colorWithRed:(85 / 255.0)
+                         green:(149 / 255.0)
+                          blue:(254 / 255.0)
+                         alpha:1.0];
+}
+// The color of the text in the portion of a search suggestion that matches the
+// omnibox input text.
+UIColor* DimColor() {
+  return [UIColor colorWithWhite:(161 / 255.0) alpha:1.0];
+}
+UIColor* SuggestionTextColorIncognito() {
+  return [UIColor whiteColor];
+}
+UIColor* DimColorIncognito() {
+  return [UIColor whiteColor];
+}
+}  // namespace
+
+@implementation AutocompleteMatchFormatter {
+  AutocompleteMatch _match;
+}
+@synthesize incognito = _incognito;
+@synthesize starred = _starred;
+
+- (instancetype)initWithMatch:(const AutocompleteMatch&)match {
+  self = [super init];
+  if (self) {
+    _match = AutocompleteMatch(match);
+  }
+  return self;
+}
+
++ (instancetype)formatterWithMatch:(const AutocompleteMatch&)match {
+  return [[self alloc] initWithMatch:match];
+}
+
+#pragma mark - NSObject
+
+- (NSString*)description {
+  return [NSString
+      stringWithFormat:@"%@ (%@)", self.text.string, self.detailText.string];
+}
+
+#pragma mark AutocompleteSuggestion
+
+- (BOOL)supportsDeletion {
+  return _match.SupportsDeletion();
+}
+
+- (BOOL)hasAnswer {
+  return _match.answer.get() != nullptr;
+}
+
+- (BOOL)hasImage {
+  return self.hasAnswer && _match.answer->second_line().image_url().is_valid();
+}
+
+- (BOOL)isURL {
+  return !AutocompleteMatch::IsSearchType(_match.type);
+}
+
+- (NSAttributedString*)detailText {
+  // The detail text should be the URL (|_match.contents|) for non-search
+  // suggestions and the entity type (|_match.description|) for search entity
+  // suggestions. For all other search suggestions, |_match.description| is the
+  // name of the currently selected search engine, which for mobile we suppress.
+  NSString* detailText = nil;
+  if (self.isURL)
+    detailText = base::SysUTF16ToNSString(_match.contents);
+  else if (_match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY)
+    detailText = base::SysUTF16ToNSString(_match.description);
+
+  NSAttributedString* detailAttributedText = nil;
+  if (self.hasAnswer) {
+    detailAttributedText =
+        [self attributedStringWithAnswerLine:_match.answer->second_line()];
+  } else {
+    const ACMatchClassifications* classifications =
+        self.isURL ? &_match.contents_class : nullptr;
+    // The suggestion detail color should match the main text color for entity
+    // suggestions. For non-search suggestions (URLs), a highlight color is used
+    // instead.
+    UIColor* suggestionDetailTextColor = nil;
+    if (_match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY) {
+      suggestionDetailTextColor =
+          _incognito ? SuggestionTextColorIncognito() : SuggestionTextColor();
+    } else {
+      suggestionDetailTextColor = SuggestionDetailTextColor();
+    }
+    DCHECK(suggestionDetailTextColor);
+    detailAttributedText =
+        [self attributedStringWithString:detailText
+                         classifications:classifications
+                               smallFont:YES
+                                   color:suggestionDetailTextColor
+                                dimColor:DimColor()];
+  }
+  return detailAttributedText;
+}
+
+- (NSInteger)numberOfLines {
+  // Answers specify their own limit on the number of lines to show but are
+  // additionally capped here at 3 to guard against unreasonable values.
+  const SuggestionAnswer::TextField& first_text_field =
+      _match.answer->second_line().text_fields()[0];
+  if (first_text_field.has_num_lines() && first_text_field.num_lines() > 1)
+    return MIN(3, first_text_field.num_lines());
+  else
+    return 1;
+}
+
+- (NSAttributedString*)text {
+  // The text should be search term (|_match.contents|) for searches, otherwise
+  // page title (|_match.description|).
+  base::string16 textString =
+      !self.isURL ? _match.contents : _match.description;
+  NSString* text = base::SysUTF16ToNSString(textString);
+
+  // If for some reason the title is empty, copy the detailText.
+  if ([text length] == 0 && [self.detailText length] != 0) {
+    text = [self.detailText string];
+  }
+
+  NSAttributedString* attributedText = nil;
+
+  if (self.hasAnswer) {
+    attributedText =
+        [self attributedStringWithAnswerLine:_match.answer->first_line()];
+  } else {
+    const ACMatchClassifications* textClassifications =
+        !self.isURL ? &_match.contents_class : &_match.description_class;
+    UIColor* suggestionTextColor =
+        _incognito ? SuggestionTextColorIncognito() : SuggestionTextColor();
+    UIColor* dimColor = _incognito ? DimColorIncognito() : DimColor();
+
+    attributedText = [self attributedStringWithString:text
+                                      classifications:textClassifications
+                                            smallFont:NO
+                                                color:suggestionTextColor
+                                             dimColor:dimColor];
+  }
+  return attributedText;
+}
+
+- (BOOL)isAppendable {
+  return _match.type == AutocompleteMatchType::SEARCH_HISTORY ||
+         _match.type == AutocompleteMatchType::SEARCH_SUGGEST ||
+         _match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY ||
+         _match.type == AutocompleteMatchType::PHYSICAL_WEB;
+}
+
+- (GURL)imageURL {
+  return _match.answer->second_line().image_url();
+}
+
+- (int)imageID {
+  return GetIconForAutocompleteMatchType(_match.type, self.isStarred,
+                                         self.isIncognito);
+}
+
+#pragma mark helpers
+
+// Create a string to display for an answer line.
+- (NSMutableAttributedString*)attributedStringWithAnswerLine:
+    (const SuggestionAnswer::ImageLine&)line {
+  NSMutableAttributedString* result =
+      [[NSMutableAttributedString alloc] initWithString:@""];
+
+  for (const auto field : line.text_fields()) {
+    [result appendAttributedString:[self attributedStringForTextfield:&field]];
+  }
+
+  NSAttributedString* spacer =
+      [[NSAttributedString alloc] initWithString:@"  "];
+  if (line.additional_text() != nil) {
+    [result appendAttributedString:spacer];
+    [result appendAttributedString:
+                [self attributedStringForTextfield:line.additional_text()]];
+  }
+
+  if (line.status_text() != nil) {
+    [result appendAttributedString:spacer];
+    [result appendAttributedString:
+                [self attributedStringForTextfield:line.status_text()]];
+  }
+
+  return result;
+}
+
+// Create a string to display for a textual part ("textfield") of a suggestion
+// answer.
+- (NSAttributedString*)attributedStringForTextfield:
+    (const SuggestionAnswer::TextField*)field {
+  const base::string16& string = field->text();
+  const int type = field->type();
+
+  NSDictionary* attributes = nil;
+
+  // Answer types, sizes and colors specified at http://goto.google.com/ais_api.
+  switch (type) {
+    case SuggestionAnswer::TOP_ALIGNED:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:12],
+        NSBaselineOffsetAttributeName : @10.0f,
+        NSForegroundColorAttributeName : [UIColor grayColor],
+      };
+      break;
+    case SuggestionAnswer::DESCRIPTION_POSITIVE:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:16],
+        NSForegroundColorAttributeName : [UIColor colorWithRed:11 / 255.0
+                                                         green:128 / 255.0
+                                                          blue:67 / 255.0
+                                                         alpha:1.0],
+      };
+      break;
+    case SuggestionAnswer::DESCRIPTION_NEGATIVE:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:16],
+        NSForegroundColorAttributeName : [UIColor colorWithRed:197 / 255.0
+                                                         green:57 / 255.0
+                                                          blue:41 / 255.0
+                                                         alpha:1.0],
+      };
+      break;
+    case SuggestionAnswer::PERSONALIZED_SUGGESTION:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:16],
+      };
+      break;
+    case SuggestionAnswer::ANSWER_TEXT_MEDIUM:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:20],
+        NSForegroundColorAttributeName : [UIColor grayColor],
+      };
+      break;
+    case SuggestionAnswer::ANSWER_TEXT_LARGE:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:24],
+        NSForegroundColorAttributeName : [UIColor grayColor],
+      };
+      break;
+    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:12],
+        NSForegroundColorAttributeName : [UIColor grayColor],
+      };
+      break;
+    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_MEDIUM:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:14],
+        NSForegroundColorAttributeName : [UIColor grayColor],
+      };
+      break;
+    case SuggestionAnswer::SUGGESTION:
+    // Fall through.
+    default:
+      attributes = @{
+        NSFontAttributeName : [[MDCTypography fontLoader] regularFontOfSize:16],
+      };
+  }
+
+  NSString* unescapedString =
+      base::SysUTF16ToNSString(net::UnescapeForHTML(string));
+  // TODO(crbug.com/763894): Remove this tag stripping once the JSON parsing
+  // class handles HTML tags.
+  unescapedString = [unescapedString stringByReplacingOccurrencesOfString:@"<b>"
+                                                               withString:@""];
+  unescapedString =
+      [unescapedString stringByReplacingOccurrencesOfString:@"</b>"
+                                                 withString:@""];
+
+  return [[NSAttributedString alloc] initWithString:unescapedString
+                                         attributes:attributes];
+}
+
+// Create a formatted string given text and classifications.
+- (NSMutableAttributedString*)
+attributedStringWithString:(NSString*)text
+           classifications:(const ACMatchClassifications*)classifications
+                 smallFont:(BOOL)smallFont
+                     color:(UIColor*)defaultColor
+                  dimColor:(UIColor*)dimColor {
+  if (text == nil)
+    return nil;
+
+  UIFont* fontRef =
+      smallFont ? [MDCTypography body1Font] : [MDCTypography subheadFont];
+
+  NSMutableAttributedString* styledText =
+      [[NSMutableAttributedString alloc] initWithString:text];
+
+  // Set the base attributes to the default font and color.
+  NSDictionary* dict = @{
+    NSFontAttributeName : fontRef,
+    NSForegroundColorAttributeName : defaultColor,
+  };
+  [styledText addAttributes:dict range:NSMakeRange(0, [text length])];
+
+  if (classifications != NULL) {
+    UIFont* boldFontRef =
+        [[MDCTypography fontLoader] mediumFontOfSize:fontRef.pointSize];
+
+    for (ACMatchClassifications::const_iterator i = classifications->begin();
+         i != classifications->end(); ++i) {
+      const BOOL isLast = (i + 1) == classifications->end();
+      const size_t nextOffset = (isLast ? [text length] : (i + 1)->offset);
+      const NSInteger location = static_cast<NSInteger>(i->offset);
+      const NSInteger length = static_cast<NSInteger>(nextOffset - i->offset);
+      // Guard against bad, off-the-end classification ranges due to
+      // crbug.com/121703 and crbug.com/131370.
+      if (i->offset + length > [text length] || length <= 0)
+        break;
+      const NSRange range = NSMakeRange(location, length);
+      if (0 != (i->style & ACMatchClassification::MATCH)) {
+        [styledText addAttribute:NSFontAttributeName
+                           value:boldFontRef
+                           range:range];
+      }
+
+      if (0 != (i->style & ACMatchClassification::DIM)) {
+        [styledText addAttribute:NSForegroundColorAttributeName
+                           value:dimColor
+                           range:range];
+      }
+    }
+  }
+  return styledText;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_result_consumer.h b/ios/chrome/browser/ui/omnibox/autocomplete_result_consumer.h
new file mode 100644
index 0000000..ff0dfcda
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/autocomplete_result_consumer.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_RESULT_CONSUMER_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_RESULT_CONSUMER_H_
+
+#import "ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h"
+
+@protocol AutocompleteResultConsumer;
+
+// Delegate for AutocompleteResultConsumer.
+@protocol AutocompleteResultConsumerDelegate<NSObject>
+
+// Tells the delegate when a row containing a suggestion is clicked.
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+                      didSelectRow:(NSUInteger)row;
+// Tells the delegate when a suggestion in|row| was chosen for appending to
+// omnibox.
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+          didSelectRowForAppending:(NSUInteger)row;
+// Tells the delegate when a suggestion in |row| was removed.
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+           didSelectRowForDeletion:(NSUInteger)row;
+// Tells the delegate on scroll.
+- (void)autocompleteResultConsumerDidScroll:
+    (id<AutocompleteResultConsumer>)sender;
+
+@end
+
+// An abstract consumer of autocomplete results.
+@protocol AutocompleteResultConsumer<NSObject>
+// Updates the current data and forces a redraw. If animation is YES, adds
+// CALayer animations to fade the OmniboxPopupMaterialRows in.
+- (void)updateMatches:(NSArray<id<AutocompleteSuggestion>>*)result
+        withAnimation:(BOOL)animation;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_RESULT_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h b/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h
new file mode 100644
index 0000000..09fc8e8
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/autocomplete_suggestion.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_SUGGESTION_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_SUGGESTION_H_
+
+#import <UIKit/UIKit.h>
+
+class GURL;
+
+// Represents an autocomplete suggestion in UI.
+@protocol AutocompleteSuggestion<NSObject>
+// Some suggestions can be deleted with a swipe-to-delete gesture.
+- (BOOL)supportsDeletion;
+// Some suggestions are answers that are displayed inline, such as for weather
+// or calculator.
+- (BOOL)hasAnswer;
+// Some suggestions represent a URL, for example the ones from history.
+- (BOOL)isURL;
+// Some suggestions can be appended to omnibox text in order to refine the
+// query.
+- (BOOL)isAppendable;
+// The leading image for this suggestion type (loupe, globe, etc). Values are
+// described in AutocompleteMatchType enum.
+- (int)imageID;
+
+// Text of the suggestion.
+- (NSAttributedString*)text;
+// Second line of text.
+- (NSAttributedString*)detailText;
+// Suggested number of lines to format |detailText|.
+- (NSInteger)numberOfLines;
+
+// Wether the suggestion has a downloadable image.
+- (BOOL)hasImage;
+// URL of the image, if |hasImage| is true.
+- (GURL)imageURL;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_AUTOCOMPLETE_SUGGESTION_H_
diff --git a/ios/chrome/browser/ui/omnibox/image_retriever.h b/ios/chrome/browser/ui/omnibox/image_retriever.h
new file mode 100644
index 0000000..6180ae7e
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/image_retriever.h
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_IMAGE_RETRIEVER_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_IMAGE_RETRIEVER_H_
+
+@protocol ImageRetriever<NSObject>
+- (void)fetchImage:(GURL)imageURL completion:(void (^)(UIImage*))completion;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_IMAGE_RETRIEVER_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
index f4b097b..e0f6482f 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h
@@ -6,39 +6,25 @@
 #define IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MATERIAL_VIEW_CONTROLLER_H_
 
 #import <UIKit/UIKit.h>
+#import "ios/chrome/browser/ui/omnibox/autocomplete_result_consumer.h"
+#import "ios/chrome/browser/ui/omnibox/image_retriever.h"
 
-#include "components/omnibox/browser/autocomplete_result.h"
-
-namespace image_fetcher {
-class IOSImageDataFetcherWrapper;
-}
-
-class OmniboxPopupMaterialViewControllerDelegate {
- public:
-  virtual bool IsStarredMatch(const AutocompleteMatch& match) const = 0;
-  virtual void OnMatchSelected(const AutocompleteMatch& match, size_t row) = 0;
-  virtual void OnMatchSelectedForAppending(const AutocompleteMatch& match) = 0;
-  virtual void OnMatchSelectedForDeletion(const AutocompleteMatch& match) = 0;
-  virtual void OnScroll() = 0;
-};
+@protocol ImageRetriever;
 
 // View controller used to display a list of omnibox autocomplete matches in the
 // omnibox popup.
-@interface OmniboxPopupMaterialViewController : UITableViewController
+@interface OmniboxPopupMaterialViewController
+    : UITableViewController<AutocompleteResultConsumer>
 
 @property(nonatomic, assign) BOOL incognito;
+@property(nonatomic, weak) id<AutocompleteResultConsumerDelegate> delegate;
+@property(nonatomic, weak) id<ImageRetriever> imageRetriever;
 
-// Designated initializer.  Creates a table view with UITableViewStylePlain.
-// Takes ownership of |imageFetcher|.
-- (instancetype)
-initWithFetcher:
-    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)imageFetcher
-       delegate:(OmniboxPopupMaterialViewControllerDelegate*)delegate;
-
-// Updates the current data and forces a redraw. If animation is YES, adds
-// CALayer animations to fade the OmniboxPopupMaterialRows in.
-- (void)updateMatches:(const AutocompleteResult&)result
-        withAnimation:(BOOL)animation;
+- (instancetype)init NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
+- (instancetype)initWithStyle:(UITableViewStyle)style NS_UNAVAILABLE;
+- (instancetype)initWithNibName:(NSString*)nibNameOrNil
+                         bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
 
 // Set text alignment for popup cells.
 - (void)setTextAlignment:(NSTextAlignment)alignment;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
index 3862902..8d44405 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.mm
@@ -7,17 +7,8 @@
 #include <memory>
 
 #include "base/ios/ios_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
-#include "components/omnibox/browser/autocomplete_input.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/autocomplete_result.h"
-#include "components/omnibox/browser/suggestion_answer.h"
 #include "ios/chrome/browser/ui/animation_util.h"
+#import "ios/chrome/browser/ui/omnibox/image_retriever.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #import "ios/chrome/browser/ui/omnibox/truncating_attributed_label.h"
@@ -25,8 +16,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "net/base/escape.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -37,28 +26,6 @@
 const CGFloat kRowHeight = 48.0;
 const CGFloat kAnswerRowHeight = 64.0;
 const CGFloat kTopAndBottomPadding = 8.0;
-// The color of the main text of a suggest cell.
-UIColor* SuggestionTextColor() {
-  return [UIColor colorWithWhite:(51 / 255.0) alpha:1.0];
-}
-// The color of the detail text of a suggest cell.
-UIColor* SuggestionDetailTextColor() {
-  return [UIColor colorWithRed:(85 / 255.0)
-                         green:(149 / 255.0)
-                          blue:(254 / 255.0)
-                         alpha:1.0];
-}
-// The color of the text in the portion of a search suggestion that matches the
-// omnibox input text.
-UIColor* DimColor() {
-  return [UIColor colorWithWhite:(161 / 255.0) alpha:1.0];
-}
-UIColor* SuggestionTextColorIncognito() {
-  return [UIColor whiteColor];
-}
-UIColor* DimColorIncognito() {
-  return [UIColor whiteColor];
-}
 UIColor* BackgroundColorTablet() {
   return [UIColor whiteColor];
 }
@@ -80,39 +47,28 @@
   // Alignment of omnibox text. Popup text should match this alignment.
   NSTextAlignment _alignment;
 
-  OmniboxPopupMaterialViewControllerDelegate* _delegate;  // weak
-
-  // Fetcher for Answers in Suggest images.
-  std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> imageFetcher_;
-
-  // The data source.
-  AutocompleteResult _currentResult;
+  NSArray<id<AutocompleteSuggestion>>* _currentResult;
 
   // Array containing the OmniboxPopupMaterialRow objects displayed in the view.
   NSArray* _rows;
 
   // The height of the keyboard. Used to determine the content inset for the
   // scroll view.
-  CGFloat keyboardHeight_;
+  CGFloat _keyboardHeight;
 }
 
 @end
 
 @implementation OmniboxPopupMaterialViewController
-
+@synthesize delegate = _delegate;
 @synthesize incognito = _incognito;
+@synthesize imageRetriever = _imageRetriever;
 
 #pragma mark -
 #pragma mark Initialization
 
-- (instancetype)
-initWithFetcher:
-    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)imageFetcher
-       delegate:(OmniboxPopupMaterialViewControllerDelegate*)delegate {
-  if ((self = [super init])) {
-    _delegate = delegate;
-    imageFetcher_ = std::move(imageFetcher);
-
+- (instancetype)init {
+  if ((self = [super initWithStyle:UITableViewStylePlain])) {
     if (IsIPadIdiom()) {
       // The iPad keyboard can cover some of the rows of the scroll view. The
       // scroll view's content inset may need to be updated when the keyboard is
@@ -192,11 +148,24 @@
   [self layoutRows];
 }
 
+#pragma mark - AutocompleteResultConsumer
+
+- (void)updateMatches:(NSArray<id<AutocompleteSuggestion>>*)result
+        withAnimation:(BOOL)animation {
+  _currentResult = result;
+  [self layoutRows];
+
+  size_t size = _currentResult.count;
+  if (animation && size > 0) {
+    [self fadeInRows];
+  }
+}
+
 #pragma mark -
 #pragma mark Updating data and UI
 
 - (void)updateRow:(OmniboxPopupMaterialRow*)row
-        withMatch:(const AutocompleteMatch&)match {
+        withMatch:(id<AutocompleteSuggestion>)match {
   const CGFloat kTextCellLeadingPadding =
       IsIPadIdiom() ? (!IsCompactTablet() ? 192 : 100) : 16;
   const CGFloat kTextCellTopPadding = 6;
@@ -213,23 +182,15 @@
 
   BOOL LTRTextInRTLLayout = _alignment == NSTextAlignmentLeft && UseRTLLayout();
 
-  row.rowHeight = [self hasAnswer:match] ? kAnswerRowHeight : kRowHeight;
+  row.rowHeight = match.hasAnswer ? kAnswerRowHeight : kRowHeight;
 
   // Fetch the answer image if specified.  Currently, no answer types specify an
   // image on the first line so for now we only look at the second line.
-  if ([self hasImage:match]) {
-    image_fetcher::IOSImageDataFetcherCallback callback =
-        ^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
-          if (data) {
-            UIImage* image =
-                [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
-            if (image) {
-              row.answerImageView.image = image;
-            }
-          }
-        };
-    imageFetcher_->FetchImageDataWebpDecoded([self imageURL:match], callback);
-
+  if (match.hasImage) {
+    [self.imageRetriever fetchImage:match.imageURL
+                         completion:^(UIImage* image) {
+                           row.answerImageView.image = image;
+                         }];
     // Answers in suggest do not support RTL, left align only.
     CGFloat imageLeftPadding =
         kTextCellLeadingPadding + kAnswerImageLeftPadding;
@@ -252,26 +213,26 @@
   // For the detail text label, we use either the regular detail label, which
   // truncates by fading, or the answer label, which uses UILabel's standard
   // truncation by ellipse for the multi-line text sometimes shown in answers.
-  row.detailTruncatingLabel.hidden = [self hasAnswer:match];
-  row.detailAnswerLabel.hidden = ![self hasAnswer:match];
+  row.detailTruncatingLabel.hidden = match.hasAnswer;
+  row.detailAnswerLabel.hidden = !match.hasAnswer;
   // URLs have have special layout requirements that need to be invoked here.
-  row.detailTruncatingLabel.displayAsURL = [self isURL:match];
+  row.detailTruncatingLabel.displayAsURL = match.isURL;
 
   // TODO(crbug.com/697647): The complexity of managing these two separate
   // labels could probably be encapusulated in the row class if we moved the
   // layout logic there.
-  UILabel* detailTextLabel = [self hasAnswer:match] ? row.detailAnswerLabel
-                                                    : row.detailTruncatingLabel;
+  UILabel* detailTextLabel =
+      match.hasAnswer ? row.detailAnswerLabel : row.detailTruncatingLabel;
   [detailTextLabel setTextAlignment:_alignment];
 
   // The width must be positive for CGContextRef to be valid.
   CGFloat labelWidth =
       MAX(40, floorf(row.frame.size.width) - kTextCellLeadingPadding);
   CGFloat labelHeight =
-      [self hasAnswer:match] ? kAnswerLabelHeight : kTextDetailLabelHeight;
+      match.hasAnswer ? kAnswerLabelHeight : kTextDetailLabelHeight;
   CGFloat answerImagePadding = kAnswerImageWidth + kAnswerImageRightPadding;
   CGFloat leadingPadding =
-      ([self hasImage:match] && !alignmentRight ? answerImagePadding : 0) +
+      (match.hasImage && !alignmentRight ? answerImagePadding : 0) +
       kTextCellLeadingPadding;
 
   LayoutRect detailTextLabelLayout =
@@ -279,11 +240,11 @@
                      kDetailCellTopPadding, labelWidth, labelHeight);
   detailTextLabel.frame = LayoutRectGetRect(detailTextLabelLayout);
 
-  detailTextLabel.attributedText = [self detailText:match];
+  detailTextLabel.attributedText = match.detailText;
 
   // Set detail text label number of lines
-  if ([self hasAnswer:match]) {
-    detailTextLabel.numberOfLines = [self numberOfLines:match];
+  if (match.hasAnswer) {
+    detailTextLabel.numberOfLines = match.numberOfLines;
   }
 
   [detailTextLabel setNeedsDisplay];
@@ -296,10 +257,10 @@
   textLabel.frame = LayoutRectGetRect(textLabelLayout);
 
   // Set the text.
-  textLabel.attributedText = [self text:match];
+  textLabel.attributedText = match.text;
 
   // Center the textLabel if detailLabel is empty.
-  if (![self hasAnswer:match] && [[self detailText:match] length] == 0) {
+  if (!match.hasAnswer && [match.detailText length] == 0) {
     textLabel.center = CGPointMake(textLabel.center.x, floor(kRowHeight / 2));
     textLabel.frame = AlignRectToPixel(textLabel.frame);
   } else {
@@ -313,17 +274,17 @@
   // The leading image (e.g. magnifying glass, star, clock) is only shown on
   // iPad.
   if (IsIPadIdiom()) {
-    [row updateLeadingImage:[self imageId:match]];
+    [row updateLeadingImage:match.imageID];
   }
 
   // Show append button for search history/search suggestions/Physical Web as
   // the right control element (aka an accessory element of a table view cell).
-  row.appendButton.hidden = ![self isAppendable:match];
+  row.appendButton.hidden = !match.isAppendable;
   [row.appendButton cancelTrackingWithEvent:nil];
 
   // If a right accessory element is present or the text alignment is right
   // aligned, adjust the width to align with the accessory element.
-  if ([self isAppendable:match] || alignmentRight) {
+  if (match.isAppendable || alignmentRight) {
     LayoutRect layout =
         LayoutRectForRectInBoundingRect(textLabel.frame, self.view.frame);
     layout.size.width -= kAppendButtonWidth;
@@ -331,7 +292,7 @@
     layout =
         LayoutRectForRectInBoundingRect(detailTextLabel.frame, self.view.frame);
     layout.size.width -=
-        kAppendButtonWidth + ([self hasImage:match] ? answerImagePadding : 0);
+        kAppendButtonWidth + (match.hasImage ? answerImagePadding : 0);
     detailTextLabel.frame = LayoutRectGetRect(layout);
   }
 
@@ -354,142 +315,8 @@
   }
 }
 
-- (NSMutableAttributedString*)attributedStringWithAnswerLine:
-    (const SuggestionAnswer::ImageLine&)line {
-  NSMutableAttributedString* result =
-      [[NSMutableAttributedString alloc] initWithString:@""];
-
-  for (size_t i = 0; i < line.text_fields().size(); i++) {
-    const SuggestionAnswer::TextField& field = line.text_fields()[i];
-    [result
-        appendAttributedString:[self attributedStringWithString:field.text()
-                                                           type:field.type()]];
-  }
-
-  NSAttributedString* spacer =
-      [[NSAttributedString alloc] initWithString:@"  "];
-  if (line.additional_text() != nil) {
-    const SuggestionAnswer::TextField* field = line.additional_text();
-    [result appendAttributedString:spacer];
-    [result
-        appendAttributedString:[self attributedStringWithString:field->text()
-                                                           type:field->type()]];
-  }
-
-  if (line.status_text() != nil) {
-    const SuggestionAnswer::TextField* field = line.status_text();
-    [result appendAttributedString:spacer];
-    [result
-        appendAttributedString:[self attributedStringWithString:field->text()
-                                                           type:field->type()]];
-  }
-
-  return result;
-}
-
-- (NSAttributedString*)attributedStringWithString:(const base::string16&)string
-                                             type:(int)type {
-  NSDictionary* attributes = nil;
-
-  const id font = (id)NSFontAttributeName;
-  NSString* foregroundColor = (NSString*)NSForegroundColorAttributeName;
-  const id baselineOffset = (id)NSBaselineOffsetAttributeName;
-
-  // Answer types, sizes and colors specified at http://goto.google.com/ais_api.
-  switch (type) {
-    case SuggestionAnswer::TOP_ALIGNED:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:12],
-        baselineOffset : @10.0f,
-        foregroundColor : [UIColor grayColor],
-      };
-      break;
-    case SuggestionAnswer::DESCRIPTION_POSITIVE:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:16],
-        foregroundColor : [UIColor colorWithRed:11 / 255.0
-                                          green:128 / 255.0
-                                           blue:67 / 255.0
-                                          alpha:1.0],
-      };
-      break;
-    case SuggestionAnswer::DESCRIPTION_NEGATIVE:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:16],
-        foregroundColor : [UIColor colorWithRed:197 / 255.0
-                                          green:57 / 255.0
-                                           blue:41 / 255.0
-                                          alpha:1.0],
-      };
-      break;
-    case SuggestionAnswer::PERSONALIZED_SUGGESTION:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:16],
-      };
-      break;
-    case SuggestionAnswer::ANSWER_TEXT_MEDIUM:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:20],
-        foregroundColor : [UIColor grayColor],
-      };
-      break;
-    case SuggestionAnswer::ANSWER_TEXT_LARGE:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:24],
-        foregroundColor : [UIColor grayColor],
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:12],
-        foregroundColor : [UIColor grayColor],
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_MEDIUM:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:14],
-        foregroundColor : [UIColor grayColor],
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION:
-    // Fall through.
-    default:
-      attributes = @{
-        font : [[MDCTypography fontLoader] regularFontOfSize:16],
-      };
-  }
-
-  NSString* unescapedString =
-      base::SysUTF16ToNSString(net::UnescapeForHTML(string));
-  // TODO(jdonnelly): Remove this tag stripping once the JSON parsing class
-  // handles HTML tags.
-  unescapedString = [unescapedString stringByReplacingOccurrencesOfString:@"<b>"
-                                                               withString:@""];
-  unescapedString =
-      [unescapedString stringByReplacingOccurrencesOfString:@"</b>"
-                                                 withString:@""];
-
-  return [[NSAttributedString alloc] initWithString:unescapedString
-                                         attributes:attributes];
-}
-
-- (void)updateMatches:(const AutocompleteResult&)result
-        withAnimation:(BOOL)animation {
-  AutocompleteResult oldResults;
-  AutocompleteInput emptyInput;
-  oldResults.Swap(&_currentResult);
-  _currentResult.CopyOldMatches(emptyInput, result, nil);
-
-  [self layoutRows];
-
-  size_t size = _currentResult.size();
-  if (animation && size > 0) {
-    [self fadeInRows];
-  }
-}
-
 - (void)layoutRows {
-  size_t size = _currentResult.size();
+  size_t size = _currentResult.count;
 
   [self.tableView reloadData];
   [self.tableView beginUpdates];
@@ -497,9 +324,7 @@
     OmniboxPopupMaterialRow* row = _rows[i];
 
     if (i < size) {
-      const AutocompleteMatch& match =
-          ((const AutocompleteResult&)_currentResult).match_at((NSUInteger)i);
-      [self updateRow:row withMatch:match];
+      [self updateRow:row withMatch:_currentResult[i]];
       row.hidden = NO;
     } else {
       row.hidden = YES;
@@ -515,7 +340,7 @@
   NSDictionary* keyboardInfo = [notification userInfo];
   NSValue* keyboardFrameValue =
       [keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey];
-  keyboardHeight_ = CurrentKeyboardHeight(keyboardFrameValue);
+  _keyboardHeight = CurrentKeyboardHeight(keyboardFrameValue);
   if (self.tableView.contentSize.height > 0)
     [self updateContentInsetForKeyboard];
 }
@@ -527,7 +352,7 @@
       [self.tableView convertRect:self.tableView.bounds toView:toView];
   CGFloat screenHeight = CurrentScreenHeight();
   CGFloat bottomInset = screenHeight - self.tableView.contentSize.height -
-                        keyboardHeight_ - absoluteRect.origin.y -
+                        _keyboardHeight - absoluteRect.origin.y -
                         kTopAndBottomPadding * 2;
   bottomInset = MAX(kTopAndBottomPadding, -bottomInset);
   self.tableView.contentInset =
@@ -572,18 +397,7 @@
 
 - (void)appendButtonTapped:(id)sender {
   NSUInteger row = [sender tag];
-  const AutocompleteMatch& match =
-      ((const AutocompleteResult&)_currentResult).match_at(row);
-
-  if (AutocompleteMatch::IsSearchType(match.type)) {
-    base::RecordAction(
-        base::UserMetricsAction("MobileOmniboxRefineSuggestion.Search"));
-  } else {
-    base::RecordAction(
-        base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url"));
-  }
-
-  _delegate->OnMatchSelectedForAppending(match);
+  [self.delegate autocompleteResultConsumer:self didSelectRowForAppending:row];
 }
 
 #pragma mark -
@@ -603,7 +417,7 @@
       return;
   }
 
-  _delegate->OnScroll();
+  [self.delegate autocompleteResultConsumerDidScroll:self];
   for (OmniboxPopupMaterialRow* row in _rows) {
     row.highlighted = NO;
   }
@@ -614,76 +428,21 @@
   _alignment = alignment;
 }
 
-- (NSMutableAttributedString*)
-attributedStringWithString:(NSString*)text
-           classifications:(const ACMatchClassifications*)classifications
-                 smallFont:(BOOL)smallFont
-                     color:(UIColor*)defaultColor
-                  dimColor:(UIColor*)dimColor {
-  if (text == nil)
-    return nil;
-
-  UIFont* fontRef =
-      smallFont ? [MDCTypography body1Font] : [MDCTypography subheadFont];
-
-  NSMutableAttributedString* as =
-      [[NSMutableAttributedString alloc] initWithString:text];
-
-  // Set the base attributes to the default font and color.
-  NSDictionary* dict = @{
-    NSFontAttributeName : fontRef,
-    NSForegroundColorAttributeName : defaultColor,
-  };
-  [as addAttributes:dict range:NSMakeRange(0, [text length])];
-
-  if (classifications != NULL) {
-    UIFont* boldFontRef =
-        [[MDCTypography fontLoader] mediumFontOfSize:fontRef.pointSize];
-
-    for (ACMatchClassifications::const_iterator i = classifications->begin();
-         i != classifications->end(); ++i) {
-      const BOOL isLast = (i + 1) == classifications->end();
-      const size_t nextOffset = (isLast ? [text length] : (i + 1)->offset);
-      const NSInteger location = static_cast<NSInteger>(i->offset);
-      const NSInteger length = static_cast<NSInteger>(nextOffset - i->offset);
-      // Guard against bad, off-the-end classification ranges due to
-      // crbug.com/121703 and crbug.com/131370.
-      if (i->offset + length > [text length] || length <= 0)
-        break;
-      const NSRange range = NSMakeRange(location, length);
-      if (0 != (i->style & ACMatchClassification::MATCH)) {
-        [as addAttribute:NSFontAttributeName value:boldFontRef range:range];
-      }
-
-      if (0 != (i->style & ACMatchClassification::DIM)) {
-        [as addAttribute:NSForegroundColorAttributeName
-                   value:dimColor
-                   range:range];
-      }
-    }
-  }
-  return as;
-}
-
 #pragma mark -
 #pragma mark Table view delegate
 
 - (void)tableView:(UITableView*)tableView
     didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
   DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.size());
+  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.count);
   NSUInteger row = indexPath.row;
 
   // Crash reports tell us that |row| is sometimes indexed past the end of
   // the results array. In those cases, just ignore the request and return
   // early. See b/5813291.
-  if (row >= _currentResult.size())
+  if (row >= _currentResult.count)
     return;
-
-  const AutocompleteMatch& match =
-      ((const AutocompleteResult&)_currentResult).match_at(row);
-
-  _delegate->OnMatchSelected(match, row);
+  [self.delegate autocompleteResultConsumer:self didSelectRow:row];
 }
 
 #pragma mark -
@@ -692,7 +451,7 @@
 - (CGFloat)tableView:(UITableView*)tableView
     heightForRowAtIndexPath:(NSIndexPath*)indexPath {
   DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.size());
+  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.count);
   return ((OmniboxPopupMaterialRow*)(_rows[indexPath.row])).rowHeight;
 }
 
@@ -703,14 +462,14 @@
 - (NSInteger)tableView:(UITableView*)tableView
     numberOfRowsInSection:(NSInteger)section {
   DCHECK_EQ(0, section);
-  return _currentResult.size();
+  return _currentResult.count;
 }
 
 // Customize the appearance of table view cells.
 - (UITableViewCell*)tableView:(UITableView*)tableView
         cellForRowAtIndexPath:(NSIndexPath*)indexPath {
   DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.size());
+  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.count);
   return _rows[indexPath.row];
 }
 
@@ -720,139 +479,24 @@
   // iOS doesn't check -numberOfRowsInSection before checking
   // -canEditRowAtIndexPath in a reload call. If |indexPath.row| is too large,
   // simple return |NO|.
-  if ((NSUInteger)indexPath.row >= _currentResult.size())
+  if ((NSUInteger)indexPath.row >= _currentResult.count)
     return NO;
 
-  const AutocompleteMatch& match =
-      ((const AutocompleteResult&)_currentResult).match_at(indexPath.row);
-  return match.SupportsDeletion();
+  return [_currentResult[indexPath.row] supportsDeletion];
 }
 
 - (void)tableView:(UITableView*)tableView
     commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
      forRowAtIndexPath:(NSIndexPath*)indexPath {
   DCHECK_EQ(0U, (NSUInteger)indexPath.section);
-  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.size());
+  DCHECK_LT((NSUInteger)indexPath.row, _currentResult.count);
   if (editingStyle == UITableViewCellEditingStyleDelete) {
     // The delete button never disappears if you don't call this after a tap.
     // It doesn't seem to be required anywhere else.
     [_rows[indexPath.row] prepareForReuse];
-    const AutocompleteMatch& match =
-        ((const AutocompleteResult&)_currentResult).match_at(indexPath.row);
-    _delegate->OnMatchSelectedForDeletion(match);
+    [self.delegate autocompleteResultConsumer:self
+                      didSelectRowForDeletion:indexPath.row];
   }
 }
 
-- (BOOL)hasAnswer:(const AutocompleteMatch&)match {
-  return match.answer.get() != nil;
-}
-
-- (BOOL)hasImage:(const AutocompleteMatch&)match {
-  return [self hasAnswer:match] &&
-         match.answer->second_line().image_url().is_valid();
-}
-
-- (BOOL)isURL:(const AutocompleteMatch&)match {
-  return !AutocompleteMatch::IsSearchType(match.type);
-}
-
-- (NSAttributedString*)detailText:(const AutocompleteMatch&)match {
-  // The detail text should be the URL (|match.contents|) for non-search
-  // suggestions and the entity type (|match.description|) for search entity
-  // suggestions. For all other search suggestions, |match.description| is the
-  // name of the currently selected search engine, which for mobile we suppress.
-  NSString* detailText = nil;
-  if ([self isURL:match])
-    detailText = base::SysUTF16ToNSString(match.contents);
-  else if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY)
-    detailText = base::SysUTF16ToNSString(match.description);
-
-  NSAttributedString* detailAttributedText = nil;
-  if ([self hasAnswer:match]) {
-    detailAttributedText =
-        [self attributedStringWithAnswerLine:match.answer->second_line()];
-  } else {
-    const ACMatchClassifications* classifications =
-        [self isURL:match] ? &match.contents_class : nil;
-    // The suggestion detail color should match the main text color for entity
-    // suggestions. For non-search suggestions (URLs), a highlight color is used
-    // instead.
-    UIColor* suggestionDetailTextColor = nil;
-    if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY) {
-      suggestionDetailTextColor =
-          _incognito ? SuggestionTextColorIncognito() : SuggestionTextColor();
-    } else {
-      suggestionDetailTextColor = SuggestionDetailTextColor();
-    }
-    DCHECK(suggestionDetailTextColor);
-    detailAttributedText =
-        [self attributedStringWithString:detailText
-                         classifications:classifications
-                               smallFont:YES
-                                   color:suggestionDetailTextColor
-                                dimColor:DimColor()];
-  }
-  return detailAttributedText;
-}
-
-- (NSInteger)numberOfLines:(const AutocompleteMatch&)match {
-  // Answers specify their own limit on the number of lines to show but we
-  // additionally cap this at 3 to guard against unreasonable values.
-  const SuggestionAnswer::TextField& first_text_field =
-      match.answer->second_line().text_fields()[0];
-  if (first_text_field.has_num_lines() && first_text_field.num_lines() > 1)
-    return MIN(3, first_text_field.num_lines());
-  else
-    return 1;
-}
-
-- (NSAttributedString*)text:(const AutocompleteMatch&)match {
-  // The text should be search term (|match.contents|) for searches, otherwise
-  // page title (|match.description|).
-  base::string16 textString =
-      ![self isURL:match] ? match.contents : match.description;
-  NSString* text = base::SysUTF16ToNSString(textString);
-
-  // If for some reason the title is empty, copy the detailText.
-  if ([text length] == 0 && [[self detailText:match] length] != 0) {
-    text = [[self detailText:match] string];
-  }
-
-  NSAttributedString* attributedText = nil;
-
-  if ([self hasAnswer:match]) {
-    attributedText =
-        [self attributedStringWithAnswerLine:match.answer->first_line()];
-  } else {
-    const ACMatchClassifications* textClassifications =
-        ![self isURL:match] ? &match.contents_class : &match.description_class;
-    UIColor* suggestionTextColor =
-        _incognito ? SuggestionTextColorIncognito() : SuggestionTextColor();
-    UIColor* dimColor = _incognito ? DimColorIncognito() : DimColor();
-
-    attributedText = [self attributedStringWithString:text
-                                      classifications:textClassifications
-                                            smallFont:NO
-                                                color:suggestionTextColor
-                                             dimColor:dimColor];
-  }
-  return attributedText;
-}
-
-- (BOOL)isAppendable:(const AutocompleteMatch&)match {
-  return match.type == AutocompleteMatchType::SEARCH_HISTORY ||
-         match.type == AutocompleteMatchType::SEARCH_SUGGEST ||
-         match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY ||
-         match.type == AutocompleteMatchType::PHYSICAL_WEB;
-}
-
-- (GURL)imageURL:(const AutocompleteMatch&)match {
-  return match.answer->second_line().image_url();
-}
-
-- (int)imageId:(const AutocompleteMatch&)match {
-  return GetIconForAutocompleteMatchType(
-      match.type, _delegate->IsStarredMatch(match), _incognito);
-}
-
 @end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h
new file mode 100644
index 0000000..61aa7520
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MEDIATOR_H_
+
+#import <UIKit/UIKit.h>
+#include "components/omnibox/browser/autocomplete_result.h"
+
+#import "ios/chrome/browser/ui/omnibox/autocomplete_result_consumer.h"
+#import "ios/chrome/browser/ui/omnibox/image_retriever.h"
+
+namespace image_fetcher {
+class IOSImageDataFetcherWrapper;
+}  // namespace
+
+class OmniboxPopupMediatorDelegate {
+ public:
+  virtual bool IsStarredMatch(const AutocompleteMatch& match) const = 0;
+  virtual void OnMatchSelected(const AutocompleteMatch& match, size_t row) = 0;
+  virtual void OnMatchSelectedForAppending(const AutocompleteMatch& match) = 0;
+  virtual void OnMatchSelectedForDeletion(const AutocompleteMatch& match) = 0;
+  virtual void OnScroll() = 0;
+};
+
+@interface OmniboxPopupMediator
+    : NSObject<AutocompleteResultConsumerDelegate, ImageRetriever>
+
+// Designated initializer. Takes ownership of |imageFetcher|.
+- (instancetype)initWithFetcher:
+                    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)
+                        imageFetcher
+                       delegate:(OmniboxPopupMediatorDelegate*)delegate;
+
+- (void)updateMatches:(const AutocompleteResult&)result
+        withAnimation:(BOOL)animated;
+
+@property(nonatomic, weak) id<AutocompleteResultConsumer> consumer;
+@property(nonatomic, assign, getter=isIncognito) BOOL incognito;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_POPUP_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.mm
new file mode 100644
index 0000000..be0ca239
--- /dev/null
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.mm
@@ -0,0 +1,128 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h"
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#import "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
+#include "components/omnibox/browser/autocomplete_input.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/autocomplete_result.h"
+#import "ios/chrome/browser/ui/omnibox/autocomplete_match_formatter.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation OmniboxPopupMediator {
+  // Fetcher for Answers in Suggest images.
+  std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper> _imageFetcher;
+
+  OmniboxPopupMediatorDelegate* _delegate;  // weak
+
+  AutocompleteResult _currentResult;
+}
+@synthesize consumer = _consumer;
+@synthesize incognito = _incognito;
+
+- (instancetype)initWithFetcher:
+                    (std::unique_ptr<image_fetcher::IOSImageDataFetcherWrapper>)
+                        imageFetcher
+                       delegate:(OmniboxPopupMediatorDelegate*)delegate {
+  self = [super init];
+  if (self) {
+    DCHECK(delegate);
+    _delegate = delegate;
+    _imageFetcher = std::move(imageFetcher);
+  }
+  return self;
+}
+
+- (void)updateMatches:(const AutocompleteResult&)result
+        withAnimation:(BOOL)animation {
+  AutocompleteResult oldResults;
+  AutocompleteInput emptyInput;
+  oldResults.Swap(&_currentResult);
+  _currentResult.CopyOldMatches(emptyInput, result, nil);
+
+  [self.consumer updateMatches:[self wrappedMatches] withAnimation:animation];
+}
+
+- (NSArray<id<AutocompleteSuggestion>>*)wrappedMatches {
+  NSMutableArray<id<AutocompleteSuggestion>>* wrappedMatches =
+      [[NSMutableArray alloc] init];
+
+  size_t size = _currentResult.size();
+  for (size_t i = 0; i < size; i++) {
+    const AutocompleteMatch& match =
+        ((const AutocompleteResult&)_currentResult).match_at((NSUInteger)i);
+    AutocompleteMatchFormatter* formatter =
+        [AutocompleteMatchFormatter formatterWithMatch:match];
+    formatter.starred = _delegate->IsStarredMatch(match);
+    formatter.incognito = _incognito;
+    [wrappedMatches addObject:formatter];
+  }
+
+  return wrappedMatches;
+}
+
+#pragma mark - AutocompleteResultConsumerDelegate
+
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+                      didSelectRow:(NSUInteger)row {
+  // OpenMatch() may close the popup, which will clear the result set and, by
+  // extension, |match| and its contents.  So copy the relevant match out to
+  // make sure it stays alive until the call completes.
+  const AutocompleteMatch& match =
+      ((const AutocompleteResult&)_currentResult).match_at(row);
+
+  _delegate->OnMatchSelected(match, row);
+}
+
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+          didSelectRowForAppending:(NSUInteger)row {
+  const AutocompleteMatch& match =
+      ((const AutocompleteResult&)_currentResult).match_at(row);
+
+  if (AutocompleteMatch::IsSearchType(match.type)) {
+    base::RecordAction(
+        base::UserMetricsAction("MobileOmniboxRefineSuggestion.Search"));
+  } else {
+    base::RecordAction(
+        base::UserMetricsAction("MobileOmniboxRefineSuggestion.Url"));
+  }
+
+  _delegate->OnMatchSelectedForAppending(match);
+}
+
+- (void)autocompleteResultConsumer:(id<AutocompleteResultConsumer>)sender
+           didSelectRowForDeletion:(NSUInteger)row {
+  const AutocompleteMatch& match =
+      ((const AutocompleteResult&)_currentResult).match_at(row);
+  _delegate->OnMatchSelectedForDeletion(match);
+}
+
+- (void)autocompleteResultConsumerDidScroll:
+    (id<AutocompleteResultConsumer>)sender {
+  _delegate->OnScroll();
+}
+
+#pragma mark - ImageFetcher
+
+- (void)fetchImage:(GURL)imageURL completion:(void (^)(UIImage*))completion {
+  image_fetcher::IOSImageDataFetcherCallback callback =
+      ^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
+        if (data) {
+          UIImage* image =
+              [UIImage imageWithData:data scale:[UIScreen mainScreen].scale];
+          completion(image);
+        } else {
+          completion(nil);
+        }
+      };
+  _imageFetcher->FetchImageDataWebpDecoded(imageURL, callback);
+}
+
+@end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
index b191ffaf..53a25468 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.h
@@ -13,6 +13,7 @@
 #include "base/strings/string16.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h"
 
 class OmniboxEditModel;
 @class OmniboxPopupMaterialViewController;
@@ -28,7 +29,7 @@
 
 // iOS implementation of AutocompletePopupView.
 class OmniboxPopupViewIOS : public OmniboxPopupView,
-                            public OmniboxPopupMaterialViewControllerDelegate {
+                            public OmniboxPopupMediatorDelegate {
  public:
   OmniboxPopupViewIOS(ios::ChromeBrowserState* browser_state,
                       OmniboxEditModel* edit_model,
@@ -59,6 +60,7 @@
  private:
   std::unique_ptr<OmniboxPopupModel> model_;
   OmniboxPopupViewSuggestionsDelegate* delegate_;  // weak
+  base::scoped_nsobject<OmniboxPopupMediator> mediator_;
   base::scoped_nsobject<OmniboxPopupPresenter> presenter_;
   base::scoped_nsobject<OmniboxPopupMaterialViewController> popup_controller_;
   bool is_open_;
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
index 25af248..88113ac 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
@@ -20,6 +20,7 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_material_view_controller.h"
+#import "ios/chrome/browser/ui/omnibox/omnibox_popup_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_popup_presenter.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_popup_view_suggestions_delegate.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
@@ -52,10 +53,17 @@
       base::MakeUnique<image_fetcher::IOSImageDataFetcherWrapper>(
           browser_state->GetRequestContext());
 
-  popup_controller_.reset([[OmniboxPopupMaterialViewController alloc]
+  mediator_.reset([[OmniboxPopupMediator alloc]
       initWithFetcher:std::move(imageFetcher)
              delegate:this]);
+  popup_controller_.reset([[OmniboxPopupMaterialViewController alloc] init]);
   [popup_controller_ setIncognito:browser_state->IsOffTheRecord()];
+
+  [mediator_ setIncognito:browser_state->IsOffTheRecord()];
+  [mediator_ setConsumer:popup_controller_];
+  [popup_controller_ setImageRetriever:mediator_];
+  [popup_controller_ setDelegate:mediator_];
+
   presenter_.reset([[OmniboxPopupPresenter alloc]
       initWithPopupPositioner:positioner
           popupViewController:popup_controller_]);
@@ -79,14 +87,15 @@
 void OmniboxPopupViewIOS::UpdatePopupAppearance() {
   const AutocompleteResult& result = model_->result();
 
+  // TODO(crbug.com/762597): this logic should move to PopupCoordinator.
   if (!is_open_ && !result.empty()) {
     // The popup is not currently open and there are results to display. Update
     // and animate the cells
-    [popup_controller_ updateMatches:result withAnimation:YES];
+    [mediator_ updateMatches:result withAnimation:YES];
   } else {
     // The popup is already displayed or there are no results to display. Update
     // the cells without animating.
-    [popup_controller_ updateMatches:result withAnimation:NO];
+    [mediator_ updateMatches:result withAnimation:NO];
   }
   is_open_ = !result.empty();
 
diff --git a/ios/chrome/browser/ui/payments/cells/page_info_item.mm b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
index f56a5596a..e908829 100644
--- a/ios/chrome/browser/ui/payments/cells/page_info_item.mm
+++ b/ios/chrome/browser/ui/payments/cells/page_info_item.mm
@@ -37,6 +37,9 @@
 // Dimension for lock indicator in points.
 const CGFloat kLockIndicatorDimension = 16;
 
+// Dimension for the favicon in points.
+const CGFloat kFaviconDimension = 16;
+
 // There is some empty space between the left and right edges of the lock
 // indicator image contents and the square box it is contained within.
 // This padding represents that difference. This is useful when it comes
@@ -153,10 +156,6 @@
         setTintColor:[[MDCPalette cr_greenPalette] tint700]];
     [self.contentView addSubview:_pageLockIndicatorView];
 
-    CGFloat faviconHeight = _pageTitleLabel.font.pointSize +
-                            _pageHostLabel.font.pointSize +
-                            kLabelsVerticalSpacing;
-
     // Layout
     [NSLayoutConstraint activateConstraints:@[
       [_pageFaviconView.leadingAnchor
@@ -164,7 +163,8 @@
                          constant:kHorizontalPadding],
       [_pageFaviconView.centerYAnchor
           constraintEqualToAnchor:self.contentView.centerYAnchor],
-      [_pageFaviconView.heightAnchor constraintEqualToConstant:faviconHeight],
+      [_pageFaviconView.heightAnchor
+          constraintEqualToConstant:kFaviconDimension],
       [_pageFaviconView.widthAnchor
           constraintEqualToAnchor:_pageFaviconView.heightAnchor],
 
diff --git a/ios/chrome/browser/ui/promos/signin_promo_view_controller.h b/ios/chrome/browser/ui/promos/signin_promo_view_controller.h
index ee254ad..b05714a 100644
--- a/ios/chrome/browser/ui/promos/signin_promo_view_controller.h
+++ b/ios/chrome/browser/ui/promos/signin_promo_view_controller.h
@@ -9,7 +9,7 @@
 
 #import "ios/chrome/browser/ui/authentication/chrome_signin_view_controller.h"
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 namespace ios {
 class ChromeBrowserState;
 }
@@ -31,8 +31,7 @@
 
 // Designated initializer.  |browserState| must not be nil.
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher;
+                          dispatcher:(id<ApplicationCommands>)dispatcher;
 
 // Records in user defaults that the promo has been shown along with the current
 // version number.
diff --git a/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm b/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm
index d777956..e1a12f8a 100644
--- a/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm
+++ b/ios/chrome/browser/ui/promos/signin_promo_view_controller.mm
@@ -63,8 +63,7 @@
 }
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
-                          dispatcher:
-                              (id<ApplicationSettingsCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher {
   self = [super initWithBrowserState:browserState
                isPresentedOnSettings:NO
                          accessPoint:signin_metrics::AccessPoint::
diff --git a/ios/chrome/browser/ui/settings/accounts_collection_egtest.mm b/ios/chrome/browser/ui/settings/accounts_collection_egtest.mm
index 71e2ed3..654fbf46 100644
--- a/ios/chrome/browser/ui/settings/accounts_collection_egtest.mm
+++ b/ios/chrome/browser/ui/settings/accounts_collection_egtest.mm
@@ -8,7 +8,10 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/signin/authentication_service.h"
+#import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
+#import "ios/chrome/browser/ui/authentication/account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -18,6 +21,7 @@
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
+#include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -278,4 +282,34 @@
       performAction:grey_tap()];
 }
 
+- (void)testMDMError {
+  ChromeIdentity* identity = [SigninEarlGreyUtils fakeIdentity1];
+  ios::FakeChromeIdentityService* fakeChromeIdentityService =
+      ios::FakeChromeIdentityService::GetInstanceFromChromeProvider();
+  fakeChromeIdentityService->AddIdentity(identity);
+  fakeChromeIdentityService->SetFakeMDMError(true);
+
+  [ChromeEarlGreyUI openSettingsMenu];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SecondarySignInButton()];
+  [[EarlGrey selectElementWithMatcher:ButtonWithIdentity(identity)]
+      performAction:grey_tap()];
+  AcceptAccountConsistencyPopup();
+  [SigninEarlGreyUtils assertSignedInWithIdentity:identity];
+  [ChromeEarlGreyUI tapSettingsMenuButton:SettingsAccountButton()];
+
+  // Check that account sync button display the sync error.
+  GREYPerformBlock block = ^(id element, NSError* __strong* errorOrNil) {
+    GREYAssertTrue([element isKindOfClass:[AccountControlCell class]],
+                   @"Should be AccountControlCell type");
+    AccountControlCell* cell = static_cast<AccountControlCell*>(element);
+    NSString* expectedString =
+        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR);
+    return [cell.detailTextLabel.text isEqualToString:expectedString];
+  };
+  [[EarlGrey selectElementWithMatcher:AccountsSyncButton()]
+      performAction:[GREYActionBlock
+                        actionWithName:@"Invoke clearStateForTest selector"
+                          performBlock:block]];
+}
+
 @end
diff --git a/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
index e85b36f..958feff 100644
--- a/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/accounts_collection_view_controller.mm
@@ -282,6 +282,8 @@
   return item;
 }
 
+// Updates the sync item according to the sync status (in progress, sync error,
+// mdm error, sync disabled or sync enabled).
 - (void)updateSyncItem:(AccountControlItem*)syncItem {
   SyncSetupService* syncSetupService =
       SyncSetupServiceFactory::GetForBrowserState(_browserState);
@@ -294,22 +296,31 @@
   }
 
   ChromeIdentity* identity = [self authService]->GetAuthenticatedIdentity();
-  bool hasSyncError =
-      !IsTransientSyncError(syncSetupService->GetSyncServiceState());
-  bool hasMDMError = [self authService]->HasCachedMDMErrorForIdentity(identity);
-  if (hasSyncError || hasMDMError) {
-    syncItem.image = [UIImage imageNamed:@"settings_error"];
-    syncItem.detailText = GetSyncErrorDescriptionForBrowserState(_browserState);
+  if (!IsTransientSyncError(syncSetupService->GetSyncServiceState())) {
+    // Sync error.
     syncItem.shouldDisplayError = YES;
-  } else {
+    NSString* errorMessage =
+        GetSyncErrorDescriptionForBrowserState(_browserState);
+    DCHECK(errorMessage);
+    syncItem.detailText = errorMessage;
+  } else if ([self authService]->HasCachedMDMErrorForIdentity(identity)) {
+    // MDM error.
+    syncItem.shouldDisplayError = YES;
+    syncItem.detailText =
+        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_ERROR);
+  } else if (!syncSetupService->IsSyncEnabled()) {
+    // Sync disabled.
+    syncItem.shouldDisplayError = NO;
     syncItem.image = [UIImage imageNamed:@"settings_sync"];
     syncItem.detailText =
-        syncSetupService->IsSyncEnabled()
-            ? l10n_util::GetNSStringF(
-                  IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
-                  base::SysNSStringToUTF16([identity userEmail]))
-            : l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF);
+        l10n_util::GetNSString(IDS_IOS_OPTIONS_ACCOUNTS_SYNC_IS_OFF);
+  } else {
+    // Sync enabled.
     syncItem.shouldDisplayError = NO;
+    syncItem.image = [UIImage imageNamed:@"settings_sync"];
+    syncItem.detailText =
+        l10n_util::GetNSStringF(IDS_IOS_SIGN_IN_TO_CHROME_SETTING_SYNCING,
+                                base::SysNSStringToUTF16([identity userEmail]));
   }
 }
 
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
index 4ab2821..b055787 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -351,7 +351,8 @@
         _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
             initWithBrowserState:_browserState
                      accessPoint:signin_metrics::AccessPoint::
-                                     ACCESS_POINT_SETTINGS];
+                                     ACCESS_POINT_SETTINGS
+                      dispatcher:self.dispatcher];
         _signinPromoViewMediator.consumer = self;
         prefs->SetInteger(prefs::kIosSettingsSigninPromoDisplayedCount,
                           displayedCount + 1);
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index 6533afa..9002ab25 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -13,7 +13,6 @@
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/clear_browsing_data_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
-#import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/icons/chrome_icon.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #import "ios/chrome/browser/ui/material_components/app_bar_presenting.h"
@@ -464,11 +463,6 @@
 
 - (void)chromeExecuteCommand:(id)sender {
   switch ([sender tag]) {
-    case IDC_SHOW_SIGNIN_IOS:
-      // Sign-in actions can only happen on the main browser state (not on
-      // incognito browser state), which is unique. The command can just be
-      // forwarded up the responder chain.
-      break;
     case IDC_CLEAR_BROWSING_DATA_IOS: {
       // Check that the data for the right browser state is being cleared before
       // forwarding it up the responder chain.
diff --git a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm
index 9d30a351..3da9c40 100644
--- a/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync_settings_collection_view_controller.mm
@@ -34,7 +34,6 @@
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
@@ -594,11 +593,11 @@
   SyncSetupService::SyncServiceState syncState =
       GetSyncStateForBrowserState(_browserState);
   if (ShouldShowSyncSignin(syncState)) {
-    [self chromeExecuteCommand:
-              [[ShowSigninCommand alloc]
-                  initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
-                        accessPoint:signin_metrics::AccessPoint::
-                                        ACCESS_POINT_UNKNOWN]];
+    [self.dispatcher
+        showSignin:[[ShowSigninCommand alloc]
+                       initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
+                             accessPoint:signin_metrics::AccessPoint::
+                                             ACCESS_POINT_UNKNOWN]];
   } else if (ShouldShowSyncSettings(syncState)) {
     [self.dispatcher showSyncSettings];
   } else if (ShouldShowSyncPassphraseSettings(syncState)) {
diff --git a/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.h b/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.h
index 495a98a..36d1f27 100644
--- a/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.h
+++ b/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.h
@@ -15,7 +15,7 @@
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ui/gfx/image/image.h"
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class GenericChromeCommand;
 
 namespace gfx {
@@ -35,13 +35,13 @@
                                  public syncer::SyncServiceObserver {
  public:
   SyncErrorInfoBarDelegate(ios::ChromeBrowserState* browser_state,
-                           id<ApplicationSettingsCommands> dispatcher);
+                           id<ApplicationCommands> dispatcher);
   ~SyncErrorInfoBarDelegate() override;
 
   // Creates a sync error infobar and adds it to |infobar_manager|.
   static bool Create(infobars::InfoBarManager* infobar_manager,
                      ios::ChromeBrowserState* browser_state,
-                     id<ApplicationSettingsCommands> dispatcher);
+                     id<ApplicationCommands> dispatcher);
 
   // InfoBarDelegate implementation.
   InfoBarIdentifier GetIdentifier() const override;
@@ -63,7 +63,7 @@
   base::string16 message_;
   base::string16 button_text_;
   base::scoped_nsobject<GenericChromeCommand> command_;
-  id<ApplicationSettingsCommands> dispatcher_;
+  id<ApplicationCommands> dispatcher_;
 
   DISALLOW_COPY_AND_ASSIGN(SyncErrorInfoBarDelegate);
 };
diff --git a/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.mm b/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.mm
index 31923b38..b43ebf76 100644
--- a/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.mm
+++ b/ios/chrome/browser/ui/sync/sync_error_infobar_delegate.mm
@@ -20,9 +20,7 @@
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/sync/sync_util.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -32,10 +30,9 @@
 #endif
 
 // static
-bool SyncErrorInfoBarDelegate::Create(
-    infobars::InfoBarManager* infobar_manager,
-    ios::ChromeBrowserState* browser_state,
-    id<ApplicationSettingsCommands> dispatcher) {
+bool SyncErrorInfoBarDelegate::Create(infobars::InfoBarManager* infobar_manager,
+                                      ios::ChromeBrowserState* browser_state,
+                                      id<ApplicationCommands> dispatcher) {
   DCHECK(infobar_manager);
   std::unique_ptr<ConfirmInfoBarDelegate> delegate(
       new SyncErrorInfoBarDelegate(browser_state, dispatcher));
@@ -45,7 +42,7 @@
 
 SyncErrorInfoBarDelegate::SyncErrorInfoBarDelegate(
     ios::ChromeBrowserState* browser_state,
-    id<ApplicationSettingsCommands> dispatcher)
+    id<ApplicationCommands> dispatcher)
     : browser_state_(browser_state), dispatcher_(dispatcher) {
   DCHECK(!browser_state->IsOffTheRecord());
   icon_ = gfx::Image([UIImage imageNamed:@"infobar_warning"]);
@@ -97,14 +94,11 @@
 
 bool SyncErrorInfoBarDelegate::Accept() {
   if (ShouldShowSyncSignin(error_state_)) {
-    UIWindow* main_window = [[UIApplication sharedApplication] keyWindow];
-    DCHECK(main_window);
-    [main_window
-        chromeExecuteCommand:
-            [[ShowSigninCommand alloc]
-                initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
-                      accessPoint:signin_metrics::AccessPoint::
-                                      ACCESS_POINT_UNKNOWN]];
+    [dispatcher_
+        showSignin:[[ShowSigninCommand alloc]
+                       initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
+                             accessPoint:signin_metrics::AccessPoint::
+                                             ACCESS_POINT_UNKNOWN]];
   } else if (ShouldShowSyncSettings(error_state_)) {
     [dispatcher_ showSyncSettings];
   } else if (ShouldShowSyncPassphraseSettings(error_state_)) {
diff --git a/ios/chrome/browser/ui/sync/sync_util.h b/ios/chrome/browser/ui/sync/sync_util.h
index 5c140cb..242eda5 100644
--- a/ios/chrome/browser/ui/sync/sync_util.h
+++ b/ios/chrome/browser/ui/sync/sync_util.h
@@ -10,7 +10,7 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 
-@protocol ApplicationSettingsCommands;
+@protocol ApplicationCommands;
 @class GenericChromeCommand;
 @class Tab;
 
@@ -53,7 +53,7 @@
 // Returns true if an infobar was brought up.
 bool DisplaySyncErrors(ios::ChromeBrowserState* browser_state,
                        Tab* tab,
-                       id<ApplicationSettingsCommands> dispatcher);
+                       id<ApplicationCommands> dispatcher);
 
 // Returns true if |errorState| corresponds to a transient sync error.
 bool IsTransientSyncError(SyncSetupService::SyncServiceState errorState);
diff --git a/ios/chrome/browser/ui/sync/sync_util.mm b/ios/chrome/browser/ui/sync/sync_util.mm
index 115dd18..fddf577 100644
--- a/ios/chrome/browser/ui/sync/sync_util.mm
+++ b/ios/chrome/browser/ui/sync/sync_util.mm
@@ -133,7 +133,7 @@
 
 bool DisplaySyncErrors(ios::ChromeBrowserState* browser_state,
                        Tab* tab,
-                       id<ApplicationSettingsCommands> dispatcher) {
+                       id<ApplicationCommands> dispatcher) {
   // Avoid displaying sync errors on incognito tabs.
   if (browser_state->IsOffTheRecord())
     return false;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
index 6de39de..ff59313 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.mm
@@ -14,7 +14,6 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
@@ -252,7 +251,8 @@
   _signinPromoViewMediator = [[SigninPromoViewMediator alloc]
       initWithBrowserState:_browserState
                accessPoint:signin_metrics::AccessPoint::
-                               ACCESS_POINT_TAB_SWITCHER];
+                               ACCESS_POINT_TAB_SWITCHER
+                dispatcher:self.dispatcher];
   _signinPromoView.delegate = _signinPromoViewMediator;
   _signinPromoViewMediator.consumer = self;
   [[_signinPromoViewMediator createConfigurator]
@@ -453,11 +453,11 @@
   SyncSetupService::SyncServiceState syncState =
       GetSyncStateForBrowserState(_browserState);
   if (ShouldShowSyncSignin(syncState)) {
-    [self chromeExecuteCommand:
-              [[ShowSigninCommand alloc]
-                  initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
-                        accessPoint:signin_metrics::AccessPoint::
-                                        ACCESS_POINT_UNKNOWN]];
+    [self.dispatcher
+        showSignin:[[ShowSigninCommand alloc]
+                       initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
+                             accessPoint:signin_metrics::AccessPoint::
+                                             ACCESS_POINT_UNKNOWN]];
   } else if (ShouldShowSyncSettings(syncState)) {
     [self.dispatcher showSyncSettings];
   } else if (ShouldShowSyncPassphraseSettings(syncState)) {
diff --git a/ios/chrome/browser/web/BUILD.gn b/ios/chrome/browser/web/BUILD.gn
index d1ee67f3..05c2c86 100644
--- a/ios/chrome/browser/web/BUILD.gn
+++ b/ios/chrome/browser/web/BUILD.gn
@@ -147,8 +147,9 @@
     "external_app_launcher.h",
     "external_app_launcher.mm",
     "passkit_dialog_provider.h",
-    "print_observer.h",
-    "print_observer.mm",
+    "print_tab_helper.h",
+    "print_tab_helper.mm",
+    "web_state_printer.h",
   ]
   deps = [
     ":chrome_bundle",
@@ -187,7 +188,10 @@
     "//ui/gfx",
     "//url",
   ]
-  libs = [ "UIKit.framework" ]
+  libs = [
+    "UIKit.framework",
+    "Foundation.framework",
+  ]
 }
 
 source_set("test_support") {
diff --git a/ios/chrome/browser/web/chrome_web_client.mm b/ios/chrome/browser/web/chrome_web_client.mm
index 600ba29..0cb0309 100644
--- a/ios/chrome/browser/web/chrome_web_client.mm
+++ b/ios/chrome/browser/web/chrome_web_client.mm
@@ -167,8 +167,7 @@
   NSMutableArray* scripts = [NSMutableArray array];
   [scripts addObject:GetPageScript(@"chrome_bundle")];
 
-  if (base::FeatureList::IsEnabled(
-          credential_manager::features::kCredentialManager)) {
+  if (base::FeatureList::IsEnabled(features::kCredentialManager)) {
     [scripts addObject:GetPageScript(@"credential_manager")];
   }
 
diff --git a/ios/chrome/browser/web/chrome_web_client_unittest.mm b/ios/chrome/browser/web/chrome_web_client_unittest.mm
index 0f3dcbe..0467a54 100644
--- a/ios/chrome/browser/web/chrome_web_client_unittest.mm
+++ b/ios/chrome/browser/web/chrome_web_client_unittest.mm
@@ -116,8 +116,7 @@
                                 web_view, @"typeof navigator.credentials"));
 
   base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      credential_manager::features::kCredentialManager);
+  feature_list.InitAndEnableFeature(features::kCredentialManager);
   script = web_client.Get()->GetEarlyPageScript(browser_state());
   web::ExecuteJavaScript(web_view, script);
   EXPECT_NSEQ(@"object", web::ExecuteJavaScript(
diff --git a/ios/chrome/browser/web/print_observer.h b/ios/chrome/browser/web/print_observer.h
deleted file mode 100644
index 548c32f..0000000
--- a/ios/chrome/browser/web/print_observer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_WEB_PRINT_OBSERVER_H_
-#define IOS_CHROME_BROWSER_WEB_PRINT_OBSERVER_H_
-
-#include "ios/web/public/web_state/web_state_observer.h"
-
-@protocol BrowserCommands;
-namespace base {
-class DictionaryValue;
-}  // namespace base
-
-class GURL;
-
-// Handles print requests from JavaScript window.print.
-class PrintObserver : public web::WebStateObserver {
- public:
-  PrintObserver(web::WebState* web_state, id<BrowserCommands> dispatcher);
-  ~PrintObserver() override;
-
- private:
-  // web::WebStateObserver overrides:
-  void WebStateDestroyed() override;
-
-  // Called when print message is sent by the web page.
-  bool OnPrintCommand(const base::DictionaryValue&, const GURL&, bool);
-  // Stops handling print requests from the web page.
-  void Detach();
-
-  __weak id<BrowserCommands> dispatcher_;
-};
-
-#endif  // IOS_CHROME_BROWSER_WEB_PRINT_OBSERVER_H_
diff --git a/ios/chrome/browser/web/print_observer.mm b/ios/chrome/browser/web/print_observer.mm
deleted file mode 100644
index 3c98184b..0000000
--- a/ios/chrome/browser/web/print_observer.mm
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/web/print_observer.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/values.h"
-#include "ios/chrome/browser/ui/commands/browser_commands.h"
-#import "ios/web/public/web_state/web_state.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Prefix for print JavaScript command.
-const char kPrintCommandPrefix[] = "print";
-}
-
-PrintObserver::PrintObserver(web::WebState* web_state,
-                             id<BrowserCommands> dispatcher)
-    : web::WebStateObserver(web_state), dispatcher_(dispatcher) {
-  web_state->AddScriptCommandCallback(
-      base::Bind(&PrintObserver::OnPrintCommand, base::Unretained(this)),
-      kPrintCommandPrefix);
-}
-
-PrintObserver::~PrintObserver() {
-  Detach();
-}
-
-void PrintObserver::WebStateDestroyed() {
-  Detach();
-}
-
-bool PrintObserver::OnPrintCommand(const base::DictionaryValue&,
-                                   const GURL&,
-                                   bool) {
-  [dispatcher_ printTab];
-  return true;
-}
-
-void PrintObserver::Detach() {
-  if (web_state()) {
-    web_state()->RemoveScriptCommandCallback(kPrintCommandPrefix);
-  }
-}
diff --git a/ios/chrome/browser/web/print_tab_helper.h b/ios/chrome/browser/web/print_tab_helper.h
new file mode 100644
index 0000000..7e03d39f
--- /dev/null
+++ b/ios/chrome/browser/web/print_tab_helper.h
@@ -0,0 +1,44 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_WEB_PRINT_TAB_HELPER_H_
+#define IOS_CHROME_BROWSER_WEB_PRINT_TAB_HELPER_H_
+
+#include "base/macros.h"
+#include "ios/web/public/web_state/web_state_observer.h"
+#include "ios/web/public/web_state/web_state_user_data.h"
+
+@protocol WebStatePrinter;
+class GURL;
+
+namespace base {
+class DictionaryValue;
+}  // namespace base
+
+// Handles print requests from JavaScript window.print.
+class PrintTabHelper : public web::WebStateObserver,
+                       public web::WebStateUserData<PrintTabHelper> {
+ public:
+  ~PrintTabHelper() override;
+
+  // Creates a PrintTabHelper and attaches it to |web_state|. The |printer|
+  // must be non-nil.
+  static void CreateForWebState(web::WebState* web_state,
+                                id<WebStatePrinter> printer);
+
+ private:
+  PrintTabHelper(web::WebState* web_state, id<WebStatePrinter> printer);
+
+  // web::WebStateObserver overrides:
+  void WebStateDestroyed() override;
+
+  // Called when print message is sent by the web page.
+  bool OnPrintCommand(const base::DictionaryValue&, const GURL&, bool);
+
+  __weak id<WebStatePrinter> printer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrintTabHelper);
+};
+
+#endif  // IOS_CHROME_BROWSER_WEB_PRINT_TAB_HELPER_H_
diff --git a/ios/chrome/browser/web/print_tab_helper.mm b/ios/chrome/browser/web/print_tab_helper.mm
new file mode 100644
index 0000000..7f37499
--- /dev/null
+++ b/ios/chrome/browser/web/print_tab_helper.mm
@@ -0,0 +1,59 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/web/print_tab_helper.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "ios/chrome/browser/web/web_state_printer.h"
+#import "ios/web/public/web_state/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Prefix for print JavaScript command.
+const char kPrintCommandPrefix[] = "print";
+}
+
+DEFINE_WEB_STATE_USER_DATA_KEY(PrintTabHelper);
+
+// static
+void PrintTabHelper::CreateForWebState(web::WebState* web_state,
+                                       id<WebStatePrinter> printer) {
+  DCHECK(web_state);
+  if (!FromWebState(web_state)) {
+    web_state->SetUserData(UserDataKey(), base::WrapUnique(new PrintTabHelper(
+                                              web_state, printer)));
+  }
+}
+
+PrintTabHelper::~PrintTabHelper() = default;
+
+PrintTabHelper::PrintTabHelper(web::WebState* web_state,
+                               id<WebStatePrinter> printer)
+    : web::WebStateObserver(web_state), printer_(printer) {
+  DCHECK(printer);
+  web_state->AddScriptCommandCallback(
+      base::Bind(&PrintTabHelper::OnPrintCommand, base::Unretained(this)),
+      kPrintCommandPrefix);
+}
+
+void PrintTabHelper::WebStateDestroyed() {
+  // Stops handling print requests from the web page.
+  if (web_state()) {
+    web_state()->RemoveScriptCommandCallback(kPrintCommandPrefix);
+  }
+}
+
+bool PrintTabHelper::OnPrintCommand(const base::DictionaryValue&,
+                                    const GURL&,
+                                    bool) {
+  DCHECK(web_state());
+  [printer_ printWebState:web_state()];
+  return true;
+}
diff --git a/ios/chrome/browser/web/web_state_printer.h b/ios/chrome/browser/web/web_state_printer.h
new file mode 100644
index 0000000..742149a
--- /dev/null
+++ b/ios/chrome/browser/web/web_state_printer.h
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_WEB_WEB_STATE_PRINTER_H_
+#define IOS_CHROME_BROWSER_WEB_WEB_STATE_PRINTER_H_
+
+#import <Foundation/Foundation.h>
+
+namespace web {
+class WebState;
+}
+
+// Protocol implemented to print a WebState. Used to implement the javascript
+// command "window.print".
+@protocol WebStatePrinter<NSObject>
+
+- (void)printWebState:(web::WebState*)webState;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_WEB_WEB_STATE_PRINTER_H_
diff --git a/ios/chrome/test/app/signin_test_util.h b/ios/chrome/test/app/signin_test_util.h
index b60ada30..763bd79 100644
--- a/ios/chrome/test/app/signin_test_util.h
+++ b/ios/chrome/test/app/signin_test_util.h
@@ -25,6 +25,9 @@
 // the accounts were correctly removed from the keychain.
 bool SignOutAndClearAccounts();
 
+// Resets mock authentication.
+void ResetMockAuthentication();
+
 // Resets Sign-in promo impression preferences for bookmarks and settings view,
 // and resets kIosBookmarkPromoAlreadySeen flag for bookmarks.
 void ResetSigninPromoPreferences();
diff --git a/ios/chrome/test/app/signin_test_util.mm b/ios/chrome/test/app/signin_test_util.mm
index 096390c..5324a3b 100644
--- a/ios/chrome/test/app/signin_test_util.mm
+++ b/ios/chrome/test/app/signin_test_util.mm
@@ -20,6 +20,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#import "ios/public/provider/chrome/browser/signin/fake_chrome_identity.h"
 #import "ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -174,6 +175,11 @@
   return !identity_service->HasIdentities();
 }
 
+void ResetMockAuthentication() {
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()
+      ->SetFakeMDMError(false);
+}
+
 void ResetSigninPromoPreferences() {
   ios::ChromeBrowserState* browser_state = GetOriginalBrowserState();
   PrefService* prefs = browser_state->GetPrefs();
diff --git a/ios/chrome/test/earl_grey/chrome_test_case.mm b/ios/chrome/test/earl_grey/chrome_test_case.mm
index 053638f0..0d522a75 100644
--- a/ios/chrome/test/earl_grey/chrome_test_case.mm
+++ b/ios/chrome/test/earl_grey/chrome_test_case.mm
@@ -179,6 +179,7 @@
   _tearDownHandler = nil;
 
   chrome_test_util::ResetSigninPromoPreferences();
+  chrome_test_util::ResetMockAuthentication();
   chrome_test_util::OpenNewTab();
   [[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
 }
diff --git a/ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.mm b/ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.mm
index 515b398..1e032aa 100644
--- a/ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.mm
+++ b/ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.mm
@@ -70,6 +70,10 @@
   [self showAlert:@"openURL"];
 }
 
+- (void)showSignin:(ShowSigninCommand*)command {
+  [self showAlert:@"showSignin"];
+}
+
 #pragma mark - ApplicationSettingsCommands
 
 - (void)showAccountsSettings {
diff --git a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
index 05b41157..7162318 100644
--- a/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
+++ b/ios/clean/chrome/browser/ui/bookmarks/bookmarks_coordinator.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.h"
 #import "ios/chrome/browser/ui/browser_list/browser.h"
 #import "ios/chrome/browser/ui/coordinators/browser_coordinator+internal.h"
+#import "ios/clean/chrome/browser/ui/adaptor/application_commands_adaptor.h"
 #import "ios/clean/chrome/browser/ui/adaptor/url_loader_adaptor.h"
 #include "ios/web/public/referrer.h"
 
@@ -30,6 +31,9 @@
 @property(nonatomic, strong) BookmarkHomeViewController* bookmarkBrowser;
 // Adaptor for old architecture URL loaders.
 @property(nonatomic, strong) URLLoaderAdaptor* loader;
+// Adaptor for old architecture application commands.
+@property(nonatomic, strong)
+    ApplicationCommandsAdaptor* applicationCommandAdaptor;
 @end
 
 @implementation BookmarksCoordinator
@@ -37,6 +41,7 @@
 @synthesize viewController = _viewController;
 @synthesize bookmarkBrowser = _bookmarkBrowser;
 @synthesize loader = _loader;
+@synthesize applicationCommandAdaptor = _applicationCommandAdaptor;
 
 - (void)start {
   if (self.started)
@@ -45,12 +50,14 @@
   DCHECK(self.mode != UNDEFINED);
 
   self.loader = [[URLLoaderAdaptor alloc] init];
+  self.applicationCommandAdaptor = [[ApplicationCommandsAdaptor alloc] init];
   if (self.mode == PRESENTED) {
     BookmarkControllerFactory* bookmarkControllerFactory =
         [[BookmarkControllerFactory alloc] init];
     self.bookmarkBrowser = [bookmarkControllerFactory
         bookmarkControllerWithBrowserState:self.browser->browser_state()
-                                    loader:self.loader];
+                                    loader:self.loader
+                                dispatcher:self.applicationCommandAdaptor];
     self.bookmarkBrowser.homeDelegate = self;
 
     if (base::FeatureList::IsEnabled(kBookmarkNewGeneration)) {
@@ -68,9 +75,11 @@
   } else {
     self.viewController = [[BookmarkHomeTabletNTPController alloc]
         initWithLoader:self.loader
-          browserState:self.browser->browser_state()];
+          browserState:self.browser->browser_state()
+            dispatcher:self.applicationCommandAdaptor];
   }
   self.loader.viewControllerForAlert = self.viewController;
+  self.applicationCommandAdaptor.viewControllerForAlert = self.viewController;
   [super start];
 }
 
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
index b9971fb..c6b7338 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.h
@@ -78,8 +78,14 @@
   // is unknown.
   void RemoveIdentity(ChromeIdentity* identity);
 
+  // When set to true, call to GetAccessToken() fakes a MDM error.
+  void SetFakeMDMError(bool fakeMDMError);
+
  private:
   base::scoped_nsobject<NSMutableArray> identities_;
+
+  // If true, call to GetAccessToken() fakes a MDM error.
+  bool _fakeMDMError;
 };
 
 }  // namespace ios
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
index 6d7a522..5626c2714 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity_service.mm
@@ -19,28 +19,6 @@
 
 namespace {
 
-void FakeGetAccessToken(ChromeIdentity*,
-                        const std::string&,
-                        const std::string&,
-                        const std::set<std::string>&,
-                        ios::AccessTokenCallback callback) {
-  base::mac::ScopedBlock<ios::AccessTokenCallback> safe_callback(
-      [callback copy]);
-
-  // |GetAccessToken| is normally an asynchronous operation (that requires some
-  // network calls), this is replicated here by dispatching it.
-  dispatch_async(dispatch_get_main_queue(), ^{
-    // Token and expiration date. It should be larger than typical test
-    // execution because tests usually setup mock to expect one token request
-    // and then rely on access token being served from cache.
-    NSTimeInterval expiration = 60.0;
-    NSDate* expiresDate = [NSDate dateWithTimeIntervalSinceNow:expiration];
-    NSString* token = [expiresDate description];
-
-    safe_callback.get()(token, expiresDate, nil);
-  });
-}
-
 UIImage* FakeGetCachedAvatarForIdentity(ChromeIdentity*) {
   ios::SigninResourcesProvider* provider =
       ios::GetChromeBrowserProvider()->GetSigninResourcesProvider();
@@ -131,7 +109,7 @@
 NSString* const kIdentityGaiaIDFormat = @"%@ID";
 
 FakeChromeIdentityService::FakeChromeIdentityService()
-    : identities_([[NSMutableArray alloc] init]) {}
+    : identities_([[NSMutableArray alloc] init]), _fakeMDMError(false) {}
 
 FakeChromeIdentityService::~FakeChromeIdentityService() {}
 
@@ -216,7 +194,33 @@
     const std::string& client_secret,
     const std::set<std::string>& scopes,
     ios::AccessTokenCallback callback) {
-  FakeGetAccessToken(identity, client_id, client_secret, scopes, callback);
+  base::mac::ScopedBlock<ios::AccessTokenCallback> safe_callback(
+      [callback copy]);
+  NSError* error = nil;
+  NSDictionary* user_info = nil;
+  if (_fakeMDMError) {
+    // |GetAccessToken| is normally an asynchronous operation (that requires
+    // some network calls), this is replicated here by dispatching it.
+    error =
+        [NSError errorWithDomain:@"com.google.HTTPStatus" code:-1 userInfo:nil];
+    user_info = @{};
+    EXPECT_CALL(*this, HandleMDMNotification(identity, user_info, _))
+        .WillRepeatedly(testing::Return(true));
+  }
+  // |GetAccessToken| is normally an asynchronous operation (that requires some
+  // network calls), this is replicated here by dispatching it.
+  dispatch_async(dispatch_get_main_queue(), ^{
+    if (user_info)
+      FireAccessTokenRefreshFailed(identity, user_info);
+    // Token and expiration date. It should be larger than typical test
+    // execution because tests usually setup mock to expect one token request
+    // and then rely on access token being served from cache.
+    NSTimeInterval expiration = 60.0;
+    NSDate* expiresDate = [NSDate dateWithTimeIntervalSinceNow:expiration];
+    NSString* token = [expiresDate description];
+
+    safe_callback.get()(token, expiresDate, error);
+  });
 }
 
 UIImage* FakeChromeIdentityService::GetCachedAvatarForIdentity(
@@ -260,4 +264,8 @@
   }
 }
 
+void FakeChromeIdentityService::SetFakeMDMError(bool fakeMDMError) {
+  _fakeMDMError = fakeMDMError;
+}
+
 }  // namespace ios
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index efcdc68..2af246e 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -250,10 +250,6 @@
 const base::Feature kUseNewMediaCache{"use-new-media-cache",
                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Use R16 texture for 9-16 bit channel instead of half-float conversion by CPU.
-const base::Feature kUseR16Texture{"use-r16-texture",
-                                   base::FEATURE_DISABLED_BY_DEFAULT};
-
 // Correct video colors based on output display?
 const base::Feature kVideoColorManagement{"video-color-management",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 4be332de..2428343 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -123,7 +123,6 @@
 MEDIA_EXPORT extern const base::Feature kSupportExperimentalCdmInterface;
 MEDIA_EXPORT extern const base::Feature kUseAndroidOverlay;
 MEDIA_EXPORT extern const base::Feature kUseNewMediaCache;
-MEDIA_EXPORT extern const base::Feature kUseR16Texture;
 MEDIA_EXPORT extern const base::Feature kVideoBlitColorAccuracy;
 MEDIA_EXPORT extern const base::Feature kVideoColorManagement;
 MEDIA_EXPORT extern const base::Feature kUseSurfaceLayerForVideo;
diff --git a/net/ssl/client_cert_store_nss.cc b/net/ssl/client_cert_store_nss.cc
index 7dd1828..b6d779eb 100644
--- a/net/ssl/client_cert_store_nss.cc
+++ b/net/ssl/client_cert_store_nss.cc
@@ -18,8 +18,8 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_piece.h"
-#include "base/task_runner_util.h"
-#include "base/threading/worker_pool.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "crypto/nss_crypto_module_delegate.h"
 #include "net/cert/scoped_nss_types.h"
 #include "net/cert/x509_util_nss.h"
@@ -50,17 +50,13 @@
           private_key_callback) override {
     // Caller is responsible for keeping the ClientCertIdentity alive until
     // the |private_key_callback| is run, so it's safe to use Unretained here.
-    if (base::PostTaskAndReplyWithResult(
-            base::WorkerPool::GetTaskRunner(true /* task_is_slow */).get(),
-            FROM_HERE,
-            base::Bind(&FetchClientCertPrivateKey,
-                       base::Unretained(certificate()), cert_certificate_.get(),
-                       base::Unretained(password_delegate_.get())),
-            private_key_callback)) {
-      return;
-    }
-    // If the task could not be posted, behave as if there was no key.
-    private_key_callback.Run(nullptr);
+    base::PostTaskWithTraitsAndReplyWithResult(
+        FROM_HERE,
+        {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+        base::Bind(&FetchClientCertPrivateKey, base::Unretained(certificate()),
+                   cert_certificate_.get(),
+                   base::Unretained(password_delegate_.get())),
+        private_key_callback);
   }
 
  private:
@@ -83,19 +79,15 @@
   scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate> password_delegate;
   if (!password_delegate_factory_.is_null())
     password_delegate = password_delegate_factory_.Run(request.host_and_port);
-  if (base::PostTaskAndReplyWithResult(
-          base::WorkerPool::GetTaskRunner(true /* task_is_slow */).get(),
-          FROM_HERE,
-          base::Bind(&ClientCertStoreNSS::GetAndFilterCertsOnWorkerThread,
-                     // Caller is responsible for keeping the ClientCertStore
-                     // alive until the callback is run.
-                     base::Unretained(this), std::move(password_delegate),
-                     base::Unretained(&request)),
-          callback)) {
-    return;
-  }
-  // If the task could not be posted, behave as if there were no certificates.
-  callback.Run(ClientCertIdentityList());
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::Bind(&ClientCertStoreNSS::GetAndFilterCertsOnWorkerThread,
+                 // Caller is responsible for keeping the ClientCertStore
+                 // alive until the callback is run.
+                 base::Unretained(this), std::move(password_delegate),
+                 base::Unretained(&request)),
+      callback);
 }
 
 // static
@@ -166,6 +158,11 @@
     scoped_refptr<crypto::CryptoModuleBlockingPasswordDelegate>
         password_delegate,
     const SSLCertRequestInfo* request) {
+  // This method may acquire the NSS lock or reenter this code via extension
+  // hooks (such as smart card UI). To ensure threads are not starved or
+  // deadlocked, the base::ScopedBlockingCall below increments the thread pool
+  // capacity if this method takes too much time to run.
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   ClientCertIdentityList selected_identities;
   GetPlatformCertsOnWorkerThread(std::move(password_delegate), CertFilter(),
                                  &selected_identities);
diff --git a/net/ssl/ssl_platform_key_nss.cc b/net/ssl/ssl_platform_key_nss.cc
index 062d4a2..c3162f1 100644
--- a/net/ssl/ssl_platform_key_nss.cc
+++ b/net/ssl/ssl_platform_key_nss.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "crypto/nss_crypto_module_delegate.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/x509_certificate.h"
@@ -157,6 +158,12 @@
     const X509Certificate* certificate,
     CERTCertificate* cert_certificate,
     crypto::CryptoModuleBlockingPasswordDelegate* password_delegate) {
+  // This function may acquire the NSS lock or reenter this code via extension
+  // hooks (such as smart card UI). To ensure threads are not starved or
+  // deadlocked, the base::ScopedBlockingCall below increments the thread pool
+  // capacity if this method takes too much time to run.
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+
   void* wincx = password_delegate ? password_delegate->wincx() : nullptr;
   crypto::ScopedSECKEYPrivateKey key(
       PK11_FindKeyByAnyCert(cert_certificate, wincx));
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 7974930..8a66114e 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -13,7 +13,7 @@
 
 # TODO(editing-dev): Investigate why a BR is left in the editable container when
 # LayoutNG is enabled, but not when disabled.
-crbug.com/707656 editing/deleting/in-visibly-empty-root.html [ Failure ]
+crbug.com/707656 editing/deleting/in-visibly-empty-root.html [ Failure Pass ]
 
 # New passes
 crbug.com/626703 external/wpt/css/css-ui-3/text-overflow-021.html [ Pass ]
@@ -156,7 +156,7 @@
 crbug.com/591099 accessibility/input-type-range-aria-value.html [ Failure ]
 crbug.com/591099 accessibility/input-type-range-value-change.html [ Failure Pass ]
 crbug.com/591099 accessibility/input-type-text-caret-position.html [ Crash Failure Pass ]
-crbug.com/591099 accessibility/input-type-text-selection.html [ Crash Failure Timeout ]
+crbug.com/591099 accessibility/input-type-text-selection.html [ Crash Failure Pass Timeout ]
 crbug.com/591099 accessibility/insert-selected-option-into-select-causes-crash.html [ Failure Pass ]
 crbug.com/591099 accessibility/is-richly-editable.html [ Crash Failure Pass ]
 crbug.com/591099 accessibility/label-element-press.html [ Failure Pass ]
@@ -261,6 +261,8 @@
 crbug.com/591099 animations/interpolation/transform-interpolation-004.html [ Timeout ]
 crbug.com/591099 animations/interpolation/transform-interpolation-005.html [ Timeout ]
 crbug.com/591099 animations/interpolation/webkit-clip-path-interpolation.html [ Crash Pass Timeout ]
+crbug.com/591099 animations/interpolation/webkit-column-count-interpolation.html [ Pass ]
+crbug.com/591099 animations/interpolation/webkit-column-width-interpolation.html [ Pass ]
 crbug.com/591099 animations/keyframes-rule.html [ Failure Pass ]
 crbug.com/591099 animations/lazy-detached-animation-stop.html [ Failure ]
 crbug.com/591099 animations/play-state.html [ Failure Pass ]
@@ -641,7 +643,6 @@
 crbug.com/591099 compositing/transitions/singular-scale-transition.html [ Failure Pass ]
 crbug.com/591099 compositing/update-paint-phases.html [ Failure ]
 crbug.com/591099 compositing/video-frame-size-change.html [ Failure Pass ]
-crbug.com/591099 compositing/video/video-controls-layer-creation.html [ Failure Pass ]
 crbug.com/591099 compositing/video/video-poster.html [ Failure ]
 crbug.com/591099 compositing/visibility/compositing-and-visibility-turned-off-together.html [ Failure Pass ]
 crbug.com/591099 compositing/visibility/hidden-iframe.html [ Failure Pass ]
@@ -2373,15 +2374,6 @@
 crbug.com/591099 css3/zoom-coords.xhtml [ Failure Pass ]
 crbug.com/591099 cssom/ahem-ex-units.html [ Failure Pass ]
 crbug.com/591099 cssom/cssvalue-comparison.html [ Failure ]
-crbug.com/591099 device_orientation/motion/add-during-dispatch.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/add-listener-from-callback.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/create-event.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/fire-last-event.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/multiple-event-listeners.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/null-values.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/optional-event-properties.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/page-visibility.html [ Failure Pass ]
-crbug.com/591099 device_orientation/motion/window-property.html [ Failure Pass ]
 crbug.com/591099 device_orientation/orientation/add-listener-from-callback.html [ Failure Pass ]
 crbug.com/591099 device_orientation/orientation/basic-operation-absolute.html [ Failure Pass ]
 crbug.com/591099 device_orientation/orientation/basic-operation.html [ Failure Pass ]
@@ -3238,6 +3230,7 @@
 crbug.com/591099 editing/unsupported-content/table-delete-003.html [ Failure ]
 crbug.com/591099 editing/unsupported-content/table-type-after.html [ Failure ]
 crbug.com/591099 editing/unsupported-content/table-type-before.html [ Failure ]
+crbug.com/591099 external/wpt/2dcontext/drawing-images-to-the-canvas/drawimage_html_image_11.html [ Pass ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_hkdf.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_empty.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/derive_bits_keys/test_pbkdf2_empty_long.https.html [ Pass Timeout ]
@@ -3269,6 +3262,9 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/test_rsa_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/test_symmetric_importKey.https.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/XMLHttpRequest/send-authentication-prompt-2-manual.htm [ Crash Failure ]
+crbug.com/591099 external/wpt/css-fonts/matching/fixed-stretch-style-over-weight.html [ Pass ]
+crbug.com/591099 external/wpt/css-fonts/matching/stretch-distance-over-weight-distance.html [ Pass ]
+crbug.com/591099 external/wpt/css-fonts/matching/style-ranges-over-weight-direction.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/float-replaced-width-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/floats-143.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats-clear/margin-collapse-157.xht [ Failure ]
@@ -3333,7 +3329,6 @@
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-103.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-104.xht [ Crash Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/positioning/top-113.xht [ Crash Failure Pass ]
-crbug.com/591099 external/wpt/css/CSS2/text/text-align-white-space-002.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/text/text-align-white-space-006.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-006.xht [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/text/text-decoration-applies-to-007.xht [ Failure ]
@@ -3548,6 +3543,7 @@
 crbug.com/591099 external/wpt/css/css-ui-3/text-overflow-014.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-ui-3/text-overflow-015.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-ui-3/text-overflow-022.html [ Failure ]
+crbug.com/591099 external/wpt/css/css-ui-3/text-overflow-023.html [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-icb-vlr-023.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-icb-vlr-025.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-icb-vrl-022.xht [ Failure ]
@@ -3719,10 +3715,6 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-vrl-222.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-vrl-226.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/abs-pos-non-replaced-vrl-228.xht [ Failure ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/baseline-inline-non-replaced-002.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/baseline-inline-non-replaced-003.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/baseline-inline-non-replaced-004.xht [ Failure Pass ]
-crbug.com/591099 external/wpt/css/css-writing-modes-3/baseline-inline-non-replaced-005.xht [ Failure Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/block-flow-direction-vlr-022.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/block-flow-direction-vrl-012.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/block-flow-direction-vrl-021.xht [ Failure ]
@@ -3794,6 +3786,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/percent-padding-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/percent-padding-vrl-004.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/percent-padding-vrl-006.xht [ Failure ]
+crbug.com/591099 external/wpt/css/css-writing-modes-3/sizing-orthog-htb-in-vlr-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/text-baseline-vlr-007.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/text-baseline-vrl-002.xht [ Failure ]
 crbug.com/591099 external/wpt/css/css-writing-modes-3/text-baseline-vrl-004.xht [ Failure ]
@@ -3831,6 +3824,7 @@
 crbug.com/591099 external/wpt/css/css-writing-modes-3/writing-mode-vertical-rl-003.htm [ Failure ]
 crbug.com/591099 external/wpt/css/geometry-1/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/css/geometry-1/interfaces.worker.html [ Timeout ]
+crbug.com/591099 external/wpt/css/selectors4/focus-within-004.html [ Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-content-vert-001a.xhtml [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-002.xhtml [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-baseline-horiz-003.xhtml [ Failure Pass ]
@@ -3840,6 +3834,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-004.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-003.xhtml [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-align-self-vert-rtl-004.xhtml [ Failure ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-single-item-001a.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-single-item-001b.html [ Crash Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-break-request-horiz-002a.html [ Failure ]
@@ -3853,6 +3848,7 @@
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-16.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-17.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-declaration-18.html [ Failure Pass ]
+crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/variables/variable-font-face-01.html [ Failure Pass ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/dynamic-offset-vrl-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/dynamic-offset-vrl-rtl-002.html [ Failure ]
 crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/writing-modes-3/text-combine-upright-break-inside-001.html [ Failure ]
@@ -3873,6 +3869,7 @@
 crbug.com/591099 external/wpt/custom-elements/reactions/Document.html [ Crash Failure ]
 crbug.com/591099 external/wpt/dom/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/DOMImplementation-createDocument.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/dom/nodes/Document-contentType/contentType/contenttype_datauri_02.html [ Pass ]
 crbug.com/591099 external/wpt/dom/nodes/Document-createElementNS.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-classlist.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/dom/nodes/Element-matches.html [ Crash Failure Pass Timeout ]
@@ -3994,10 +3991,14 @@
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href-errors-misc.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-tchinese/big5/big5-encode-href.html [ Timeout ]
 crbug.com/591099 external/wpt/encoding/textdecoder-fatal-single-byte.html [ Timeout ]
+crbug.com/591099 external/wpt/feature-policy/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/feature-policy/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Crash Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Crash Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Crash Failure ]
 crbug.com/591099 external/wpt/html/browsers/windows/noreferrer-window-name.html [ Crash Timeout ]
+crbug.com/591099 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Pass ]
 crbug.com/591099 external/wpt/html/dom/interfaces.html [ Timeout ]
 crbug.com/591099 external/wpt/html/dom/interfaces.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/html/infrastructure/urls/resolving-urls/query-encoding/utf-16be.html [ Crash Timeout ]
@@ -4040,7 +4041,13 @@
 crbug.com/591099 external/wpt/intersection-observer/edge-inclusive-intersection.html [ Failure ]
 crbug.com/591099 external/wpt/intersection-observer/remove-element.html [ Failure ]
 crbug.com/591099 external/wpt/intersection-observer/same-document-root.html [ Crash Failure ]
+crbug.com/591099 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/media-source/mediasource-getvideoplaybackquality.html [ Crash Timeout ]
+crbug.com/591099 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Pass ]
+crbug.com/591099 external/wpt/payment-request/payment-allowed-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/payment-request/payment-disabled-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/performance-timeline/po-callback-mutate.any.html [ Pass ]
+crbug.com/591099 external/wpt/performance-timeline/po-callback-mutate.any.worker.html [ Pass ]
 crbug.com/591099 external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction-manual.html [ Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_hoverable_pointers-manual.html [ Crash Pass Timeout ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html [ Crash Pass Timeout ]
@@ -4087,6 +4094,8 @@
 crbug.com/591099 external/wpt/webmessaging/broadcastchannel/sandbox.html [ Crash Failure ]
 crbug.com/591099 external/wpt/webrtc/interfaces.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/webstorage/storage_setitem.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/webusb/usb-allowed-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/webusb/usb-disabled-by-feature-policy.https.sub.html [ Pass ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_completely_move_up.html [ Crash Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/2_cues_overlapping_partially_move_up.html [ Crash Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/bidi/bidi_ruby.html [ Crash Failure ]
@@ -4106,6 +4115,9 @@
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/underline_object/underline_font_shorthand.html [ Crash Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_properties.html [ Crash Failure ]
 crbug.com/591099 external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/voice_object/voice_font_shorthand.html [ Crash Failure ]
+crbug.com/591099 external/wpt/workers/Worker_terminate_event_queue.htm [ Pass ]
+crbug.com/591099 external/wpt/workers/semantics/navigation/001.html [ Pass ]
+crbug.com/591099 external/wpt/workers/semantics/navigation/002.html [ Pass ]
 crbug.com/591099 fast/alignment/ensure-flexbox-compatibility-with-initial-values.html [ Failure Pass ]
 crbug.com/591099 fast/alignment/overwrite-content-alignment.html [ Failure Pass ]
 crbug.com/591099 fast/alignment/overwrite-self-alignment.html [ Failure Pass ]
@@ -4476,6 +4488,7 @@
 crbug.com/591099 fast/borders/bidi-012.html [ Failure ]
 crbug.com/591099 fast/borders/border-antialiasing.html [ Failure ]
 crbug.com/591099 fast/borders/border-color-visited.html [ Crash Failure Pass ]
+crbug.com/591099 fast/borders/border-image-border-radius.html [ Failure Pass ]
 crbug.com/591099 fast/borders/border-image-width-negative.html [ Failure Pass ]
 crbug.com/591099 fast/borders/border-radius-child.html [ Failure Pass ]
 crbug.com/591099 fast/borders/border-radius-mask-canvas-all.html [ Crash Failure ]
@@ -4600,7 +4613,11 @@
 crbug.com/591099 fast/clip/014.html [ Failure ]
 crbug.com/591099 fast/clip/nestedTransparencyClip.html [ Failure ]
 crbug.com/591099 fast/clip/outline-overflowClip.html [ Failure ]
+crbug.com/591099 fast/clip/overflow-border-radius-combinations.html [ Failure Pass ]
+crbug.com/591099 fast/clip/overflow-border-radius-composited-parent.html [ Failure Pass ]
+crbug.com/591099 fast/clip/overflow-border-radius-composited.html [ Failure Pass ]
 crbug.com/591099 fast/clip/overflow-border-radius-fixed-position.html [ Failure ]
+crbug.com/591099 fast/clip/overflow-border-radius-transformed.html [ Failure Pass ]
 crbug.com/591099 fast/compact/001.html [ Failure ]
 crbug.com/591099 fast/compact/002.html [ Failure ]
 crbug.com/591099 fast/compact/003.html [ Failure ]
@@ -4870,9 +4887,9 @@
 crbug.com/591099 fast/css-grid-layout/percent-grid-item-in-percent-grid-track-update.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/percent-grid-item-in-percent-grid-track.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/percent-intrinsic-track-breadth.html [ Failure Pass ]
-crbug.com/591099 fast/css-grid-layout/percent-of-indefinite-track-size-in-auto.html [ Failure ]
+crbug.com/591099 fast/css-grid-layout/percent-of-indefinite-track-size-in-auto.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/percent-of-indefinite-track-size-in-minmax-crash.html [ Failure Pass ]
-crbug.com/591099 fast/css-grid-layout/percent-of-indefinite-track-size.html [ Failure ]
+crbug.com/591099 fast/css-grid-layout/percent-of-indefinite-track-size.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/percent-padding-margin-resolution-grid-item-update.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/percent-padding-margin-resolution-grid-item.html [ Failure ]
 crbug.com/591099 fast/css-grid-layout/percent-resolution-grid-item-children.html [ Failure ]
@@ -4896,6 +4913,7 @@
 crbug.com/591099 fast/css-grid-layout/should-not-collapse-anonymous-blocks.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/stale-grid-layout.html [ Failure Pass ]
 crbug.com/591099 fast/css-grid-layout/tracks-wider-min-track-breadth-crash.html [ Failure Pass ]
+crbug.com/591099 fast/css-intrinsic-dimensions/css-tables.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fillavailable-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fitcontent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Crash Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/fixed-height-stf-img-block-child-percent-height.html [ Failure ]
@@ -4906,9 +4924,10 @@
 crbug.com/591099 fast/css-intrinsic-dimensions/height-property-value.html [ Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/indefinite-percent-minmax-content-inlinesize-contribution-nonreplaced-blocks.html [ Failure ]
-crbug.com/591099 fast/css-intrinsic-dimensions/min-width.html [ Crash Failure ]
+crbug.com/591099 fast/css-intrinsic-dimensions/min-width.html [ Crash Failure Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/multicol.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/resize-inside-percent-width-overflow-hidden.html [ Failure ]
+crbug.com/591099 fast/css-intrinsic-dimensions/tables.html [ Failure ]
 crbug.com/591099 fast/css-intrinsic-dimensions/width-property-value.html [ Failure Pass ]
 crbug.com/591099 fast/css/001.html [ Crash Failure ]
 crbug.com/591099 fast/css/002.html [ Failure ]
@@ -5671,7 +5690,6 @@
 crbug.com/591099 fast/css/zoom-property-parsing.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last.html [ Failure Pass ]
-crbug.com/591099 fast/css3-text/css3-text-align-last/text-align-last.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-color.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-style.html [ Failure Pass ]
@@ -5697,7 +5715,7 @@
 crbug.com/591099 fast/css3-text/css3-word-break/css3-word-break-keep-all.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-word-break/word-break-all-rtl.html [ Failure Pass ]
 crbug.com/591099 fast/css3-text/css3-word-break/word-break-all-wrap-with-floats.html [ Failure Pass ]
-crbug.com/591099 fast/css3-text/css3-word-break/word-break-break-all-in-span.html [ Failure ]
+crbug.com/591099 fast/css3-text/css3-word-break/word-break-break-all-in-span.html [ Failure Pass ]
 crbug.com/591099 fast/deprecated-flexbox/004.html [ Failure ]
 crbug.com/591099 fast/deprecated-flexbox/009-horizontal.html [ Failure ]
 crbug.com/591099 fast/deprecated-flexbox/assert-generated-deprecated-flexbox.html [ Failure Pass ]
@@ -7146,7 +7164,7 @@
 crbug.com/591099 fast/events/pointerevents/pointer-use-count.html [ Failure Pass ]
 crbug.com/591099 fast/events/pointerevents/touch-capture-in-iframe.html [ Timeout ]
 crbug.com/591099 fast/events/pointerevents/touch-capture.html [ Failure Timeout ]
-crbug.com/591099 fast/events/pointerevents/touch-pointer-events.html [ Failure Timeout ]
+crbug.com/591099 fast/events/pointerevents/touch-pointer-events.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/events/pointerevents/touch-pointer-mouse.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/events/pointerevents/touch-pointercancel.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/events/popup-allowed-from-gesture-initiated-event.html [ Crash Failure ]
@@ -7373,7 +7391,7 @@
 crbug.com/591099 fast/files/blob-parts-slice-test.html [ Failure Pass ]
 crbug.com/591099 fast/files/blob-slice-test.html [ Crash Failure Pass ]
 crbug.com/591099 fast/files/file-constructor.html [ Failure Pass ]
-crbug.com/591099 fast/files/file-in-input-display.html [ Crash Failure ]
+crbug.com/591099 fast/files/file-in-input-display.html [ Crash Failure Timeout ]
 crbug.com/591099 fast/files/file-list-test.html [ Crash Failure Pass ]
 crbug.com/591099 fast/files/file-reader-abort-gc-iframe.html [ Crash Failure Pass ]
 crbug.com/591099 fast/files/file-reader-detached-no-crash.html [ Failure Pass ]
@@ -9285,6 +9303,7 @@
 crbug.com/591099 fast/mediastream/enabled.html [ Failure Pass ]
 crbug.com/591099 fast/mediastream/getusermedia.html [ Failure Pass ]
 crbug.com/591099 fast/mediastream/no-interface-object.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/5-levels-of-nesting-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/abspos-after-break-after.html [ Failure ]
 crbug.com/591099 fast/multicol/abspos-in-overflow-hidden-in-2nd-column.html [ Failure ]
 crbug.com/591099 fast/multicol/abspos-new-width-rebalance.html [ Failure ]
@@ -9354,8 +9373,10 @@
 crbug.com/591099 fast/multicol/composited-with-child-layer-in-next-column.html [ Failure ]
 crbug.com/591099 fast/multicol/composited-with-overflow-in-next-column.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/constrained-content-height-with-overflow-crash.html [ Failure Pass ]
+crbug.com/591099 fast/multicol/content-change-same-height.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/content-height-zero-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/cssom-view.html [ Failure ]
+crbug.com/591099 fast/multicol/doubly-nested-with-increasing-row-heights-crash.html [ Failure Pass ]
 crbug.com/757767 fast/multicol/doubly-nested-with-insane-child-height-crash.html [ Timeout ]
 crbug.com/757767 fast/multicol/doubly-nested-with-top-padding-crossing-row-boundaries.html [ Timeout ]
 crbug.com/591099 fast/multicol/dynamic/abspos-becomes-spanner.html [ Failure ]
@@ -9481,9 +9502,11 @@
 crbug.com/591099 fast/multicol/hit-test-gap-between-pages.html [ Failure ]
 crbug.com/757767 fast/multicol/huge-column-count.html [ Crash Timeout ]
 crbug.com/591099 fast/multicol/image-inside-nested-blocks-with-border.html [ Failure ]
+crbug.com/591099 fast/multicol/image-loaded-before-layout-assert.html [ Failure Pass ]
 crbug.com/757767 fast/multicol/infinite-height-causing-fractional-row-height-crash.html [ Timeout ]
 crbug.com/757767 fast/multicol/infinitely-tall-content-in-outer-crash.html [ Timeout ]
 crbug.com/591099 fast/multicol/inline-block-baseline.html [ Failure ]
+crbug.com/591099 fast/multicol/inline-children-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/inline-getclientrects.html [ Failure ]
 crbug.com/591099 fast/multicol/inner-multicol-in-second-column.html [ Failure ]
 crbug.com/591099 fast/multicol/inner-multicol-moved-into-continuation.html [ Failure Pass ]
@@ -9510,6 +9533,7 @@
 crbug.com/591099 fast/multicol/multicol-with-child-renderLayer-for-input.html [ Failure ]
 crbug.com/591099 fast/multicol/negative-margins-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/nested-3-multicols-fixed-height.html [ Failure ]
+crbug.com/591099 fast/multicol/nested-after-composited-layer-crash.html [ Failure Pass ]
 crbug.com/757767 fast/multicol/nested-and-unbreakable-crash.html [ Timeout ]
 crbug.com/591099 fast/multicol/nested-auto-height-extra-block-inbetween.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-auto-height-short-first-row.html [ Failure ]
@@ -9534,6 +9558,7 @@
 crbug.com/591099 fast/multicol/nested-with-clipped-first-column.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-with-composited-and-multicol-crash.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/multicol/nested-with-forced-breaks-in-eariler-rows.html [ Failure Timeout ]
+crbug.com/591099 fast/multicol/nested-with-line-taller-than-outer.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/nested-with-padding.html [ Failure ]
 crbug.com/591099 fast/multicol/nested-with-single-empty-block.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/nested-with-single-tall-line.html [ Failure ]
@@ -9562,7 +9587,6 @@
 crbug.com/591099 fast/multicol/newmulticol/fixed-height-fill-balance.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-lr.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/hide-box-vertical-rl.html [ Failure Pass ]
-crbug.com/757767 fast/multicol/newmulticol/leading-margin.html [ Pass Timeout ]
 crbug.com/591099 fast/multicol/newmulticol/orphans-and-widows-balance.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/regular-block-becomes-multicol.html [ Failure ]
 crbug.com/591099 fast/multicol/newmulticol/unresolvable-percent-height-2.html [ Failure ]
@@ -9588,7 +9612,6 @@
 crbug.com/591099 fast/multicol/overflow-into-columngap.html [ Failure ]
 crbug.com/591099 fast/multicol/overflow-unsplittable.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/overflowing-columns-large-gaps.html [ Failure ]
-crbug.com/591099 fast/multicol/pageLogicalOffset-vertical.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/paged-becomes-multicol-auto-height.html [ Failure ]
 crbug.com/591099 fast/multicol/paged-becomes-multicol-fixed-height.html [ Failure ]
 crbug.com/591099 fast/multicol/paged-in-multicol-crash.html [ Failure Pass ]
@@ -9643,6 +9666,7 @@
 crbug.com/591099 fast/multicol/span/fill-after-spanner-exact-fit.html [ Failure ]
 crbug.com/591099 fast/multicol/span/fill-after-spanner-extra-height.html [ Failure ]
 crbug.com/591099 fast/multicol/span/float.html [ Failure ]
+crbug.com/591099 fast/multicol/span/foreignObject.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/height-decrease.html [ Failure ]
 crbug.com/591099 fast/multicol/span/height-increase.html [ Failure ]
 crbug.com/591099 fast/multicol/span/in-nested-multicol-with-hard-breaks.html [ Failure ]
@@ -9651,6 +9675,7 @@
 crbug.com/591099 fast/multicol/span/inside-abspos-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/inside-block-with-fixed-height-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/inside-block-with-fixed-height.html [ Failure ]
+crbug.com/591099 fast/multicol/span/inside-float-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/inside-overflow-hidden-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/invalid-span-1.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/span/invalid-spanner-in-abspos.html [ Failure ]
@@ -9711,8 +9736,10 @@
 crbug.com/591099 fast/multicol/textarea-with-placeholder-as-multicol-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/three-inner-rows.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/transform-inside-opacity.html [ Failure ]
+crbug.com/591099 fast/multicol/triply-nested-with-padding-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/unbreakable-block-too-tall-at-column-start.html [ Failure ]
 crbug.com/591099 fast/multicol/unbreakable-block-too-tall-to-fit.html [ Failure ]
+crbug.com/591099 fast/multicol/unbreakable-content-taller-than-height-crash.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/unforced-break-after-complex-margin-collapsing.html [ Failure ]
 crbug.com/591099 fast/multicol/unsplittable-inline-block.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-lr/abspos-auto-position-on-line.html [ Failure ]
@@ -9771,7 +9798,7 @@
 crbug.com/591099 fast/multicol/vertical-rl/float-truncation.html [ Failure ]
 crbug.com/591099 fast/multicol/vertical-rl/gap-non-negative.html [ Failure Pass ]
 crbug.com/591099 fast/multicol/vertical-rl/image-inside-nested-blocks-with-border.html [ Failure ]
-crbug.com/757767 fast/multicol/vertical-rl/nested-columns.html [ Crash ]
+crbug.com/757767 fast/multicol/vertical-rl/nested-columns.html [ Crash Failure ]
 crbug.com/757767 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries-nested.html [ Timeout ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-at-boundaries.html [ Failure Timeout ]
 crbug.com/591099 fast/multicol/vertical-rl/offset-top-and-left-nested.html [ Failure Timeout ]
@@ -9807,7 +9834,7 @@
 crbug.com/591099 fast/overflow/overflow-auto-position-absolute.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-clamp-after-visible-rect-resize.html [ Failure Pass ]
 crbug.com/591099 fast/overflow/overflow-float-stacking.html [ Failure ]
-crbug.com/757767 fast/overflow/overflow-height-float-not-removed-crash3.html [ Crash Timeout ]
+crbug.com/757767 fast/overflow/overflow-height-float-not-removed-crash3.html [ Crash Failure Timeout ]
 crbug.com/591099 fast/overflow/overflow-rtl-inline-scrollbar.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-rtl-vertical-origin.html [ Failure Pass ]
 crbug.com/591099 fast/overflow/overflow-rtl-vertical.html [ Crash Failure ]
@@ -10460,7 +10487,7 @@
 crbug.com/591099 fast/table/margins-flipped-text-direction.html [ Failure ]
 crbug.com/591099 fast/table/margins-perpendicular-containing-block.html [ Failure ]
 crbug.com/591099 fast/table/min-width-css-block-table.html [ Failure Pass Timeout ]
-crbug.com/591099 fast/table/min-width-css-inline-table.html [ Failure Timeout ]
+crbug.com/591099 fast/table/min-width-css-inline-table.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/table/min-width-html-block-table.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/table/min-width-html-inline-table.html [ Failure Pass Timeout ]
 crbug.com/591099 fast/table/nested-percent-height-table.html [ Failure ]
@@ -10737,7 +10764,7 @@
 crbug.com/591099 fast/text/place-rtl-ellipsis-in-inline-blocks.html [ Failure ]
 crbug.com/591099 fast/text/regional-indicator-symobls.html [ Failure Pass ]
 crbug.com/591099 fast/text/reset-drag-on-mouse-down.html [ Failure Pass ]
-crbug.com/591099 fast/text/reset-emptyRun.html [ Failure ]
+crbug.com/591099 fast/text/reset-emptyRun.html [ Failure Pass ]
 crbug.com/591099 fast/text/selection-hard-linebreak.html [ Failure ]
 crbug.com/591099 fast/text/selection-rect-line-height-too-big.html [ Failure ]
 crbug.com/591099 fast/text/selection-rect-line-height-too-small.html [ Failure ]
@@ -10747,7 +10774,7 @@
 crbug.com/591099 fast/text/shaping/same-script-different-lang.html [ Failure ]
 crbug.com/591099 fast/text/shaping/shaping-width-initialized.html [ Failure Pass ]
 crbug.com/591099 fast/text/soft-hyphen-5.html [ Failure Pass ]
-crbug.com/591099 fast/text/soft-hyphen-overflow.html [ Failure ]
+crbug.com/591099 fast/text/soft-hyphen-overflow.html [ Failure Pass ]
 crbug.com/591099 fast/text/sub-pixel/text-scaling-pixel.html [ Failure Timeout ]
 crbug.com/591099 fast/text/tab-min-size.html [ Failure Pass ]
 crbug.com/591099 fast/text/text-between-two-brs-in-nowrap-overflow.html [ Failure Pass ]
@@ -10912,6 +10939,7 @@
 crbug.com/591099 fast/writing-mode/box-shadow-horizontal-tb-tile-edge.html [ Failure ]
 crbug.com/591099 fast/writing-mode/english-rl-text.html [ Failure ]
 crbug.com/591099 fast/writing-mode/fallback-orientation.html [ Failure ]
+crbug.com/591099 fast/writing-mode/fieldsets.html [ Crash Failure Pass ]
 crbug.com/591099 fast/writing-mode/flipped-blocks-hit-test-line-edges.html [ Failure ]
 crbug.com/591099 fast/writing-mode/flipped-blocks-hit-test-overflow.html [ Failure ]
 crbug.com/591099 fast/writing-mode/flipped-blocks-inline-map-local-to-container.html [ Crash Failure ]
@@ -11540,7 +11568,7 @@
 crbug.com/591099 http/tests/devtools/console/console-uncaught-exception-in-eval.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/console-uncaught-exception.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/console-uncaught-promise-in-worker.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/console/console-uncaught-promise.html [ Failure ]
+crbug.com/591099 http/tests/devtools/console/console-uncaught-promise.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-control.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-selection.html [ Failure ]
 crbug.com/591099 http/tests/devtools/console/console-viewport-stick-to-bottom.html [ Failure Pass ]
@@ -11548,7 +11576,7 @@
 crbug.com/591099 http/tests/devtools/console/console-xpath.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/exception-objects.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/inspect-html-all-collection.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/console/paintworklet-console-selector.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/console/paintworklet-console-selector.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/console/shadow-element.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/worker-eval-contains-stack.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/cookie-resource-match.html [ Failure Pass ]
@@ -11817,16 +11845,23 @@
 crbug.com/591099 http/tests/devtools/modules-load-initial.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/modules-load-network.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/modules-load-source.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/network/network-columns-visible.html [ Crash Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/network/network-cookies-pane.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/devtools/network/network-disable-cache-preloads.php [ Crash Failure ]
 crbug.com/591099 http/tests/devtools/network/network-domain-filter.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-filmstrip-overview-showing.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-filter-http-requests.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-filter-updated-requests.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/devtools/network/network-filters.html [ Crash Failure Timeout ]
+crbug.com/591099 http/tests/devtools/network/network-initiator.html [ Crash Failure Timeout ]
 crbug.com/591099 http/tests/devtools/network/network-json-parser.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/devtools/network/network-memory-cached-resource.html [ Crash Failure ]
 crbug.com/591099 http/tests/devtools/network/network-request-parse-query-params.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-request-query-string.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-toggle-type-filter.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/network/network-update-calculator-for-all-requests.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/network/network-xhr-same-url-as-main-resource.html [ Crash Failure Timeout ]
+crbug.com/591099 http/tests/devtools/network/waterfall-images.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/profiler/agents-disabled-check.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-agent-crash-on-start.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/profiler/cpu-profiler-bottom-up-large-tree-search.html [ Crash Failure Pass ]
@@ -12112,11 +12147,11 @@
 crbug.com/591099 http/tests/devtools/sources/source-code-diff.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/sources-panel-extension-names.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/sources/sources-panel-focus-editor-on-select.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/startup/console/console-uncaught-promise-no-inspector.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/startup/console/console-uncaught-promise-no-inspector.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/startup/sources/debugger/linkifier.html [ Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-breakpoints-1.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-breakpoints-1.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-breakpoints-4.html [ Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-console.html [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/startup/sources/debugger/script-formatter-console.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/startup/tabbed-pane-closeable-persistence-restore.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/devtools/storage-panel-dom-storage-update.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/storage-panel-dom-storage.html [ Failure Pass ]
@@ -12195,7 +12230,7 @@
 crbug.com/591099 http/tests/devtools/tracing/timeline-time/timeline-usertiming.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/tracing/tracing-timeline-load.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/tracing/worker-events.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure ]
+crbug.com/591099 http/tests/devtools/tracing/worker-js-frames.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/devtools/uisourcecode-revisions.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/user-metrics.html [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/version-controller.html [ Failure Pass ]
@@ -12246,6 +12281,9 @@
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-disabled.php [ Crash Timeout ]
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-enabledforall.php [ Timeout ]
 crbug.com/591099 http/tests/feature-policy-experimental-features/vibrate-enabledforself.php [ Crash Timeout ]
+crbug.com/591099 http/tests/feature-policy/fullscreen-disabled.php [ Pass ]
+crbug.com/591099 http/tests/feature-policy/payment-disabled.php [ Pass ]
+crbug.com/591099 http/tests/feature-policy/payment-enabledforall.php [ Pass ]
 crbug.com/591099 http/tests/fetch/window/pageimportancesignals.html [ Failure Pass ]
 crbug.com/591099 http/tests/fileapi/blob-url-in-subframe.html [ Failure Pass ]
 crbug.com/591099 http/tests/fileapi/create-blob-url-from-data-url.html [ Failure Pass ]
@@ -12409,68 +12447,6 @@
 crbug.com/591099 http/tests/inspector/inspect-iframe-from-different-domain.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/inspector/modify-cross-domain-rule.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/inspector/network-preflight-options.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/font-face.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/from-disk-cache-timing.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/har-content.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/json-preview.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/long-script-content.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-blocked-reason.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-cachedresources-with-same-urls.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-choose-preview-view.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-columns-sorted.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-columns-visible.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-content-replacement-xhr.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-cyrillic-xhr.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-datareceived.html [ Crash Failure Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-datasaver-warning.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-disable-cache-cors.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-disable-cache-memory.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-disable-cache-preloads.php [ Crash Failure ]
-crbug.com/591099 http/tests/devtools/network/network-disable-cache-xhrs.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-disabling-check-no-memory-leak.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-document-initiator.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-empty-xhr.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-eventsource.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-fetch-post-payload.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-fetch.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-filters-internals.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-filters.html [ Crash Failure Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-iframe-load-and-delete.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-image-404.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-imported-resource-content.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-initiator-from-console.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-initiator.html [ Crash Failure Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-memory-cached-resource.html [ Crash Failure ]
-crbug.com/591099 http/tests/devtools/network/network-recording-after-reload-with-screenshots-enabled.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-request-revision-content.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-request-type.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-requestblocking-icon.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-timing.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-worker-fetch-blocked.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-worker-fetch-parallel.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-worker-fetch.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-async-response-type-blob.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-async.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-binary-content.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-data-received-async-response-type-blob.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-post-payload.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-redirect-body.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-redirect-method.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-same-url-as-main-resource.html [ Crash Failure Timeout ]
-crbug.com/591099 http/tests/devtools/network/network-xhr-sync.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/network-xsl-content.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/ping-response.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/ping.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/preview-searchable.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/request-name-path.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/request-parameters-decoding.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/resource-priority.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/script-as-text-loading-long-url.html [ Crash Failure Pass Timeout ]
-crbug.com/591099 http/tests/devtools/network/script-as-text-loading-with-caret.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/subresource-integrity-number-of-requests-for-script.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/subresource-integrity-number-of-requests-for-stylesheet.html [ Crash Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/waterfall-images.html [ Failure Pass ]
-crbug.com/591099 http/tests/devtools/network/x-frame-options-deny.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/inspector/persistence/automapping-absolute-paths.html [ Failure Pass ]
 crbug.com/591099 http/tests/inspector/persistence/automapping-dynamic-uisourcecodes.html [ Failure Pass ]
 crbug.com/591099 http/tests/inspector/persistence/automapping-git-folders.html [ Failure Pass ]
@@ -12746,7 +12722,9 @@
 crbug.com/591099 http/tests/navigatorcontentutils/register-protocol-handler.html [ Failure Pass ]
 crbug.com/591099 http/tests/navigatorcontentutils/unregister-protocol-handler.html [ Failure Pass ]
 crbug.com/591099 http/tests/notifications/notification-sandbox-permission.html [ Failure Pass ]
+crbug.com/591099 http/tests/origin_trials/sample-api-workers.html [ Pass ]
 crbug.com/591099 http/tests/permissionclient/image-permissions.html [ Failure Pass ]
+crbug.com/591099 http/tests/permissions/test-api-surface.html [ Pass ]
 crbug.com/591099 http/tests/pointer-lock/iframe-sandboxed-allow-pointer-lock.html [ Failure Pass ]
 crbug.com/591099 http/tests/pointer-lock/iframe-sandboxed-nested-allow-pointer-lock.html [ Failure Pass ]
 crbug.com/591099 http/tests/pointer-lock/iframe-sandboxed-nested-disallow-then-allow-pointer-lock.html [ Failure Pass ]
@@ -13034,6 +13012,7 @@
 crbug.com/591099 http/tests/security/script-onerror-no-crossorigin-cors.html [ Failure Pass ]
 crbug.com/591099 http/tests/security/script-onerror-no-crossorigin-no-cors.html [ Failure Pass ]
 crbug.com/591099 http/tests/security/script-with-failed-cors-check-fails-to-load.html [ Failure Pass ]
+crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Pass ]
 crbug.com/591099 http/tests/security/shape-image-cors-allow-origin.html [ Failure ]
 crbug.com/591099 http/tests/security/shape-image-cors-data-url.html [ Failure ]
 crbug.com/591099 http/tests/security/shape-image-cors-same-origin.html [ Failure ]
@@ -13261,8 +13240,9 @@
 crbug.com/591099 http/tests/websocket/zero-length-text.html [ Failure Pass ]
 crbug.com/591099 http/tests/workers/shared-worker-importScripts.html [ Failure Pass ]
 crbug.com/591099 http/tests/workers/shared-worker-invalid-url.html [ Failure Pass ]
+crbug.com/591099 http/tests/workers/shared-worker-performance-timeline.html [ Pass ]
 crbug.com/591099 http/tests/workers/shared-worker-redirect.html [ Failure Pass ]
-crbug.com/591099 http/tests/workers/terminate-during-sync-operation-file.html [ Failure Pass ]
+crbug.com/591099 http/tests/workers/terminate-during-sync-operation-file.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/workers/terminate-during-sync-operation-filesystem.html [ Failure Pass Timeout ]
 crbug.com/591099 http/tests/workers/worker-importScripts-onerror-crossorigin.html [ Failure Pass ]
 crbug.com/591099 http/tests/workers/worker-importScripts-onerror-redirect-to-crossorigin.html [ Failure Pass ]
@@ -13411,7 +13391,7 @@
 crbug.com/591099 http/tests/xmlhttprequest/response-blob-abort-in-loading-state.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/response-blob-mimetype.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/response-document.html [ Failure Pass Timeout ]
-crbug.com/591099 http/tests/xmlhttprequest/response-encoding.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/xmlhttprequest/response-encoding.html [ Crash Failure Pass Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/response-encoding2.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/response-text.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/responsexml-type.html [ Failure Pass ]
@@ -13463,7 +13443,7 @@
 crbug.com/591099 http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/workers/xmlhttprequest-timeout-override.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/xhr-onunload.html [ Failure Pass ]
-crbug.com/591099 http/tests/xmlhttprequest/xml-encoding.html [ Crash Failure Pass ]
+crbug.com/591099 http/tests/xmlhttprequest/xml-encoding.html [ Crash Failure Pass Timeout ]
 crbug.com/591099 http/tests/xmlhttprequest/xmlhttprequest-abort-readyState-shouldDispatchEvent.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/xmlhttprequest-abort-readyState-shouldNotDispatchEvent.html [ Failure Pass ]
 crbug.com/591099 http/tests/xmlhttprequest/xmlhttprequest-addEventListener-onProgress.html [ Failure Pass ]
@@ -13830,13 +13810,13 @@
 crbug.com/591099 media/W3C/video/src/src_removal_does_not_trigger_loadstart.html [ Failure Pass ]
 crbug.com/591099 media/audio-only-video-intrinsic-size.html [ Failure Pass ]
 crbug.com/591099 media/autoplay/document-user-activation.html [ Failure ]
+crbug.com/591099 media/controls-drag-timebar-rendering.html [ Failure Pass ]
 crbug.com/591099 media/controls-slider-appearance-crash.html [ Failure Pass ]
 crbug.com/591099 media/controls-timeline.html [ Failure ]
 crbug.com/591099 media/controls-volume-slider.html [ Failure ]
 crbug.com/591099 media/controls/paint-controls-webkit-appearance-none-custom-bg.html [ Failure ]
 crbug.com/591099 media/controls/paint-controls-webkit-appearance-none.html [ Failure ]
 crbug.com/591099 media/controls/video-controls-with-cast-rendering.html [ Failure ]
-crbug.com/591099 media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Pass Timeout ]
 crbug.com/591099 media/controls/video-overlay-cast-dark-rendering.html [ Failure ]
 crbug.com/591099 media/controls/video-overlay-cast-light-rendering.html [ Failure ]
 crbug.com/591099 media/fallback.html [ Failure Pass ]
@@ -13856,7 +13836,6 @@
 crbug.com/591099 media/video-canvas-alpha.html [ Failure ]
 crbug.com/591099 media/video-colorspace-yuv420.html [ Failure ]
 crbug.com/591099 media/video-colorspace-yuv422.html [ Failure ]
-crbug.com/591099 media/video-controls-fullscreen.html [ Pass Timeout ]
 crbug.com/591099 media/video-controls-start-selection.html [ Failure Pass ]
 crbug.com/591099 media/video-controls-visible-audio-only.html [ Failure ]
 crbug.com/591099 media/video-controls-with-mutation-event-handler.html [ Failure Pass ]
@@ -14656,8 +14635,10 @@
 crbug.com/591099 printing/page-count-percentage-height.html [ Failure Pass ]
 crbug.com/591099 printing/page-count-relayout-shrink.html [ Failure ]
 crbug.com/591099 printing/page-format-data.html [ Failure Pass ]
+crbug.com/591099 printing/page-height-zero.html [ Failure Pass ]
 crbug.com/591099 printing/page-rule-selection.html [ Failure Pass Timeout ]
 crbug.com/591099 printing/pageNumerForElementById.html [ Failure Pass ]
+crbug.com/591099 printing/pageProperty-with-multicol.html [ Failure Pass ]
 crbug.com/591099 printing/pseudo-class-outside-page.html [ Failure Pass ]
 crbug.com/591099 printing/quirks-percentage-height-body.html [ Failure ]
 crbug.com/591099 printing/quirks-percentage-height.html [ Failure ]
@@ -14672,6 +14653,7 @@
 crbug.com/591099 printing/tfoot-repeats-at-bottom-of-each-page.html [ Failure ]
 crbug.com/591099 printing/thead-repeats-at-top-of-each-page-multiple-tables.html [ Failure ]
 crbug.com/591099 printing/thead-repeats-at-top-of-each-page.html [ Failure ]
+crbug.com/591099 printing/viewport-size-dependant-iframe-with-multicol-crash.html [ Failure Pass ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
 crbug.com/591099 scrollbars/basic-scrollbar.html [ Failure ]
 crbug.com/591099 scrollbars/custom-scrollbar-enable-changes-thickness-with-iframe.html [ Failure Pass ]
@@ -14740,7 +14722,7 @@
 crbug.com/591099 storage/indexeddb/createObjectStore-null-name.html [ Failure Pass ]
 crbug.com/591099 storage/indexeddb/cursor-added-bug.html [ Failure Pass ]
 crbug.com/591099 storage/indexeddb/cursor-advance-workers.html [ Failure Pass Timeout ]
-crbug.com/591099 storage/indexeddb/cursor-advance.html [ Failure Timeout ]
+crbug.com/591099 storage/indexeddb/cursor-advance.html [ Failure Pass Timeout ]
 crbug.com/591099 storage/indexeddb/cursor-basics.html [ Failure Pass ]
 crbug.com/591099 storage/indexeddb/cursor-cast.html [ Failure Pass ]
 crbug.com/591099 storage/indexeddb/cursor-continue-dir.html [ Failure Pass ]
@@ -16192,6 +16174,8 @@
 crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-viewport-parameters-preserved.html [ Failure Pass ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-experimental-features/ [ Skip ]
+crbug.com/591099 virtual/feature-policy/http/tests/feature-policy/payment-disabled.php [ Pass ]
+crbug.com/591099 virtual/feature-policy/http/tests/feature-policy/payment-enabledforall.php [ Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/12-55.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/182.html [ Crash Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/2-comp.html [ Crash Failure ]
@@ -16326,6 +16310,7 @@
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-createImageBitmap-recursive.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-createImageBitmap-svg-no-intrinsic-size.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-animated-images.html [ Crash Failure ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-drawImage-video-imageSmoothingEnabled.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-ellipse-connecting-line.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-hides-fallback.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-imageSmoothingQuality.html [ Crash Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index aef1ff8..3455779 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -274,7 +274,7 @@
 
 ### virtual/layout_ng Mac textarea.
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/float/overhanging-tall-block.html [ Failure ]
-crbug.com/763494 [ Mac ] virtual/layout_ng/fast/block/float/editable-text-overlapping-float.html [ Crash Failure ]
+crbug.com/763494 [ Mac ] virtual/layout_ng/fast/block/float/editable-text-overlapping-float.html [ Failure ]
 
 ### virtual/layout_ng Mac 1px glyph difference.
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/basic/015.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 731e1f4..d4d71a2 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -36647,6 +36647,18 @@
      {}
     ]
    ],
+   "css/css-logical-1/cascading-001.html": [
+    [
+     "/css/css-logical-1/cascading-001.html",
+     [
+      [
+       "/css/css-logical-1/cascading-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-namespaces-3/prefix-001.xml": [
     [
      "/css/css-namespaces-3/prefix-001.xml",
@@ -78181,6 +78193,11 @@
      {}
     ]
    ],
+   "css/css-cascade-3/OWNERS": [
+    [
+     {}
+    ]
+   ],
    "css/css-cascade-3/all-prop-001-ref.html": [
     [
      {}
@@ -78196,6 +78213,11 @@
      {}
     ]
    ],
+   "css/css-cascade-4/OWNERS": [
+    [
+     {}
+    ]
+   ],
    "css/css-cascade-4/reference/ref-filled-green-100px-square.xht": [
     [
      {}
@@ -87936,6 +87958,16 @@
      {}
     ]
    ],
+   "css/css-logical-1/cascading-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-logical-1/resources/style-check.js": [
+    [
+     {}
+    ]
+   ],
    "css/css-namespaces-3/OWNERS": [
     [
      {}
@@ -133545,6 +133577,12 @@
      {}
     ]
    ],
+   "XMLHttpRequest/access-control-sandboxed-iframe-denied-without-wildcard.htm": [
+    [
+     "/XMLHttpRequest/access-control-sandboxed-iframe-denied-without-wildcard.htm",
+     {}
+    ]
+   ],
    "XMLHttpRequest/access-control-sandboxed-iframe-denied.htm": [
     [
      "/XMLHttpRequest/access-control-sandboxed-iframe-denied.htm",
@@ -138541,6 +138579,36 @@
      {}
     ]
    ],
+   "css/css-logical-1/logicalprops-block-size-vlr.html": [
+    [
+     "/css/css-logical-1/logicalprops-block-size-vlr.html",
+     {}
+    ]
+   ],
+   "css/css-logical-1/logicalprops-block-size.html": [
+    [
+     "/css/css-logical-1/logicalprops-block-size.html",
+     {}
+    ]
+   ],
+   "css/css-logical-1/logicalprops-inline-size-vlr.html": [
+    [
+     "/css/css-logical-1/logicalprops-inline-size-vlr.html",
+     {}
+    ]
+   ],
+   "css/css-logical-1/logicalprops-inline-size.html": [
+    [
+     "/css/css-logical-1/logicalprops-inline-size.html",
+     {}
+    ]
+   ],
+   "css/css-logical-1/logicalprops-quirklength.html": [
+    [
+     "/css/css-logical-1/logicalprops-quirklength.html",
+     {}
+    ]
+   ],
    "css/css-position-3/position-sticky-get-bounding-client-rect.html": [
     [
      "/css/css-position-3/position-sticky-get-bounding-client-rect.html",
@@ -197654,6 +197722,10 @@
    "b1140eacc383af590578319b25ee803ba50c3fee",
    "testharness"
   ],
+  "XMLHttpRequest/access-control-sandboxed-iframe-denied-without-wildcard.htm": [
+   "a476086f22c912c13d4ac175af95c80f8e226c25",
+   "testharness"
+  ],
   "XMLHttpRequest/access-control-sandboxed-iframe-denied.htm": [
    "32fcbfa28e93aad6e0040b5b1c9478ce76e7e06e",
    "testharness"
@@ -217018,6 +217090,10 @@
    "c7b1d7a341e34e780c452e9e1ffcfdf0e2f15230",
    "visual"
   ],
+  "css/css-cascade-3/OWNERS": [
+   "f6528390d313cb18665c1f3d1584e809fa85ed17",
+   "support"
+  ],
   "css/css-cascade-3/all-prop-001-ref.html": [
    "257c3381ff5d565a6d5d45716b717fadad8a4922",
    "support"
@@ -217050,6 +217126,10 @@
    "781d92c3b5c5fbccff4921e21cc5d2a8f93ee138",
    "reftest"
   ],
+  "css/css-cascade-4/OWNERS": [
+   "f6528390d313cb18665c1f3d1584e809fa85ed17",
+   "support"
+  ],
   "css/css-cascade-4/reference/ref-filled-green-100px-square.xht": [
    "2f6ee60666fbb65497dc8749683d66ae543bad12",
    "support"
@@ -228886,6 +228966,38 @@
    "e633dc7584fbc7bfe99177aa5dd9fbd107a2d3f5",
    "support"
   ],
+  "css/css-logical-1/cascading-001-ref.html": [
+   "b95cd62ce3592f653aaa54de0dbc27e16618064b",
+   "support"
+  ],
+  "css/css-logical-1/cascading-001.html": [
+   "a94344f196774b463dff39c022a48a0cc5585c88",
+   "reftest"
+  ],
+  "css/css-logical-1/logicalprops-block-size-vlr.html": [
+   "68a86c5b34cf3769e4cda12ef4d23ecdb523734f",
+   "testharness"
+  ],
+  "css/css-logical-1/logicalprops-block-size.html": [
+   "e9597ce04c2b8be8128f9b411e7990bc85d3842a",
+   "testharness"
+  ],
+  "css/css-logical-1/logicalprops-inline-size-vlr.html": [
+   "a0438d0713820ac5ab82f0165af7711f71d91ae6",
+   "testharness"
+  ],
+  "css/css-logical-1/logicalprops-inline-size.html": [
+   "fea8f8205053e933de3dc4490c918c3db69a4a05",
+   "testharness"
+  ],
+  "css/css-logical-1/logicalprops-quirklength.html": [
+   "3024bbd54e4cbe1ee55e59684188587e2a56fda6",
+   "testharness"
+  ],
+  "css/css-logical-1/resources/style-check.js": [
+   "f6260209571bdd53be52c698f072c121e3702dd1",
+   "support"
+  ],
   "css/css-namespaces-3/OWNERS": [
    "f6528390d313cb18665c1f3d1584e809fa85ed17",
    "support"
@@ -271575,11 +271687,11 @@
    "support"
   ],
   "innerText/getter-expected.txt": [
-   "cdc8c4b7628f9ba43ced105850a614a279353e02",
+   "77e80d74e88dbaceb78773b67522423ae1bf7515",
    "support"
   ],
   "innerText/getter-tests.js": [
-   "08171e0a781c05d91841e483d7e18c670c82c827",
+   "e5ec1c1fd4777a1a1c25720047a955ec04c0d014",
    "support"
   ],
   "innerText/getter.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-items/grid-minimum-size-grid-items-021.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-items/grid-minimum-size-grid-items-021.html
index 4a70bde..136872f 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-items/grid-minimum-size-grid-items-021.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-grid-1/grid-items/grid-minimum-size-grid-items-021.html
@@ -68,14 +68,14 @@
   function runTests() {
     checkGridSizeTracksAndImageSize("grid-1", "img-1", "200px", "200px", "200px", "200px", "200px", "200px");
     checkGridSizeTracksAndImageSize("grid-2", "img-2", "10px", "10px", "200px", "200px", "200px", "200px");
-    checkGridSizeTracksAndImageSize("grid-3", "img-3", "200px", "50px", "200px", "50px", "200px", "200px");
-    checkGridSizeTracksAndImageSize("grid-4", "img-4", "200px", "10px", "200px", "50px", "200px", "200px");
+    checkGridSizeTracksAndImageSize("grid-3", "img-3", "200px", "200px", "200px", "200px", "200px", "200px");
+    checkGridSizeTracksAndImageSize("grid-4", "img-4", "200px", "10px", "200px", "200px", "200px", "200px");
     checkGridSizeTracksAndImageSize("grid-5", "img-5", "200px", "50px", "50px", "50px", "50px", "50px");
     checkGridSizeTracksAndImageSize("grid-6", "img-6", "200px", "10px", "50px", "50px", "50px", "50px");
     checkGridSizeTracksAndImageSize("grid-7", "img-7", "200px", "225px", "200px", "200px 25px", "200px", "200px");
     checkGridSizeTracksAndImageSize("grid-8", "img-8", "10px", "10px", "200px", "200px 25px", "200px", "200px");
-    checkGridSizeTracksAndImageSize("grid-9", "img-9", "200px", "125px", "200px", "100px 25px", "200px", "200px");
-    checkGridSizeTracksAndImageSize("grid-10", "img-10", "200px", "10px", "200px", "100px 25px", "200px", "200px");
+    checkGridSizeTracksAndImageSize("grid-9", "img-9", "200px", "225px", "200px", "200px 25px", "200px", "200px");
+    checkGridSizeTracksAndImageSize("grid-10", "img-10", "200px", "10px", "200px", "200px 25px", "200px", "200px");
     checkGridSizeTracksAndImageSize("grid-11", "img-11", "200px", "125px", "100px", "100px 25px", "100px", "100px");
     checkGridSizeTracksAndImageSize("grid-12", "img-12", "200px", "10px", "100px", "100px 25px", "100px", "100px");
     checkGridSizeTracksAndImageSize("grid-13", "img-13", "200px", "200px", "200px", "200px", "200px", "200px");
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001-ref.html
new file mode 100644
index 0000000..79a432c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001-ref.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Logical Properties Cascading Reference</title>
+  <link rel="author" title="Manish Goregaokar" href="mailto:manishearth@gmail.com">
+  <style>
+    div {
+      writing-mode: horizontal-tb;
+      direction: ltr;
+      background-color: blue;
+    }
+    .horizontal {
+      width: 100px;
+      height: 10px;
+    }
+    #horizontal {
+      width: 100px;
+      height: 10px;
+    }
+    .vertical {
+      width: 10px;
+      height: 100px;
+    }
+    #vertical {
+      width: 10px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>Test passes if there are two vertical blue boxes followed by two horizontal blue boxes.</p>
+
+<div class="horizontal" id="vertical"></div><br>
+<div class="horizontal" id="vertical"></div><br>
+<div class="vertical" id="horizontal"></div><br>
+<div class="vertical" id="horizontal"></div><br>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001.html
new file mode 100644
index 0000000..6539255
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/cascading-001.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>CSS Logical Properties: "A computed value that has logical and physical properties is determined by applying the CSS cascade to declarations of both."</title>
+  <link rel="author" title="Manish Goregaokar" href="mailto:manishearth@gmail.com">
+  <link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-box-props">
+  <link rel="match" href="cascading-001-ref.html">
+  <meta name="flags" content="">
+  <meta name="assert" content="Physical property declarations with higher specificity should override logical ones and vice versa.">
+  <style>
+    div {
+      writing-mode: horizontal-tb;
+      direction: ltr;
+      background-color: blue;
+    }
+    .horizontal-logical {
+      inline-size: 100px;
+      block-size: 10px;
+    }
+    #horizontal-logical {
+      inline-size: 100px;
+      block-size: 10px;
+    }
+    .horizontal-physical {
+      width: 100px;
+      height: 10px;
+    }
+    #horizontal-physical {
+      width: 100px;
+      height: 10px;
+    }
+    .vertical-logical {
+      inline-size: 10px;
+      block-size: 100px;
+    }
+    #vertical-logical {
+      inline-size: 10px;
+      block-size: 100px;
+    }
+    .vertical-physical {
+      width: 10px;
+      height: 100px;
+    }
+    #vertical-physical {
+      width: 10px;
+      height: 100px;
+    }
+  </style>
+</head>
+<body>
+  <p>Test passes if there are two vertical blue boxes followed by two horizontal blue boxes.</p>
+<div class="horizontal-logical" id="vertical-physical"></div><br>
+<div class="horizontal-physical" id="vertical-logical"></div><br>
+<div class="vertical-logical" id="horizontal-physical"></div><br>
+<div class="vertical-physical" id="horizontal-logical"></div><br>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size-vlr.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size-vlr.html
new file mode 100644
index 0000000..4c8c13e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size-vlr.html
@@ -0,0 +1,167 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Logical Properties: {max-,min-}block-size vertical-lr</title>
+<link rel="author" title="Xu Xing" href="mailto:openxu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-dimension-properties">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/style-check.js"></script>
+
+<style>
+div {
+  border: 1px solid #000;
+  writing-mode: vertical-lr;
+}
+#div1 {
+  block-size: 40px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#div2 {
+  block-size: 100px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#div3 {
+  block-size: 120px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#ref_div1 {
+  width: 40px;
+  min-width: 50px;
+  max-width: 100px;
+}
+#ref_div2 {
+  width: 100px;
+  min-width: 50px;
+  max-width: 100px;
+}
+#ref_div3 {
+  width: 120px;
+  min-width: 50px;
+  max-width: 100px;
+}
+
+p {
+  border: 1px solid #000;
+  writing-mode: vertical-lr;
+}
+#p1 {
+  block-size: 100px;
+  width: 50px;
+}
+#p2 {
+  width: 50px;
+  block-size: 100px;
+}
+#ref_p1 {
+  width: 50px;
+}
+#ref_p2 {
+  width: 100px;
+}
+
+.table {
+  border: 1px solid #000;
+  display: table;
+  writing-mode: vertical-lr;
+}
+.tablecell {
+  display: table-cell;
+  writing-mode: vertical-lr;
+}
+#table1_cell {
+  block-size: 40px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: red;
+}
+#table2_cell {
+  block-size: 100px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: blue;
+}
+#table3_cell {
+  block-size: 120px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: green;
+}
+#ref_table1_cell {
+  width: 40px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: red;
+}
+#ref_table2_cell {
+  width: 100px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: blue;
+}
+#ref_table3_cell {
+  width: 120px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="div1"></div>
+<div id="div2"></div>
+<div id="div3"></div>
+<div id="ref_div1"></div>
+<div id="ref_div2"></div>
+<div id="ref_div3"></div>
+
+<p id="p1"></div>
+<p id="p2"></div>
+<p id="ref_p1"></div>
+<p id="ref_p2"></div>
+
+<div class="table">
+  <div class="tablecell" id="table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table3_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table3_cell"></div>
+</div>
+
+<script>
+test(function () {
+  assert_true(compareWidthHeight("div1", "ref_div1"));
+  assert_true(compareWidthHeight("div2", "ref_div2"));
+  assert_true(compareWidthHeight("div3", "ref_div3"));
+}, "Check that block-size < min-block-size or min-block-size < block-size <= max-block-size or block-size > max-block-size in vertical-lr");
+
+test(function () {
+  assert_true(compareWidthHeight("p1", "ref_p1"));
+  assert_true(compareWidthHeight("p2", "ref_p2"));
+}, "Check that width override block-size and vice versa in vertical-lr");
+
+test(function () {
+  assert_true(compareWidthHeight("table1_cell", "ref_table1_cell"));
+  assert_true(compareWidthHeight("table2_cell", "ref_table2_cell"));
+  assert_true(compareWidthHeight("table3_cell", "ref_table3_cell"));
+}, "Check that block-size < min-block-size or min-block-size < block-size <= max-block-size or block-size > max-block-size in table vertical-lr");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size.html
new file mode 100644
index 0000000..66cb318
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-block-size.html
@@ -0,0 +1,163 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Logical Properties: {max-,min-}block-size</title>
+<link rel="author" title="Xu Xing" href="mailto:openxu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-dimension-properties">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/style-check.js"></script>
+
+<style>
+div {
+  border: 1px solid #000;
+}
+#div1 {
+  block-size: 40px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#div2 {
+  block-size: 100px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#div3 {
+  block-size: 120px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+}
+#ref_div1 {
+  height: 40px;
+  min-height: 50px;
+  max-height: 100px;
+}
+#ref_div2 {
+  height: 100px;
+  min-height: 50px;
+  max-height: 100px;
+}
+#ref_div3 {
+  height: 120px;
+  min-height: 50px;
+  max-height: 100px;
+}
+
+p {
+  border: 1px solid #000;
+}
+#p1 {
+  block-size: 100px;
+  height: 50px;
+}
+#p2 {
+  height: 50px;
+  block-size: 100px;
+}
+#ref_p1 {
+  height: 50px;
+}
+#ref_p2 {
+  height: 100px;
+}
+
+.table {
+  border: 1px solid #000;
+  display: table;
+}
+.tablecell {
+  display: table-cell;
+}
+#table1_cell {
+  block-size: 40px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: red;
+}
+#table2_cell {
+  block-size: 100px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: blue;
+}
+#table3_cell {
+  block-size: 120px;
+  min-block-size: 50px;
+  max-block-size: 100px;
+  inline-size: 100px;
+  background-color: green;
+}
+#ref_table1_cell {
+  height: 40px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: red;
+}
+#ref_table2_cell {
+  height: 100px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: blue;
+}
+#ref_table3_cell {
+  height: 120px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="div1"></div>
+<div id="div2"></div>
+<div id="div3"></div>
+<div id="ref_div1"></div>
+<div id="ref_div2"></div>
+<div id="ref_div3"></div>
+
+<p id="p1"></div>
+<p id="p2"></div>
+<p id="ref_p1"></div>
+<p id="ref_p2"></div>
+
+<div class="table">
+  <div class="tablecell" id="table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table3_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table3_cell"></div>
+</div>
+
+<script>
+test(function () {
+  assert_true(compareWidthHeight("div1", "ref_div1"));
+  assert_true(compareWidthHeight("div2", "ref_div2"));
+  assert_true(compareWidthHeight("div3", "ref_div3"));
+}, "Check that block-size < min-block-size or min-block-size < block-size <= max-block-size or block-size > max-block-size");
+
+test(function () {
+  assert_true(compareWidthHeight("p1", "ref_p1"));
+  assert_true(compareWidthHeight("p2", "ref_p2"));
+}, "Check that height override block-size and vice versa");
+
+test(function () {
+  assert_true(compareWidthHeight("table1_cell", "ref_table1_cell"));
+  assert_true(compareWidthHeight("table2_cell", "ref_table2_cell"));
+  assert_true(compareWidthHeight("table3_cell", "ref_table3_cell"));
+}, "Check that block-size < min-block-size or min-block-size < block-size <= max-block-size or block-size > max-block-size in table");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size-vlr.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size-vlr.html
new file mode 100644
index 0000000..09e17009
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size-vlr.html
@@ -0,0 +1,167 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Logical Properties: {max-,min-}inline-size vertical-lr</title>
+<link rel="author" title="Xu Xing" href="mailto:openxu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-dimension-properties">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/style-check.js"></script>
+
+<style>
+div {
+  border: 1px solid #000;
+  writing-mode: vertical-lr;
+}
+#div1 {
+  inline-size: 40px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#div2 {
+  inline-size: 100px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#div3 {
+  inline-size: 120px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#ref_div1 {
+  height: 40px;
+  min-height: 50px;
+  max-height: 100px;
+}
+#ref_div2 {
+  height: 100px;
+  min-height: 50px;
+  max-height: 100px;
+}
+#ref_div3 {
+  height: 120px;
+  min-height: 50px;
+  max-height: 100px;
+}
+
+p {
+  border: 1px solid #000;
+  writing-mode: vertical-lr;
+}
+#p1 {
+  inline-size: 100px;
+  height: 50px;
+}
+#p2 {
+  height: 50px;
+  inline-size: 100px;
+}
+#ref_p1 {
+  height: 50px;
+}
+#ref_p2 {
+  height: 100px;
+}
+
+.table {
+  border: 1px solid #000;
+  display: table;
+  writing-mode: vertical-lr;
+}
+.tablecell {
+  display: table-cell;
+  writing-mode: vertical-lr;
+}
+#table1_cell {
+  inline-size: 40px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: red;
+}
+#table2_cell {
+  inline-size: 100px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: blue;
+}
+#table3_cell {
+  inline-size: 120px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: green;
+}
+#ref_table1_cell {
+  height: 40px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: red;
+}
+#ref_table2_cell {
+  height: 100px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: blue;
+}
+#ref_table3_cell {
+  height: 120px;
+  min-height: 50px;
+  max-height: 100px;
+  width: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="div1"></div>
+<div id="div2"></div>
+<div id="div3"></div>
+<div id="ref_div1"></div>
+<div id="ref_div2"></div>
+<div id="ref_div3"></div>
+
+<p id="p1"></div>
+<p id="p2"></div>
+<p id="ref_p1"></div>
+<p id="ref_p2"></div>
+
+<div class="table">
+  <div class="tablecell" id="table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table3_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table3_cell"></div>
+</div>
+
+<script>
+test(function () {
+  assert_true(compareWidthHeight("div1", "ref_div1"));
+  assert_true(compareWidthHeight("div2", "ref_div2"));
+  assert_true(compareWidthHeight("div3", "ref_div3"));
+}, "Check that inline-size < min-inline-size or min-inline-size < inline-size <= max-inline-size or inline-size > max-inline-size in vertical-lr");
+
+test(function () {
+  assert_true(compareWidthHeight("p1", "ref_p1"));
+  assert_true(compareWidthHeight("p2", "ref_p2"));
+}, "Check that height override inline-size and vice versa in vertical-lr");
+
+test(function () {
+  assert_true(compareWidthHeight("table1_cell", "ref_table1_cell"));
+  assert_true(compareWidthHeight("table2_cell", "ref_table2_cell"));
+  assert_true(compareWidthHeight("table3_cell", "ref_table3_cell"));
+}, "Check that inline-size < min-inline-size or min-inline-size < inline-size <= max-inline-size or inline-size > max-inline-size in table vertical-lr");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size.html
new file mode 100644
index 0000000..32ede09
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-inline-size.html
@@ -0,0 +1,163 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>CSS Logical Properties: {max-,min-}inline-size</title>
+<link rel="author" title="Xu Xing" href="mailto:openxu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-dimension-properties">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/style-check.js"></script>
+
+<style>
+div {
+  border: 1px solid #000;
+}
+#div1 {
+  inline-size: 40px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#div2 {
+  inline-size: 100px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#div3 {
+  inline-size: 120px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+}
+#ref_div1 {
+  width: 40px;
+  min-width: 50px;
+  max-width: 100px;
+}
+#ref_div2 {
+  width: 100px;
+  min-width: 50px;
+  max-width: 100px;
+}
+#ref_div3 {
+  width: 120px;
+  min-width: 50px;
+  max-width: 100px;
+}
+
+p {
+  border: 1px solid #000;
+}
+#p1 {
+  inline-size: 100px;
+  width: 50px;
+}
+#p2 {
+  width: 50px;
+  inline-size: 100px;
+}
+#ref_p1 {
+  width: 50px;
+}
+#ref_p2 {
+  width: 100px;
+}
+
+.table {
+  border: 1px solid #000;
+  display: table;
+}
+.tablecell {
+  display: table-cell;
+}
+#table1_cell {
+  inline-size: 40px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: red;
+}
+#table2_cell {
+  inline-size: 100px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: blue;
+}
+#table3_cell {
+  inline-size: 120px;
+  min-inline-size: 50px;
+  max-inline-size: 100px;
+  block-size: 100px;
+  background-color: green;
+}
+#ref_table1_cell {
+  width: 40px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: red;
+}
+#ref_table2_cell {
+  width: 100px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: blue;
+}
+#ref_table3_cell {
+  width: 120px;
+  min-width: 50px;
+  max-width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+
+<div id="div1"></div>
+<div id="div2"></div>
+<div id="div3"></div>
+<div id="ref_div1"></div>
+<div id="ref_div2"></div>
+<div id="ref_div3"></div>
+
+<p id="p1"></div>
+<p id="p2"></div>
+<p id="ref_p1"></div>
+<p id="ref_p2"></div>
+
+<div class="table">
+  <div class="tablecell" id="table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="table3_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table1_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell" id="ref_table2_cell"></div>
+</div>
+<div class="table">
+  <div class="tablecell"  id="ref_table3_cell"></div>
+</div>
+
+<script>
+test(function () {
+  assert_true(compareWidthHeight("div1", "ref_div1"));
+  assert_true(compareWidthHeight("div2", "ref_div2"));
+  assert_true(compareWidthHeight("div3", "ref_div3"));
+}, "Check that inline-size < min-inline-size or min-inline-size < inline-size <= max-inline-size or inline-size > max-inline-size");
+
+test(function () {
+  assert_true(compareWidthHeight("p1", "ref_p1"));
+  assert_true(compareWidthHeight("p2", "ref_p2"));
+}, "Check that width override inline-size and vice versa");
+
+test(function () {
+  assert_true(compareWidthHeight("table1_cell", "ref_table1_cell"));
+  assert_true(compareWidthHeight("table2_cell", "ref_table2_cell"));
+  assert_true(compareWidthHeight("table3_cell", "ref_table3_cell"));
+}, "Check that inline-size < min-inline-size or min-inline-size < inline-size <= max-inline-size or inline-size > max-inline-size in table");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-quirklength.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-quirklength.html
new file mode 100644
index 0000000..0431783
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/logicalprops-quirklength.html
@@ -0,0 +1,30 @@
+<meta charset="utf-8">
+<title>CSS Logical Properties: {max-,min-}block-size</title>
+<link rel="author" title="Xu Xing" href="mailto:openxu@gmail.com">
+<link rel="help" href="https://drafts.csswg.org/css-logical-props-1/#logical-dimension-properties">
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style> #dummy {} </style>
+
+<script>
+function isValidDeclaration(cssText) {
+  var cssRule = document.styleSheets[0].cssRules[0];
+  cssRule.style = cssText;
+  var valid = (cssRule.style.length > 0);
+  cssRule.style = "";
+  return valid;
+}
+var tests = [
+  {cssText:"block-size: 1"},
+  {cssText:"min-block-size: 1"},
+  {cssText:"max-block-size: 1"},
+  {cssText:"inline-size: 1"},
+  {cssText:"min-inline-size: 1"},
+  {cssText:"max-inline-size: 1"},
+];
+tests.forEach(function(t) {
+  test(() => assert_false(isValidDeclaration(t.cssText)), 'Check that "' + t.cssText + '" is not valid in quirks mode');
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/resources/style-check.js b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/resources/style-check.js
new file mode 100644
index 0000000..cd129fd5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-logical-1/resources/style-check.js
@@ -0,0 +1,9 @@
+"use strict";
+function compareWidthHeight(id1, id2) {
+  var element1 = document.getElementById(id1);
+  var style1 = getComputedStyle(element1);
+  var element2 = document.getElementById(id2);
+  var style2 = getComputedStyle(element2);
+  return (style1.width == style2.width) &&
+      (style1.height == style2.height)
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-expected.txt
index ccb6401..0187a02 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 206 tests; 126 PASS, 80 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 213 tests; 126 PASS, 87 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Simplest possible test ("<div>abc")
 PASS Leading whitespace removed ("<div> abc")
 PASS Trailing whitespace removed ("<div>abc ")
@@ -135,6 +135,13 @@
 FAIL No blank lines around <div> with margin ("<div>abc<div style='margin:2em'>def") assert_equals: expected "abc\ndef" but got "abc\ndef\n"
 PASS No newlines at display:inline-block boundary ("<div>123<span style='display:inline-block'>abc</span>def")
 FAIL Leading/trailing space removal at display:inline-block boundary ("<div>123<span style='display:inline-block'> abc </span>def") assert_equals: expected "123abcdef" but got "123 abc def"
+FAIL Blank lines around <p> even without margin ("<div>123<p style='margin:0px'>abc</p>def") assert_equals: expected "123\n\nabc\n\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h1> ("<div>123<h1>abc</h1>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h2> ("<div>123<h2>abc</h2>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h3> ("<div>123<h3>abc</h3>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h4> ("<div>123<h4>abc</h4>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h5> ("<div>123<h5>abc</h5>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
+FAIL No blank lines around <h6> ("<div>123<h6>abc</h6>def") assert_equals: expected "123\nabc\ndef" but got "123\nabc\n\ndef"
 PASS <span> boundaries are irrelevant ("<div>123<span>abc</span>def")
 PASS <span> boundaries are irrelevant ("<div>123 <span>abc</span> def")
 PASS <span> boundaries are irrelevant ("<div style='width:0'>123 <span>abc</span> def")
diff --git a/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-tests.js b/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-tests.js
index 7882be4..6df8912 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-tests.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/innerText/getter-tests.js
@@ -197,6 +197,13 @@
 testText("<div>abc<div style='margin:2em'>def", "abc\ndef", "No blank lines around <div> with margin");
 testText("<div>123<span style='display:inline-block'>abc</span>def", "123abcdef", "No newlines at display:inline-block boundary");
 testText("<div>123<span style='display:inline-block'> abc </span>def", "123abcdef", "Leading/trailing space removal at display:inline-block boundary");
+testText("<div>123<p style='margin:0px'>abc</p>def", "123\n\nabc\n\ndef", "Blank lines around <p> even without margin");
+testText("<div>123<h1>abc</h1>def", "123\nabc\ndef", "No blank lines around <h1>");
+testText("<div>123<h2>abc</h2>def", "123\nabc\ndef", "No blank lines around <h2>");
+testText("<div>123<h3>abc</h3>def", "123\nabc\ndef", "No blank lines around <h3>");
+testText("<div>123<h4>abc</h4>def", "123\nabc\ndef", "No blank lines around <h4>");
+testText("<div>123<h5>abc</h5>def", "123\nabc\ndef", "No blank lines around <h5>");
+testText("<div>123<h6>abc</h6>def", "123\nabc\ndef", "No blank lines around <h6>");
 
 /**** Spans ****/
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/click-window-focus-document.html b/third_party/WebKit/LayoutTests/http/tests/notifications/click-window-focus-document.html
index c2dd86e81..e7d2a64 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/click-window-focus-document.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/click-window-focus-document.html
@@ -33,7 +33,7 @@
               var notification = new Notification('My Notification');
               notification.addEventListener('show', test.step_func(function() {
                   if (window.testRunner)
-                      testRunner.simulateWebNotificationClick('My Notification', -1 /* action_index */);
+                      testRunner.simulateWebNotificationClick('My Notification');
               }));
 
               notification.addEventListener('click', test.step_func(function() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/click-event-test.js b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/click-event-test.js
index 8270016..c9a135e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/click-event-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/click-event-test.js
@@ -12,7 +12,7 @@
     var notification = new Notification('My Notification');
     notification.addEventListener('show', function() {
         if (testRunner)
-            testRunner.simulateWebNotificationClick('My Notification', -1 /* action_index */);
+            testRunner.simulateWebNotificationClick('My Notification');
     });
 
     notification.addEventListener('click', function() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/test-helpers.js b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/test-helpers.js
index b94677f..bbc5e90 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/test-helpers.js
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/test-helpers.js
@@ -7,7 +7,7 @@
 
     messagePort.addEventListener('message', function(message) {
         if (message.data.type == 'simulateWebNotificationClick')
-            testRunner.simulateWebNotificationClick(message.data.title, -1 /* action_index */);
+            testRunner.simulateWebNotificationClick(message.data.title);
     });
 }
 
@@ -85,8 +85,7 @@
 }
 
 // Simulates a click on the notification whose title equals |title|. The |actionIndex| specifies
-// which action button to activate, where -1 means the notification itself is clicked, not an action
-// button.
+// which action button to activate, if any.
 function simulateNotificationClick(title, actionIndex, port)
 {
     return new Promise((resolve, reject) => {
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/worker-helpers.js b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/worker-helpers.js
index 6f0d0e0..8bcf499 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/resources/worker-helpers.js
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/resources/worker-helpers.js
@@ -16,6 +16,6 @@
     simulateWebNotificationClick: function(title, action_index)
     {
         if (_port)
-            _port.postMessage({ type: 'simulateWebNotificationClick', title: title, action_index: action_index });
+            _port.postMessage({ type: 'simulateWebNotificationClick', title, action_index });
     }
 };
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
index 1889a40..a214c7c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notification-event.html
@@ -33,7 +33,7 @@
               });
           }).then(function() {
               // (2) Simulate a click on the notification that has been displayed.
-              testRunner.simulateWebNotificationClick(scope, -1 /* action_index */);
+              testRunner.simulateWebNotificationClick(scope);
 
               workerInfo.port.addEventListener('message', function(event) {
                   if (typeof event.data != 'object' || typeof event.data.success != 'boolean') {
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-action-reflection.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-action-reflection.html
index 67c4390..86c4c024 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-action-reflection.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-action-reflection.html
@@ -47,7 +47,7 @@
               // (3) Simulate a click on each button and on the notification body.
               for (var i = 0; i < options.actions.length; ++i)
                   testRunner.simulateWebNotificationClick(scope, i);
-              testRunner.simulateWebNotificationClick(scope, -1 /* action_index */);
+              testRunner.simulateWebNotificationClick(scope);
 
               port.addEventListener('message', function(event) {
                   // (4) Listen for confirmation from the Service Worker that the
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-data-reflection.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-data-reflection.html
index 570fb24..9c58ba1a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-data-reflection.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-data-reflection.html
@@ -18,7 +18,7 @@
       async_test(function(test) {
           runNotificationDataReflectionTest(test, {
               run: function (scope) {
-                  testRunner.simulateWebNotificationClick(scope, -1 /* action_index */);
+                  testRunner.simulateWebNotificationClick(scope);
               },
               name: 'click'
           });
diff --git a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-reply-reflection.html b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-reply-reflection.html
index 355cf1cd..0882365 100644
--- a/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-reply-reflection.html
+++ b/third_party/WebKit/LayoutTests/http/tests/notifications/serviceworker-notificationclick-event-reply-reflection.html
@@ -38,15 +38,15 @@
               var expectedReplies = [];
               // (3) Simulate some clicks on the notification, with and without replies.
               // (3.1) Simulate a reply to the notification text action.
-              testRunner.simulateWebNotificationClickWithReply(scope, 0 /* action_index */, 'My reply.');
+              testRunner.simulateWebNotificationClick(scope, 0 /* action_index */, 'My reply.');
               expectedReplies.push('My reply.');
 
               // (3.2) Simulate an empty reply to the notification text action.
-              testRunner.simulateWebNotificationClickWithReply(scope, 0 /* action_index */, '');
+              testRunner.simulateWebNotificationClick(scope, 0 /* action_index */, '');
               expectedReplies.push('');
 
               // (3.3) Simulate a click on the notification body (reply should be null).
-              testRunner.simulateWebNotificationClick(scope, -1 /* action_index */);
+              testRunner.simulateWebNotificationClick(scope);
               expectedReplies.push(null);
 
               port.addEventListener('message', function(event) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
index 7aae5e4..69184fb5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/clients-openwindow.html
@@ -58,7 +58,7 @@
         if (message.type !== 'click')
           return;
         if (window.testRunner)
-          testRunner.simulateWebNotificationClick(message.title, -1 /* action_index */);
+          testRunner.simulateWebNotificationClick(message.title);
         return;
       }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-focus.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-focus.html
index 731213f..7816ef7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-focus.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-focus.html
@@ -39,7 +39,7 @@
         if (message.type !== 'click')
           return;
         if (window.testRunner)
-          testRunner.simulateWebNotificationClick(message.title, -1 /* action_index */);
+          testRunner.simulateWebNotificationClick(message.title);
         return;
       }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-openwindow.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-openwindow.html
index ec360362..bf5866c8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-openwindow.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/notificationclick-can-openwindow.html
@@ -39,7 +39,7 @@
         if (message.type !== 'click')
           return;
         if (window.testRunner)
-          testRunner.simulateWebNotificationClick(message.title, -1 /* action_index */);
+          testRunner.simulateWebNotificationClick(message.title);
         return;
       }
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/windowclient-focus.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/windowclient-focus.html
index 971bbf6..0c0e6cf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/windowclient-focus.html
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/chromium/windowclient-focus.html
@@ -74,7 +74,7 @@
             if (message.type !== 'click')
                 return;
             if (window.testRunner)
-                testRunner.simulateWebNotificationClick(message.title, -1 /* action_index */);
+                testRunner.simulateWebNotificationClick(message.title);
             return;
         }
 
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 31203b85..6d86b5b 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -81,8 +81,8 @@
     const CSSParserContext* context) {
   DCHECK(context);
   CSSPropertyParser parser(range, context, nullptr);
-  const CSSValue* value = CSSPropertyParserHelpers::ParseLonghandViaAPI(
-      property, CSSPropertyInvalid, *parser.context_, parser.range_);
+  const CSSValue* value = ParseLonghandViaAPI(property, CSSPropertyInvalid,
+                                              *parser.context_, parser.range_);
   if (!value || !parser.range_.AtEnd())
     return nullptr;
   return value;
@@ -97,16 +97,20 @@
   CSSPropertyID property_id = resolveCSSPropertyID(unresolved_property);
   bool is_shorthand = isShorthandProperty(property_id);
 
+  DCHECK(context_);
   if (is_shorthand) {
     // Variable references will fail to parse here and will fall out to the
     // variable ref parser below.
-    if (ParseShorthand(unresolved_property, important))
+    if (CSSPropertyAPI::Get(property_id)
+            .ParseShorthand(
+                property_id, important, range_, *context_,
+                CSSParserLocalContext(isPropertyAlias(unresolved_property),
+                                      property_id),
+                *parsed_properties_))
       return true;
   } else {
-    DCHECK(context_);
-    if (const CSSValue* parsed_value =
-            CSSPropertyParserHelpers::ParseLonghandViaAPI(
-                unresolved_property, CSSPropertyInvalid, *context_, range_)) {
+    if (const CSSValue* parsed_value = ParseLonghandViaAPI(
+            unresolved_property, CSSPropertyInvalid, *context_, range_)) {
       if (range_.AtEnd()) {
         AddProperty(property_id, CSSPropertyInvalid, *parsed_value, important,
                     IsImplicitProperty::kNotImplicit, *parsed_properties_);
@@ -504,14 +508,4 @@
   }
 }
 
-bool CSSPropertyParser::ParseShorthand(CSSPropertyID unresolved_property,
-                                       bool important) {
-  DCHECK(context_);
-  CSSPropertyID property = resolveCSSPropertyID(unresolved_property);
-  return CSSPropertyAPI::Get(property).ParseShorthand(
-      property, important, range_, *context_,
-      CSSParserLocalContext(isPropertyAlias(unresolved_property), property),
-      *parsed_properties_);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 432dfb2..e4d8963 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -64,12 +64,9 @@
   bool ParseValueStart(CSSPropertyID unresolved_property, bool important);
   bool ConsumeCSSWideKeyword(CSSPropertyID unresolved_property, bool important);
 
-  bool InQuirksMode() const { return IsQuirksModeBehavior(context_->Mode()); }
-
   bool ParseViewportDescriptor(CSSPropertyID prop_id, bool important);
   bool ParseFontFaceDescriptor(CSSPropertyID);
 
-  bool ParseShorthand(CSSPropertyID, bool important);
  private:
   // Inputs:
   CSSParserTokenRange range_;
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
index 1568c160..4a130e5 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.cpp
@@ -88,7 +88,7 @@
 
 std::unique_ptr<blink::WebURLLoader> WorkerShadowPage::CreateURLLoader(
     const WebURLRequest& request,
-    SingleThreadTaskRunner* task_runner) {
+    SingleThreadTaskRunnerRefPtr task_runner) {
   DCHECK(IsMainThread());
   // TODO(yhirano): Stop using Platform::CreateURLLoader() here.
   return Platform::Current()->CreateURLLoader(request, task_runner);
diff --git a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
index da513ca..d844adf 100644
--- a/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
+++ b/third_party/WebKit/Source/core/exported/WorkerShadowPage.h
@@ -68,7 +68,7 @@
   service_manager::InterfaceProvider* GetInterfaceProvider() override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      SingleThreadTaskRunner*) override;
+      SingleThreadTaskRunnerRefPtr) override;
 
   Document* GetDocument() { return main_frame_->GetFrame()->GetDocument(); }
   WebSettings* GetSettings() { return web_view_->GetSettings(); }
diff --git a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
index ee145115..ee69bca 100644
--- a/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
+++ b/third_party/WebKit/Source/core/frame/FrameTestHelpers.h
@@ -382,7 +382,7 @@
   }
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest& request,
-      SingleThreadTaskRunner* task_runner) override {
+      SingleThreadTaskRunnerRefPtr task_runner) override {
     // TODO(yhirano): Stop using Platform::CreateURLLoader() here.
     return Platform::Current()->CreateURLLoader(request, task_runner);
   }
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
index b7400f0..5ec346d9 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.cpp
@@ -2339,8 +2339,8 @@
 
 std::unique_ptr<WebURLLoader> WebLocalFrameImpl::CreateURLLoader(
     const WebURLRequest& request,
-    SingleThreadTaskRunner* task_runner) {
-  return client_->CreateURLLoader(request, task_runner);
+    SingleThreadTaskRunnerRefPtr task_runner) {
+  return client_->CreateURLLoader(request, std::move(task_runner));
 }
 
 void WebLocalFrameImpl::CopyImageAt(const WebPoint& pos_in_viewport) {
@@ -2434,21 +2434,21 @@
   return GetFrame()->FrameScheduler();
 }
 
-SingleThreadTaskRunner* WebLocalFrameImpl::TimerTaskRunner() {
+SingleThreadTaskRunnerRefPtr WebLocalFrameImpl::TimerTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
       ->ThrottleableTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
-SingleThreadTaskRunner* WebLocalFrameImpl::LoadingTaskRunner() {
+SingleThreadTaskRunnerRefPtr WebLocalFrameImpl::LoadingTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
       ->LoadingTaskRunner()
       ->ToSingleThreadTaskRunner();
 }
 
-SingleThreadTaskRunner* WebLocalFrameImpl::UnthrottledTaskRunner() {
+SingleThreadTaskRunnerRefPtr WebLocalFrameImpl::UnthrottledTaskRunner() {
   return GetFrame()
       ->FrameScheduler()
       ->PausableTaskRunner()
diff --git a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
index 80e4e11..43ec08c 100644
--- a/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
+++ b/third_party/WebKit/Source/core/frame/WebLocalFrameImpl.h
@@ -312,9 +312,9 @@
   void ClearActiveFindMatch() override;
   void UsageCountChromeLoadTimes(const WebString& metric) override;
   WebFrameScheduler* Scheduler() const override;
-  SingleThreadTaskRunner* TimerTaskRunner() override;
-  SingleThreadTaskRunner* LoadingTaskRunner() override;
-  SingleThreadTaskRunner* UnthrottledTaskRunner() override;
+  SingleThreadTaskRunnerRefPtr TimerTaskRunner() override;
+  SingleThreadTaskRunnerRefPtr LoadingTaskRunner() override;
+  SingleThreadTaskRunnerRefPtr UnthrottledTaskRunner() override;
   WebInputMethodController* GetInputMethodController() override;
 
   void ExtractSmartClipData(WebRect rect_in_viewport,
@@ -430,7 +430,7 @@
 
   std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      SingleThreadTaskRunner*) override;
+      SingleThreadTaskRunnerRefPtr) override;
 
   WebFrameWidgetBase* LocalRootFrameWidget();
 
diff --git a/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.cpp b/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.cpp
index 400ee97..19436f5 100644
--- a/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.cpp
+++ b/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.cpp
@@ -726,6 +726,7 @@
 void GridTrackSizingAlgorithm::InitializeTrackSizes() {
   DCHECK(content_sized_tracks_index_.IsEmpty());
   DCHECK(flexible_sized_tracks_index_.IsEmpty());
+  DCHECK(auto_sized_tracks_index_.IsEmpty());
   Vector<GridTrack>& track_list = Tracks(direction_);
   bool has_definite_free_space = !!AvailableSpace();
   size_t num_tracks = track_list.size();
@@ -748,6 +749,8 @@
       content_sized_tracks_index_.push_back(i);
     if (track_size.MaxTrackBreadth().IsFlex())
       flexible_sized_tracks_index_.push_back(i);
+    if (track_size.HasAutoMaxTrackBreadth())
+      auto_sized_tracks_index_.push_back(i);
   }
 }
 
@@ -1300,6 +1303,9 @@
 
 void GridTrackSizingAlgorithm::StretchFlexibleTracks(
     Optional<LayoutUnit> free_space) {
+  if (flexible_sized_tracks_index_.IsEmpty())
+    return;
+
   double flex_fraction = strategy_->FindUsedFlexFraction(
       flexible_sized_tracks_index_, direction_, free_space);
 
@@ -1329,6 +1335,34 @@
   max_content_size_ += total_growth;
 }
 
+void GridTrackSizingAlgorithm::StretchAutoTracks() {
+  if (auto_sized_tracks_index_.IsEmpty())
+    return;
+
+  Optional<LayoutUnit> free_space = FreeSpace(direction_);
+  if (!free_space || free_space.value() <= 0 ||
+      (direction_ == kForColumns &&
+       layout_grid_->StyleRef().ResolvedJustifyContentDistribution(
+           layout_grid_->ContentAlignmentNormalBehavior()) !=
+           kContentDistributionStretch) ||
+      (direction_ == kForRows &&
+       layout_grid_->StyleRef().ResolvedAlignContentDistribution(
+           layout_grid_->ContentAlignmentNormalBehavior()) !=
+           kContentDistributionStretch))
+    return;
+
+  unsigned number_of_auto_sized_tracks = auto_sized_tracks_index_.size();
+  LayoutUnit size_to_increase =
+      free_space.value() / number_of_auto_sized_tracks;
+  Vector<GridTrack>& all_tracks = Tracks(direction_);
+  for (const auto& track_index : auto_sized_tracks_index_) {
+    auto& track = all_tracks[track_index];
+    LayoutUnit base_size = track.BaseSize() + size_to_increase;
+    track.SetBaseSize(base_size);
+  }
+  SetFreeSpace(direction_, LayoutUnit());
+}
+
 void GridTrackSizingAlgorithm::AdvanceNextState() {
   switch (sizing_state_) {
     case kColumnSizingFirstIteration:
@@ -1379,6 +1413,7 @@
 
   content_sized_tracks_index_.Shrink(0);
   flexible_sized_tracks_index_.Shrink(0);
+  auto_sized_tracks_index_.Shrink(0);
 
   SetFreeSpace(direction, free_space);
   Tracks(direction).resize(num_tracks);
@@ -1417,11 +1452,11 @@
                                                     ? free_space_columns_
                                                     : free_space_rows_);
 
-  if (flexible_sized_tracks_index_.IsEmpty())
-    return;
-
   // Step 4.
   StretchFlexibleTracks(initial_free_space);
+
+  // Step 5.
+  StretchAutoTracks();
 }
 
 void GridTrackSizingAlgorithm::Reset() {
@@ -1430,6 +1465,7 @@
   rows_.Shrink(0);
   content_sized_tracks_index_.Shrink(0);
   flexible_sized_tracks_index_.Shrink(0);
+  auto_sized_tracks_index_.Shrink(0);
   SetAvailableSpace(kForRows, WTF::nullopt);
   SetAvailableSpace(kForColumns, WTF::nullopt);
 }
diff --git a/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.h b/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.h
index 89d8ce1a..633373d 100644
--- a/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.h
+++ b/third_party/WebKit/Source/core/layout/GridTrackSizingAlgorithm.h
@@ -166,6 +166,7 @@
   void InitializeTrackSizes();
   void ResolveIntrinsicTrackSizes();
   void StretchFlexibleTracks(Optional<LayoutUnit> free_space);
+  void StretchAutoTracks();
 
   // State machine.
   void AdvanceNextState();
@@ -185,6 +186,7 @@
   Vector<GridTrack> rows_;
   Vector<size_t> content_sized_tracks_index_;
   Vector<size_t> flexible_sized_tracks_index_;
+  Vector<size_t> auto_sized_tracks_index_;
 
   GridTrackSizingDirection direction_;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index 7022d5c..a7767582 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -404,9 +404,6 @@
       SetLogicalHeight(
           std::max(LogicalHeight(), MinimumLogicalHeightForEmptyLine()));
 
-    ApplyStretchAlignmentToTracksIfNeeded(kForColumns);
-    ApplyStretchAlignmentToTracksIfNeeded(kForRows);
-
     LayoutGridItems();
     track_sizing_algorithm_.Reset();
 
@@ -1172,44 +1169,6 @@
   return kNormalBehavior;
 }
 
-void LayoutGrid::ApplyStretchAlignmentToTracksIfNeeded(
-    GridTrackSizingDirection direction) {
-  Optional<LayoutUnit> free_space =
-      track_sizing_algorithm_.FreeSpace(direction);
-  if (!free_space || free_space.value() <= 0 ||
-      (direction == kForColumns &&
-       StyleRef().ResolvedJustifyContentDistribution(
-           ContentAlignmentNormalBehavior()) != kContentDistributionStretch) ||
-      (direction == kForRows &&
-       StyleRef().ResolvedAlignContentDistribution(
-           ContentAlignmentNormalBehavior()) != kContentDistributionStretch))
-    return;
-
-  // Spec defines auto-sized tracks as the ones with an 'auto' max-sizing
-  // function.
-  Vector<GridTrack>& all_tracks = track_sizing_algorithm_.Tracks(direction);
-  Vector<unsigned> auto_sized_tracks_index;
-  for (unsigned i = 0; i < all_tracks.size(); ++i) {
-    const GridTrackSize& track_size =
-        track_sizing_algorithm_.GetGridTrackSize(direction, i);
-    if (track_size.HasAutoMaxTrackBreadth())
-      auto_sized_tracks_index.push_back(i);
-  }
-
-  unsigned number_of_auto_sized_tracks = auto_sized_tracks_index.size();
-  if (number_of_auto_sized_tracks < 1)
-    return;
-
-  LayoutUnit size_to_increase =
-      free_space.value() / number_of_auto_sized_tracks;
-  for (const auto& track_index : auto_sized_tracks_index) {
-    GridTrack* track = all_tracks.data() + track_index;
-    LayoutUnit base_size = track->BaseSize() + size_to_increase;
-    track->SetBaseSize(base_size);
-  }
-  track_sizing_algorithm_.SetFreeSpace(direction, LayoutUnit());
-}
-
 void LayoutGrid::LayoutGridItems() {
   PopulateGridPositionsForDirection(kForColumns);
   PopulateGridPositionsForDirection(kForRows);
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h
index da21e8f79..f866800a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.h
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -106,6 +106,8 @@
   LayoutUnit GridGap(GridTrackSizingDirection) const;
   LayoutUnit GridItemOffset(GridTrackSizingDirection) const;
 
+  static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
+
  protected:
   ItemPosition SelfAlignmentNormalBehavior(
       const LayoutBox* child = nullptr) const override {
@@ -211,8 +213,6 @@
       const LayoutBox&,
       GridTrackSizingDirection) const;
 
-  void ApplyStretchAlignmentToTracksIfNeeded(GridTrackSizingDirection);
-
   void PaintChildren(const PaintInfo&, const LayoutPoint&) const override;
 
   LayoutUnit AvailableAlignmentSpaceForChildBeforeStretching(
@@ -297,7 +297,6 @@
                                                       LineDirectionMode);
   static LayoutUnit SynthesizedBaselineFromBorderBox(const LayoutBox&,
                                                      LineDirectionMode);
-  static const StyleContentAlignmentData& ContentAlignmentNormalBehavior();
 
   typedef HashMap<unsigned,
                   std::unique_ptr<BaselineContext>,
diff --git a/third_party/WebKit/Source/platform/CrossThreadCopier.h b/third_party/WebKit/Source/platform/CrossThreadCopier.h
index 37a8c1e..f9cb7aea 100644
--- a/third_party/WebKit/Source/platform/CrossThreadCopier.h
+++ b/third_party/WebKit/Source/platform/CrossThreadCopier.h
@@ -94,13 +94,23 @@
 
 // CrossThreadCopier specializations follow.
 template <typename T>
+struct CrossThreadCopier<PassRefPtr<T>> {
+  STATIC_ONLY(CrossThreadCopier);
+  typedef PassRefPtr<T> Type;
+  static_assert(WTF::IsSubclassOfTemplate<T, ThreadSafeRefCounted>::value,
+                "PassRefPtr<T> can be passed across threads only if T is "
+                "ThreadSafeRefCounted.");
+  static PassRefPtr<T> Copy(PassRefPtr<T>&& pointer) {
+    return std::move(pointer);
+  }
+};
+template <typename T>
 struct CrossThreadCopier<RefPtr<T>>
     : public CrossThreadCopierPassThrough<RefPtr<T>> {
   STATIC_ONLY(CrossThreadCopier);
   static_assert(WTF::IsSubclassOfTemplate<T, ThreadSafeRefCounted>::value,
                 "RefPtr<T> can be passed across threads only if T is "
                 "ThreadSafeRefCounted.");
-  static RefPtr<T> Copy(RefPtr<T> pointer) { return pointer; }
 };
 template <typename T>
 struct CrossThreadCopier<sk_sp<T>>
diff --git a/third_party/WebKit/Source/platform/WebTaskRunner.h b/third_party/WebKit/Source/platform/WebTaskRunner.h
index 8c0a0a7..09f5f61 100644
--- a/third_party/WebKit/Source/platform/WebTaskRunner.h
+++ b/third_party/WebKit/Source/platform/WebTaskRunner.h
@@ -14,15 +14,10 @@
 #include "platform/wtf/WeakPtr.h"
 #include "public/platform/WebCommon.h"
 #include "public/platform/WebTraceLocation.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 namespace blink {
 
-using SingleThreadTaskRunner = base::SingleThreadTaskRunner;
-
 // TaskHandle is associated to a task posted by
 // WebTaskRunner::postCancellableTask or
 // WebTaskRunner::postCancellableDelayedTask and cancels the associated task on
@@ -84,7 +79,7 @@
   virtual double MonotonicallyIncreasingVirtualTimeSeconds() const = 0;
 
   // Returns the underlying task runner object.
-  virtual SingleThreadTaskRunner* ToSingleThreadTaskRunner() = 0;
+  virtual SingleThreadTaskRunnerRefPtr ToSingleThreadTaskRunner() = 0;
 
   // Helpers for posting bound functions as tasks.
 
diff --git a/third_party/WebKit/Source/platform/WebThread.cpp b/third_party/WebKit/Source/platform/WebThread.cpp
index 67e2529..c772eec6 100644
--- a/third_party/WebKit/Source/platform/WebThread.cpp
+++ b/third_party/WebKit/Source/platform/WebThread.cpp
@@ -26,7 +26,7 @@
 #error Unexpected platform
 #endif
 
-base::SingleThreadTaskRunner* WebThread::GetSingleThreadTaskRunner() {
+SingleThreadTaskRunnerRefPtr WebThread::GetSingleThreadTaskRunner() {
   return GetWebTaskRunner()->ToSingleThreadTaskRunner();
 }
 
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 44675ab..2ecfc44f 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -180,7 +180,7 @@
   return file_thread_ ? file_thread_->GetWebTaskRunner() : nullptr;
 }
 
-base::TaskRunner* Platform::BaseFileTaskRunner() const {
+SingleThreadTaskRunnerRefPtr Platform::BaseFileTaskRunner() const {
   return file_thread_ ? file_thread_->GetSingleThreadTaskRunner() : nullptr;
 }
 
diff --git a/third_party/WebKit/Source/platform/exported/WebAudioBus.cpp b/third_party/WebKit/Source/platform/exported/WebAudioBus.cpp
index afe4ac9..462c4d3 100644
--- a/third_party/WebKit/Source/platform/exported/WebAudioBus.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebAudioBus.cpp
@@ -85,7 +85,7 @@
   return private_->Channel(channel_index)->MutableData();
 }
 
-RefPtr<AudioBus> WebAudioBus::Release() {
+PassRefPtr<AudioBus> WebAudioBus::Release() {
   RefPtr<AudioBus> audio_bus(AdoptRef(static_cast<AudioBus*>(private_)));
   private_ = 0;
   return audio_bus;
diff --git a/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeCapsSupport.h b/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeCapsSupport.h
index 82839b7d..3cc9477 100644
--- a/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeCapsSupport.h
+++ b/third_party/WebKit/Source/platform/fonts/opentype/OpenTypeCapsSupport.h
@@ -34,7 +34,6 @@
 
   const HarfBuzzFace* harf_buzz_face_;
   FontDescription::FontVariantCaps requested_caps_;
-  SmallCapsIterator::SmallCapsBehavior run_case_;
 
   enum class FontSupport {
     kFull,
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
index 0825366..d07cde8 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -47,7 +47,7 @@
 
 class Font;
 template <typename TextContainerType>
-class ShapeResultSpacing;
+class PLATFORM_EXPORT ShapeResultSpacing;
 class SimpleFontData;
 class TextRun;
 
@@ -65,7 +65,7 @@
       unsigned count);
   ~ShapeResult();
 
-  // Returns a mutalbe unique instance. If |this| has more than 1 ref count,
+  // Returns a mutable unique instance. If |this| has more than 1 ref count,
   // a clone is created.
   RefPtr<ShapeResult> MutableUnique() const;
 
diff --git a/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.cpp
index b5f9658..cd00401c 100644
--- a/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.cpp
@@ -40,7 +40,7 @@
 
 std::unique_ptr<WebURLLoader> FetchTestingPlatformSupport::CreateURLLoader(
     const blink::WebURLRequest& request,
-    base::SingleThreadTaskRunner* task_runner) {
+    SingleThreadTaskRunnerRefPtr task_runner) {
   return url_loader_mock_factory_->CreateURLLoader(nullptr);
 }
 
diff --git a/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.h b/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.h
index 7bfd833..2b03d5c7 100644
--- a/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.h
+++ b/third_party/WebKit/Source/platform/loader/testing/FetchTestingPlatformSupport.h
@@ -25,7 +25,7 @@
   WebURLLoaderMockFactory* GetURLLoaderMockFactory() override;
   std::unique_ptr<WebURLLoader> CreateURLLoader(
       const blink::WebURLRequest&,
-      base::SingleThreadTaskRunner*) override;
+      SingleThreadTaskRunnerRefPtr) override;
 
  private:
   class FetchTestingWebURLLoaderMockFactory;
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
index 01fb90e..da9b6a9 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.cc
@@ -48,7 +48,8 @@
   return time_domain->Now();
 }
 
-base::SingleThreadTaskRunner* WebTaskRunnerImpl::ToSingleThreadTaskRunner() {
+scoped_refptr<base::SingleThreadTaskRunner>
+WebTaskRunnerImpl::ToSingleThreadTaskRunner() {
   return task_queue_.get();
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
index d5ac48b..005ee08 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/web_task_runner_impl.h
@@ -26,7 +26,8 @@
   bool RunsTasksInCurrentSequence() override;
   double VirtualTimeSeconds() const override;
   double MonotonicallyIncreasingVirtualTimeSeconds() const override;
-  base::SingleThreadTaskRunner* ToSingleThreadTaskRunner() override;
+  scoped_refptr<base::SingleThreadTaskRunner> ToSingleThreadTaskRunner()
+      override;
 
   TaskQueue* GetTaskQueue() const { return task_queue_.get(); }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
index 706b2f4..1e0d3b2 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -104,9 +104,9 @@
   return web_scheduler_.get();
 }
 
-base::SingleThreadTaskRunner* WebThreadImplForWorkerScheduler::GetTaskRunner()
-    const {
-  return task_queue_.get();
+scoped_refptr<base::SingleThreadTaskRunner>
+WebThreadImplForWorkerScheduler::GetTaskRunner() const {
+  return task_queue_;
 }
 
 SingleThreadIdleTaskRunner* WebThreadImplForWorkerScheduler::GetIdleTaskRunner()
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.h b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
index d2722af1..249b846 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
@@ -42,7 +42,7 @@
   WebTaskRunner* GetWebTaskRunner() override;
 
   // WebThreadBase implementation.
-  base::SingleThreadTaskRunner* GetTaskRunner() const override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override;
   scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override;
   void Init() override;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
index c082872..2fad99d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.cc
@@ -33,9 +33,9 @@
   return web_scheduler_.get();
 }
 
-base::SingleThreadTaskRunner* WebThreadImplForRendererScheduler::GetTaskRunner()
+SingleThreadTaskRunnerRefPtr WebThreadImplForRendererScheduler::GetTaskRunner()
     const {
-  return task_runner_.get();
+  return task_runner_;
 }
 
 SingleThreadIdleTaskRunner*
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
index b5020de..7674d4b4 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler.h
@@ -31,7 +31,7 @@
   WebTaskRunner* GetWebTaskRunner() override;
 
   // WebThreadBase implementation.
-  base::SingleThreadTaskRunner* GetTaskRunner() const override;
+  SingleThreadTaskRunnerRefPtr GetTaskRunner() const override;
   SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override;
   void Init() override;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
index a39e5a0..90898b5 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.cc
@@ -94,8 +94,9 @@
   return data_->time_;
 }
 
-SingleThreadTaskRunner* FakeWebTaskRunner::ToSingleThreadTaskRunner() {
-  return base_task_runner_.get();
+scoped_refptr<base::SingleThreadTaskRunner>
+FakeWebTaskRunner::ToSingleThreadTaskRunner() {
+  return base_task_runner_;
 }
 
 void FakeWebTaskRunner::RunUntilIdle() {
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.h b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.h
index b62fb0ef..ba3071d 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_task_runner.h
@@ -28,7 +28,7 @@
   bool RunsTasksInCurrentSequence() override;
   double VirtualTimeSeconds() const override;
   double MonotonicallyIncreasingVirtualTimeSeconds() const override;
-  SingleThreadTaskRunner* ToSingleThreadTaskRunner() override;
+  SingleThreadTaskRunnerRefPtr ToSingleThreadTaskRunner() override;
 
   void RunUntilIdle();
   void AdvanceTimeAndRun(double delta_seconds);
diff --git a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
index b1e0d57..a5db34f 100644
--- a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
+++ b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.cc
@@ -24,9 +24,9 @@
   return thread_id_;
 }
 
-base::SingleThreadTaskRunner* WebThreadImplForUtilityThread::GetTaskRunner()
-    const {
-  return task_runner_.get();
+scoped_refptr<base::SingleThreadTaskRunner>
+WebThreadImplForUtilityThread::GetTaskRunner() const {
+  return task_runner_;
 }
 
 scheduler::SingleThreadIdleTaskRunner*
diff --git a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.h b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.h
index e5b915b..9180e9da 100644
--- a/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.h
+++ b/third_party/WebKit/Source/platform/scheduler/utility/webthread_impl_for_utility_thread.h
@@ -24,7 +24,7 @@
   PlatformThreadId ThreadId() const override;
 
   // WebThreadBase implementation.
-  base::SingleThreadTaskRunner* GetTaskRunner() const override;
+  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner() const override;
   scheduler::SingleThreadIdleTaskRunner* GetIdleTaskRunner() const override;
   void Init() override;
 
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
index 2b5eea1..4f0493f5 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.cpp
@@ -196,9 +196,10 @@
 
 std::unique_ptr<WebURLLoader> TestingPlatformSupport::CreateURLLoader(
     const WebURLRequest& request,
-    base::SingleThreadTaskRunner* runner) {
-  return old_platform_ ? old_platform_->CreateURLLoader(request, runner)
-                       : nullptr;
+    SingleThreadTaskRunnerRefPtr runner) {
+  return old_platform_
+             ? old_platform_->CreateURLLoader(request, std::move(runner))
+             : nullptr;
 }
 
 WebData TestingPlatformSupport::GetDataResource(const char* name) {
diff --git a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
index 34880d9c..8694ac2 100644
--- a/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
+++ b/third_party/WebKit/Source/platform/testing/TestingPlatformSupport.h
@@ -114,7 +114,7 @@
   WebURLLoaderMockFactory* GetURLLoaderMockFactory() override;
   std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      base::SingleThreadTaskRunner*) override;
+      SingleThreadTaskRunnerRefPtr) override;
   WebData GetDataResource(const char* name) override;
   InterfaceProvider* GetInterfaceProvider() override;
 
diff --git a/third_party/WebKit/Source/platform/wtf/Forward.h b/third_party/WebKit/Source/platform/wtf/Forward.h
index a69c4669..c6d12c1d 100644
--- a/third_party/WebKit/Source/platform/wtf/Forward.h
+++ b/third_party/WebKit/Source/platform/wtf/Forward.h
@@ -27,9 +27,9 @@
 namespace WTF {
 
 template <typename T>
-class RefPtr;
+class PassRefPtr;
 template <typename T>
-using PassRefPtr = RefPtr<T>;
+class RefPtr;
 template <typename T>
 class StringBuffer;
 template <typename T, size_t inlineCapacity, typename Allocator>
diff --git a/third_party/WebKit/Source/platform/wtf/Functional.h b/third_party/WebKit/Source/platform/wtf/Functional.h
index ce5c2b4..c85f989 100644
--- a/third_party/WebKit/Source/platform/wtf/Functional.h
+++ b/third_party/WebKit/Source/platform/wtf/Functional.h
@@ -172,6 +172,11 @@
 };
 
 template <typename T>
+struct ParamStorageTraits<PassRefPtr<T>> {
+  typedef RefPtr<T> StorageType;
+};
+
+template <typename T>
 struct ParamStorageTraits<RefPtr<T>> {
   typedef RefPtr<T> StorageType;
 };
diff --git a/third_party/WebKit/Source/platform/wtf/HashFunctions.h b/third_party/WebKit/Source/platform/wtf/HashFunctions.h
index f123973..f1c27b3 100644
--- a/third_party/WebKit/Source/platform/wtf/HashFunctions.h
+++ b/third_party/WebKit/Source/platform/wtf/HashFunctions.h
@@ -150,10 +150,16 @@
 struct RefPtrHash : PtrHash<T> {
   using PtrHash<T>::GetHash;
   static unsigned GetHash(const RefPtr<T>& key) { return GetHash(key.Get()); }
+  static unsigned GetHash(const PassRefPtr<T>& key) {
+    return GetHash(key.Get());
+  }
   using PtrHash<T>::Equal;
   static bool Equal(const RefPtr<T>& a, const RefPtr<T>& b) { return a == b; }
   static bool Equal(T* a, const RefPtr<T>& b) { return a == b; }
   static bool Equal(const RefPtr<T>& a, T* b) { return a == b; }
+  static bool Equal(const RefPtr<T>& a, const PassRefPtr<T>& b) {
+    return a == b;
+  }
 };
 
 template <typename T>
diff --git a/third_party/WebKit/Source/platform/wtf/PassRefPtr.h b/third_party/WebKit/Source/platform/wtf/PassRefPtr.h
index 94e26255..b2d9031 100644
--- a/third_party/WebKit/Source/platform/wtf/PassRefPtr.h
+++ b/third_party/WebKit/Source/platform/wtf/PassRefPtr.h
@@ -29,11 +29,15 @@
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Assertions.h"
 #include "platform/wtf/Compiler.h"
-#include "platform/wtf/Forward.h"
 #include "platform/wtf/TypeTraits.h"
 
 namespace WTF {
 
+template <typename T>
+class RefPtr;
+template <typename T>
+class PassRefPtr;
+
 // requireAdoption() is not overloaded for WTF::RefCounted, which has a built-in
 // assumption that adoption is required. requireAdoption() is for bootstrapping
 // alternate reference count classes that are compatible with RefPtr/PassRefPtr
@@ -57,10 +61,146 @@
 }
 
 template <typename T>
+class PassRefPtr {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
+ public:
+  PassRefPtr() : ptr_(nullptr) {}
+  PassRefPtr(std::nullptr_t) : ptr_(nullptr) {}
+  PassRefPtr(T* ptr) : ptr_(ptr) { RefIfNotNull(ptr); }
+  PassRefPtr(PassRefPtr&& o) : ptr_(o.LeakRef()) {}
+  template <typename U>
+  PassRefPtr(PassRefPtr<U>&& o, EnsurePtrConvertibleArgDecl(U, T))
+      : ptr_(o.LeakRef()) {}
+
+  ALWAYS_INLINE ~PassRefPtr() { DerefIfNotNull(ptr_); }
+
+  template <typename U>
+  PassRefPtr(const RefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
+  template <typename U>
+  PassRefPtr(RefPtr<U>&&, EnsurePtrConvertibleArgDecl(U, T));
+
+  T* Get() const { return ptr_; }
+
+  WARN_UNUSED_RESULT T* LeakRef();
+
+  T& operator*() const { return *ptr_; }
+  T* operator->() const { return ptr_; }
+
+  bool operator!() const { return !ptr_; }
+  explicit operator bool() const { return ptr_ != nullptr; }
+
+ private:
+  PassRefPtr& operator=(const PassRefPtr&) {
+    static_assert(!sizeof(T*), "PassRefPtr should never be assigned to");
+    return *this;
+  }
+
+  T* ptr_;
+};
+
+template <typename T>
 PassRefPtr<T> WrapPassRefPtr(T* ptr) {
   return PassRefPtr<T>(ptr);
 }
 
+template <typename T>
+template <typename U>
+inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o,
+                                 EnsurePtrConvertibleArgDefn(U, T))
+    : ptr_(o.Get()) {
+  T* ptr = ptr_;
+  RefIfNotNull(ptr);
+}
+
+template <typename T>
+template <typename U>
+inline PassRefPtr<T>::PassRefPtr(RefPtr<U>&& o,
+                                 EnsurePtrConvertibleArgDefn(U, T))
+    : ptr_(o.LeakRef()) {}
+
+template <typename T>
+inline T* PassRefPtr<T>::LeakRef() {
+  T* ptr = ptr_;
+  ptr_ = nullptr;
+  return ptr;
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.Get() == b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b) {
+  return a.Get() == b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.Get() == b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, U* b) {
+  return a.Get() == b;
+}
+
+template <typename T, typename U>
+inline bool operator==(T* a, const PassRefPtr<U>& b) {
+  return a == b.Get();
+}
+
+template <typename T>
+inline bool operator==(const PassRefPtr<T>& a, std::nullptr_t) {
+  return !a.Get();
+}
+
+template <typename T>
+inline bool operator==(std::nullptr_t, const PassRefPtr<T>& b) {
+  return !b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.Get() != b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b) {
+  return a.Get() != b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.Get() != b.Get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, U* b) {
+  return a.Get() != b;
+}
+
+template <typename T, typename U>
+inline bool operator!=(T* a, const PassRefPtr<U>& b) {
+  return a != b.Get();
+}
+
+template <typename T>
+inline bool operator!=(const PassRefPtr<T>& a, std::nullptr_t) {
+  return a.Get();
+}
+
+template <typename T>
+inline bool operator!=(std::nullptr_t, const PassRefPtr<T>& b) {
+  return b.Get();
+}
+
+template <typename T>
+inline T* GetPtr(const PassRefPtr<T>& p) {
+  return p.Get();
+}
+
 }  // namespace WTF
 
 using WTF::PassRefPtr;
diff --git a/third_party/WebKit/Source/platform/wtf/RefPtr.h b/third_party/WebKit/Source/platform/wtf/RefPtr.h
index e46a7acc..d24cf24 100644
--- a/third_party/WebKit/Source/platform/wtf/RefPtr.h
+++ b/third_party/WebKit/Source/platform/wtf/RefPtr.h
@@ -32,6 +32,8 @@
 namespace WTF {
 
 template <typename T>
+class PassRefPtr;
+template <typename T>
 class RefPtrValuePeeker;
 template <typename T>
 class RefPtr;
@@ -61,6 +63,11 @@
   RefPtr(RefPtr<U>&& o, EnsurePtrConvertibleArgDecl(U, T))
       : ptr_(o.LeakRef()) {}
 
+  // See comments in PassRefPtr.h for an explanation of why this takes a const
+  // reference.
+  template <typename U>
+  RefPtr(PassRefPtr<U>&&, EnsurePtrConvertibleArgDecl(U, T));
+
   // Hash table deleted values, which are only constructed and never copied or
   // destroyed.
   RefPtr(HashTableDeletedValueType) : ptr_(HashTableDeletedValue()) {}
@@ -106,6 +113,11 @@
 };
 
 template <typename T>
+template <typename U>
+inline RefPtr<T>::RefPtr(PassRefPtr<U>&& o, EnsurePtrConvertibleArgDefn(U, T))
+    : ptr_(o.LeakRef()) {}
+
+template <typename T>
 inline T* RefPtr<T>::LeakRef() {
   T* ptr = ptr_;
   ptr_ = nullptr;
@@ -201,6 +213,8 @@
   ALWAYS_INLINE RefPtrValuePeeker(std::nullptr_t) : ptr_(nullptr) {}
   template <typename U>
   RefPtrValuePeeker(const RefPtr<U>& p) : ptr_(p.Get()) {}
+  template <typename U>
+  RefPtrValuePeeker(const PassRefPtr<U>& p) : ptr_(p.Get()) {}
 
   ALWAYS_INLINE operator T*() const { return ptr_; }
 
diff --git a/third_party/WebKit/public/platform/Platform.h b/third_party/WebKit/public/platform/Platform.h
index de90605..13eabdf 100644
--- a/third_party/WebKit/public/platform/Platform.h
+++ b/third_party/WebKit/public/platform/Platform.h
@@ -63,10 +63,7 @@
 #include "components/viz/common/surfaces/frame_sink_id.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/message_pipe.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 namespace device {
 class Gamepads;
@@ -346,7 +343,7 @@
   // Returns a new WebURLLoader instance.
   virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      base::SingleThreadTaskRunner*) {
+      SingleThreadTaskRunnerRefPtr) {
     return nullptr;
   }
 
@@ -466,7 +463,7 @@
 
   // Returns an interface to the file task runner.
   WebTaskRunner* FileTaskRunner() const;
-  base::TaskRunner* BaseFileTaskRunner() const;
+  SingleThreadTaskRunnerRefPtr BaseFileTaskRunner() const;
 
   // Testing -------------------------------------------------------------
 
diff --git a/third_party/WebKit/public/platform/WebAudioBus.h b/third_party/WebKit/public/platform/WebAudioBus.h
index 0e0a027..6d3ecd3 100644
--- a/third_party/WebKit/public/platform/WebAudioBus.h
+++ b/third_party/WebKit/public/platform/WebAudioBus.h
@@ -30,7 +30,7 @@
 #if INSIDE_BLINK
 namespace WTF {
 template <typename T>
-class RefPtr;
+class PassRefPtr;
 }
 #endif
 
@@ -68,7 +68,7 @@
   float* ChannelData(unsigned channel_index);
 
 #if INSIDE_BLINK
-  WTF::RefPtr<AudioBus> Release();
+  WTF::PassRefPtr<AudioBus> Release();
 #endif
 
  private:
diff --git a/third_party/WebKit/public/platform/WebThread.h b/third_party/WebKit/public/platform/WebThread.h
index 1815f046..4665d522 100644
--- a/third_party/WebKit/public/platform/WebThread.h
+++ b/third_party/WebKit/public/platform/WebThread.h
@@ -26,13 +26,10 @@
 #define WebThread_h
 
 #include "WebCommon.h"
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 #include <stdint.h>
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace blink {
 namespace scheduler {
 class TaskTimeObserver;
@@ -72,7 +69,7 @@
   // manage task priorities and should not be used.
   // Use TaskRunnerHelper::Get instead (crbug.com/624696).
   virtual WebTaskRunner* GetWebTaskRunner() { return nullptr; }
-  base::SingleThreadTaskRunner* GetSingleThreadTaskRunner();
+  SingleThreadTaskRunnerRefPtr GetSingleThreadTaskRunner();
 
   virtual bool IsCurrentThread() const = 0;
   virtual PlatformThreadId ThreadId() const { return 0; }
diff --git a/third_party/WebKit/public/platform/WebWorkerFetchContext.h b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
index 648d745f..2bc8291 100644
--- a/third_party/WebKit/public/platform/WebWorkerFetchContext.h
+++ b/third_party/WebKit/public/platform/WebWorkerFetchContext.h
@@ -10,10 +10,7 @@
 #include "public/platform/WebApplicationCacheHost.h"
 #include "public/platform/WebDocumentSubresourceFilter.h"
 #include "public/platform/WebURL.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 namespace blink {
 
@@ -30,13 +27,13 @@
  public:
   virtual ~WebWorkerFetchContext() {}
 
-  virtual void InitializeOnWorkerThread(base::SingleThreadTaskRunner*) = 0;
+  virtual void InitializeOnWorkerThread(SingleThreadTaskRunnerRefPtr) = 0;
 
   // Returns a new WebURLLoader instance which is associated with the worker
   // thread.
   virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      base::SingleThreadTaskRunner*) = 0;
+      SingleThreadTaskRunnerRefPtr) = 0;
 
   // Called when a request is about to be sent out to modify the request to
   // handle the request correctly in the loading stack later. (Example: service
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h
index 5317044f..5159ecd 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h
+++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerNetworkProvider.h
@@ -34,6 +34,7 @@
 #include <memory>
 
 #include "public/platform/WebURLLoader.h"
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 namespace blink {
 
@@ -72,7 +73,7 @@
   // and only if servicification is enabled.
   virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest& request,
-      base::SingleThreadTaskRunner* task_runner) {
+      SingleThreadTaskRunnerRefPtr task_runner) {
     return nullptr;
   }
 };
diff --git a/third_party/WebKit/public/platform/scheduler/child/webthread_base.h b/third_party/WebKit/public/platform/scheduler/child/webthread_base.h
index 642fd8d..c812d4e 100644
--- a/third_party/WebKit/public/platform/scheduler/child/webthread_base.h
+++ b/third_party/WebKit/public/platform/scheduler/child/webthread_base.h
@@ -13,6 +13,7 @@
 #include "public/platform/WebCommon.h"
 #include "public/platform/WebThread.h"
 #include "public/platform/WebTraceLocation.h"
+#include "public/platform/scheduler/single_thread_task_runner.h"
 
 namespace blink {
 namespace scheduler {
@@ -47,7 +48,7 @@
 
   // Returns the base::Bind-compatible task runner for posting tasks to this
   // thread. Can be called from any thread.
-  virtual base::SingleThreadTaskRunner* GetTaskRunner() const = 0;
+  virtual SingleThreadTaskRunnerRefPtr GetTaskRunner() const = 0;
 
   // Returns the base::Bind-compatible task runner for posting idle tasks to
   // this thread. Can be called from any thread.
diff --git a/third_party/WebKit/public/platform/scheduler/single_thread_task_runner.h b/third_party/WebKit/public/platform/scheduler/single_thread_task_runner.h
new file mode 100644
index 0000000..5b33043
--- /dev/null
+++ b/third_party/WebKit/public/platform/scheduler/single_thread_task_runner.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_SINGLE_THREAD_TASK_RUNNER_H_
+#define THIRD_PARTY_WEBKIT_PUBLIC_PLATFORM_SCHEDULER_SINGLE_THREAD_TASK_RUNNER_H_
+
+#include "base/single_thread_task_runner.h"
+
+// Helper header for passing references to task queues across blink/content
+// boundary. It's explicitly mandated to have a strong reference to
+// a SingleThreadTaskRunner inside Blink.
+//
+// Please use WebTaskRunner inside Blink wherever is possible and consult
+// scheduler-dev@chromium.org if you want to use this.
+
+namespace blink {
+
+using SingleThreadTaskRunnerRefPtr =
+    scoped_refptr<base::SingleThreadTaskRunner>;
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h
index 6611674..c0e00b0 100644
--- a/third_party/WebKit/public/web/WebFrameClient.h
+++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -80,10 +80,6 @@
 class InterfaceProvider;
 }
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace blink {
 namespace mojom {
 enum class WebFeature : int32_t;
@@ -832,7 +828,7 @@
 
   virtual std::unique_ptr<blink::WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      base::SingleThreadTaskRunner*) {
+      SingleThreadTaskRunnerRefPtr) {
     NOTREACHED();
     return nullptr;
   }
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index 4811b37..7916766 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -17,14 +17,11 @@
 #include "public/platform/WebSize.h"
 #include "public/platform/WebURLError.h"
 #include "public/platform/WebURLRequest.h"
+#include "public/platform/scheduler/single_thread_task_runner.h"
 #include "public/platform/site_engagement.mojom-shared.h"
 #include "public/web/WebSandboxFlags.h"
 #include "v8/include/v8.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace blink {
 
 class InterfaceRegistry;
@@ -705,9 +702,9 @@
 
   // Returns frame-specific task runner to run tasks of this type on.
   // They have the same lifetime as the frame.
-  virtual base::SingleThreadTaskRunner* TimerTaskRunner() = 0;
-  virtual base::SingleThreadTaskRunner* LoadingTaskRunner() = 0;
-  virtual base::SingleThreadTaskRunner* UnthrottledTaskRunner() = 0;
+  virtual SingleThreadTaskRunnerRefPtr TimerTaskRunner() = 0;
+  virtual SingleThreadTaskRunnerRefPtr LoadingTaskRunner() = 0;
+  virtual SingleThreadTaskRunnerRefPtr UnthrottledTaskRunner() = 0;
 
   // Returns the WebInputMethodController associated with this local frame.
   virtual WebInputMethodController* GetInputMethodController() = 0;
@@ -718,7 +715,7 @@
   // frame is attached to a document.
   virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest&,
-      base::SingleThreadTaskRunner*) = 0;
+      SingleThreadTaskRunnerRefPtr) = 0;
 
   // Returns an AssociatedURLLoader that is associated with this frame.  The
   // loader will, for example, be cancelled when WebFrame::stopLoading is
diff --git a/tools/perf/page_sets/memory_top_10_mobile.py b/tools/perf/page_sets/memory_top_10_mobile.py
index 0a7239d..e324cfb 100644
--- a/tools/perf/page_sets/memory_top_10_mobile.py
+++ b/tools/perf/page_sets/memory_top_10_mobile.py
@@ -14,15 +14,9 @@
 
 
 class Top10MobileSharedState(shared_page_state.SharedMobilePageState):
-  def __init__(self, test, finder_options, story_set):
-    super(Top10MobileSharedState, self).__init__(
-        test, finder_options, story_set)
-    self._story_set = story_set
-
   def ShouldStopBrowserAfterStoryRun(self, story):
-    # Close the browser after the last story in the set.
-    # TODO(crbug.com/750055): Switch to close after each background page.
-    return self._story_set[-1] == story
+    # Close the browser after each background story.
+    return isinstance(story, BackgroundPage)
 
 
 class MemoryMeasurementPage(page_module.Page):
@@ -58,17 +52,17 @@
   def __init__(self, story_set, name):
     super(BackgroundPage, self).__init__(story_set, name, 'about:blank')
 
-  def RunPageInteractions(self, action_runner):
-    action_runner.tab.WaitForDocumentReadyStateToBeComplete()
-
+  def RunNavigateSteps(self, action_runner):
     # Launch clock app, pushing Chrome to the background.
     android_browser = action_runner.tab.browser
     android_browser.Background()
 
+  def RunPageInteractions(self, action_runner):
     # Take measurement.
     action_runner.MeasureMemory(self.story_set.DETERMINISTIC_MODE)
 
     # Go back to Chrome.
+    android_browser = action_runner.tab.browser
     android_browser.platform.android_action_runner.InputKeyEvent(
         keyevent.KEYCODE_BACK)
 
@@ -86,6 +80,8 @@
       # We name pages so their foreground/background counterparts are easy
       # to identify. For example 'http://google.com' becomes
       # 'http_google_com' and 'after_http_google_com' respectively.
+      # This also allows to use e.g. '--story-filter http_google_com' to
+      # match and run both parts of the story.
       name = re.sub(r'\W+', '_', url)
       self.AddStory(ForegroundPage(self, name, url))
       self.AddStory(BackgroundPage(self, 'after_' + name))