diff --git a/DEPS b/DEPS
index 24171ad6..cfdcf844 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '8aacdbbccf43caf1ed51109609797545d6fad4d3',
+  'v8_revision': '60d37ab26372b10eef25127e1ae3dd5270f73f68',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '5171a27eaa7489939310bd2864864867cc78ce21',
+  'pdfium_revision': '8cb884102c17ef0530277126fd8da054d329d065',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '817b8684be607f1ac5aad1e6ef5713188a8cfb2c',
+  'catapult_revision': 'b33525e9912492df600d3642dbeacfc4f33d92be',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -403,7 +403,7 @@
 
     # For Linux and Chromium OS.
     'src/third_party/cros_system_api':
-      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'ff270ca217a85f02bddcdd78d8cbc9d6a4641572',
+      Var('chromium_git') + '/chromiumos/platform/system_api.git' + '@' + 'd1586d3fcb3ac7152129de96cbe358221ccdca09',
 
     # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
     'src/third_party/chromite':
@@ -1169,7 +1169,7 @@
       'action': [
         'python',
         'src/build/fuchsia/update_sdk.py',
-        '3886a632c4a472fa7ef9eab35b45b63359e387fa',
+        'e250262c2129378374edf66c6f58deea8ca01e17',
       ],
     },
   ],
diff --git a/android_webview/browser/aw_safe_browsing_blocking_page.cc b/android_webview/browser/aw_safe_browsing_blocking_page.cc
index 4ad1cf8..7f505a3a 100644
--- a/android_webview/browser/aw_safe_browsing_blocking_page.cc
+++ b/android_webview/browser/aw_safe_browsing_blocking_page.cc
@@ -72,7 +72,6 @@
             false,  // is_extended_reporting
             false,  // is_scout
             false,  // kSafeBrowsingProceedAnywayDisabled
-            true,   // is_resource_cancellable
             "cpn_safe_browsing_wv");  // help_center_article_link
 
     ErrorUiType errorType =
diff --git a/cc/base/devtools_instrumentation.cc b/cc/base/devtools_instrumentation.cc
index 010b1614..cbf47b35 100644
--- a/cc/base/devtools_instrumentation.cc
+++ b/cc/base/devtools_instrumentation.cc
@@ -30,5 +30,50 @@
 extern const char kPaintSetup[] = "PaintSetup";
 extern const char kUpdateLayer[] = "UpdateLayer";
 
+ScopedImageDecodeTask::ScopedImageDecodeTask(const void* image_ptr,
+                                             DecodeType decode_type,
+                                             TaskType task_type)
+    : decode_type_(decode_type),
+      task_type_(task_type),
+      start_time_(base::TimeTicks::Now()) {
+  TRACE_EVENT_BEGIN1(internal::kCategory, internal::kImageDecodeTask,
+                     internal::kPixelRefId,
+                     reinterpret_cast<uint64_t>(image_ptr));
+}
+
+ScopedImageDecodeTask::~ScopedImageDecodeTask() {
+  TRACE_EVENT_END0(internal::kCategory, internal::kImageDecodeTask);
+  base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
+  switch (task_type_) {
+    case kInRaster:
+      switch (decode_type_) {
+        case kSoftware:
+          UMA_HISTOGRAM_COUNTS_1M(
+              "Renderer4.ImageDecodeTaskDurationUs.Software",
+              duration.InMicroseconds());
+          break;
+        case kGpu:
+          UMA_HISTOGRAM_COUNTS_1M("Renderer4.ImageDecodeTaskDurationUs.Gpu",
+                                  duration.InMicroseconds());
+          break;
+      }
+      break;
+    case kOutOfRaster:
+      switch (decode_type_) {
+        case kSoftware:
+          UMA_HISTOGRAM_COUNTS_1M(
+              "Renderer4.ImageDecodeTaskDurationUs.OutOfRaster.Software",
+              duration.InMicroseconds());
+          break;
+        case kGpu:
+          UMA_HISTOGRAM_COUNTS_1M(
+              "Renderer4.ImageDecodeTaskDurationUs.OutOfRaster.Gpu",
+              duration.InMicroseconds());
+          break;
+      }
+      break;
+  }
+}
+
 }  // namespace devtools_instrumentation
 }  // namespace cc
diff --git a/cc/base/devtools_instrumentation.h b/cc/base/devtools_instrumentation.h
index 40e2d9e..0562877 100644
--- a/cc/base/devtools_instrumentation.h
+++ b/cc/base/devtools_instrumentation.h
@@ -57,31 +57,17 @@
 
 class CC_BASE_EXPORT ScopedImageDecodeTask {
  public:
-  enum Type { SOFTWARE, GPU };
+  enum DecodeType { kSoftware, kGpu };
+  enum TaskType { kInRaster, kOutOfRaster };
 
-  ScopedImageDecodeTask(const void* imagePtr, Type type)
-      : type_(type), start_time_(base::TimeTicks::Now()) {
-    TRACE_EVENT_BEGIN1(internal::kCategory, internal::kImageDecodeTask,
-                       internal::kPixelRefId,
-                       reinterpret_cast<uint64_t>(imagePtr));
-  }
-  ~ScopedImageDecodeTask() {
-    TRACE_EVENT_END0(internal::kCategory, internal::kImageDecodeTask);
-    base::TimeDelta duration = base::TimeTicks::Now() - start_time_;
-    switch (type_) {
-      case SOFTWARE:
-        UMA_HISTOGRAM_COUNTS_1M("Renderer4.ImageDecodeTaskDurationUs.Software",
-                                duration.InMicroseconds());
-        break;
-      case GPU:
-        UMA_HISTOGRAM_COUNTS_1M("Renderer4.ImageDecodeTaskDurationUs.Gpu",
-                                duration.InMicroseconds());
-        break;
-    }
-  }
+  ScopedImageDecodeTask(const void* image_ptr,
+                        DecodeType decode_type,
+                        TaskType task_type);
+  ~ScopedImageDecodeTask();
 
  private:
-  const Type type_;
+  const DecodeType decode_type_;
+  const TaskType task_type_;
   const base::TimeTicks start_time_;
   DISALLOW_COPY_AND_ASSIGN(ScopedImageDecodeTask);
 };
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index b2d98eea2..7b29b32 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -101,10 +101,9 @@
     return false;
 
   if (!updater_) {
-    updater_.reset(new VideoResourceUpdater(
-        layer_tree_impl()->context_provider(),
-        layer_tree_impl()->resource_provider(),
-        layer_tree_impl()->settings().use_stream_video_draw_quad));
+    updater_.reset(
+        new VideoResourceUpdater(layer_tree_impl()->context_provider(),
+                                 layer_tree_impl()->resource_provider()));
   }
 
   VideoFrameExternalResources external_resources =
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index ce4c650..e8215673 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -915,13 +915,12 @@
  public:
   void SetUp() override {
     IntersectingQuadPixelTest<TypeParam>::SetUp();
-    bool use_stream_video_draw_quad = false;
-    video_resource_updater_.reset(new VideoResourceUpdater(
-        this->output_surface_->context_provider(),
-        this->resource_provider_.get(), use_stream_video_draw_quad));
-    video_resource_updater2_.reset(new VideoResourceUpdater(
-        this->output_surface_->context_provider(),
-        this->resource_provider_.get(), use_stream_video_draw_quad));
+    video_resource_updater_.reset(
+        new VideoResourceUpdater(this->output_surface_->context_provider(),
+                                 this->resource_provider_.get()));
+    video_resource_updater2_.reset(
+        new VideoResourceUpdater(this->output_surface_->context_provider(),
+                                 this->resource_provider_.get()));
   }
 
  protected:
@@ -1242,10 +1241,8 @@
 
   void SetUp() override {
     GLRendererPixelTest::SetUp();
-    bool use_stream_video_draw_quad = false;
     video_resource_updater_.reset(new VideoResourceUpdater(
-        output_surface_->context_provider(), resource_provider_.get(),
-        use_stream_video_draw_quad));
+        output_surface_->context_provider(), resource_provider_.get()));
   }
 
   std::unique_ptr<VideoResourceUpdater> video_resource_updater_;
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 62007f9..9e69758 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -35,8 +35,7 @@
 const ResourceFormat kRGBResourceFormat = RGBA_8888;
 
 VideoFrameExternalResources::ResourceType ResourceTypeForVideoFrame(
-    media::VideoFrame* video_frame,
-    bool use_stream_video_draw_quad) {
+    media::VideoFrame* video_frame) {
   switch (video_frame->format()) {
     case media::PIXEL_FORMAT_ARGB:
     case media::PIXEL_FORMAT_XRGB:
@@ -47,11 +46,10 @@
                      ? VideoFrameExternalResources::RGB_RESOURCE
                      : VideoFrameExternalResources::RGBA_PREMULTIPLIED_RESOURCE;
         case GL_TEXTURE_EXTERNAL_OES:
-          if (use_stream_video_draw_quad &&
-              !video_frame->metadata()->IsTrue(
-                  media::VideoFrameMetadata::COPY_REQUIRED))
-            return VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
-          return VideoFrameExternalResources::RGBA_RESOURCE;
+          return video_frame->metadata()->IsTrue(
+                     media::VideoFrameMetadata::COPY_REQUIRED)
+                     ? VideoFrameExternalResources::RGBA_RESOURCE
+                     : VideoFrameExternalResources::STREAM_TEXTURE_RESOURCE;
         case GL_TEXTURE_RECTANGLE_ARB:
           return VideoFrameExternalResources::RGB_RESOURCE;
         default:
@@ -174,11 +172,9 @@
 VideoFrameExternalResources::~VideoFrameExternalResources() {}
 
 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider,
-                                           ResourceProvider* resource_provider,
-                                           bool use_stream_video_draw_quad)
+                                           ResourceProvider* resource_provider)
     : context_provider_(context_provider),
       resource_provider_(resource_provider),
-      use_stream_video_draw_quad_(use_stream_video_draw_quad),
       weak_ptr_factory_(this) {}
 
 VideoResourceUpdater::~VideoResourceUpdater() {
@@ -634,8 +630,7 @@
   }
   gfx::ColorSpace resource_color_space = video_frame->ColorSpace();
 
-  external_resources.type =
-      ResourceTypeForVideoFrame(video_frame.get(), use_stream_video_draw_quad_);
+  external_resources.type = ResourceTypeForVideoFrame(video_frame.get());
   if (external_resources.type == VideoFrameExternalResources::NONE) {
     DLOG(ERROR) << "Unsupported Texture format"
                 << media::VideoPixelFormatToString(video_frame->format());
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index c00b9fc..f5f949c 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -73,8 +73,7 @@
 class CC_EXPORT VideoResourceUpdater {
  public:
   VideoResourceUpdater(ContextProvider* context_provider,
-                       ResourceProvider* resource_provider,
-                       bool use_stream_video_draw_quad);
+                       ResourceProvider* resource_provider);
   ~VideoResourceUpdater();
 
   VideoFrameExternalResources CreateExternalResourcesFromVideoFrame(
@@ -176,7 +175,6 @@
 
   ContextProvider* context_provider_;
   ResourceProvider* resource_provider_;
-  const bool use_stream_video_draw_quad_;
   std::unique_ptr<media::SkCanvasVideoRenderer> video_renderer_;
   std::vector<uint8_t> upload_pixels_;
 
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 3a9e6bf0..3c7874e4 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -249,10 +249,8 @@
 };
 
 TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
@@ -261,10 +259,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, HighBitFrameNoF16) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
@@ -280,10 +276,8 @@
 };
 
 TEST_F(VideoResourceUpdaterTestWithF16, HighBitFrame) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
@@ -302,9 +296,7 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, HighBitFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
-                               use_stream_video_draw_quad);
+  VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestHighBitFrame();
 
   VideoFrameExternalResources resources =
@@ -313,10 +305,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrame) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
@@ -325,9 +315,7 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, WonkySoftwareFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
-                               use_stream_video_draw_quad);
+  VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateWonkyTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
@@ -336,10 +324,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResource) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
@@ -370,10 +356,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDelete) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
@@ -399,9 +383,7 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
-                               use_stream_video_draw_quad);
+  VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
 
   VideoFrameExternalResources resources =
@@ -410,9 +392,7 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
-                               use_stream_video_draw_quad);
+  VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
@@ -443,9 +423,7 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDeleteSoftwareCompositor) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(nullptr, resource_provider_software_.get(),
-                               use_stream_video_draw_quad);
+  VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
   scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
   video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
 
@@ -472,10 +450,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes) {
-  bool use_stream_video_draw_quad = false;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
 
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestRGBAHardwareVideoFrame();
@@ -506,10 +482,8 @@
 }
 
 TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_StreamTexture) {
-  bool use_stream_video_draw_quad = true;
   VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
+                               resource_provider3d_.get());
   context3d_->ResetTextureCreationCount();
   scoped_refptr<media::VideoFrame> video_frame =
       CreateTestStreamTextureHardwareVideoFrame(false);
@@ -545,24 +519,5 @@
   EXPECT_FALSE(context3d_->WasImmutableTextureCreated());
 }
 
-TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_TextureQuad) {
-  bool use_stream_video_draw_quad = false;
-  VideoResourceUpdater updater(context_provider_.get(),
-                               resource_provider3d_.get(),
-                               use_stream_video_draw_quad);
-  context3d_->ResetTextureCreationCount();
-  scoped_refptr<media::VideoFrame> video_frame =
-      CreateTestStreamTextureHardwareVideoFrame(false);
-
-  VideoFrameExternalResources resources =
-      updater.CreateExternalResourcesFromVideoFrame(video_frame);
-  EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE, resources.type);
-  EXPECT_EQ(1u, resources.mailboxes.size());
-  EXPECT_EQ((GLenum)GL_TEXTURE_EXTERNAL_OES, resources.mailboxes[0].target());
-  EXPECT_EQ(1u, resources.release_callbacks.size());
-  EXPECT_EQ(0u, resources.software_resources.size());
-  EXPECT_EQ(0, context3d_->TextureCreationCount());
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index a194751..8ec875f65 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -173,7 +173,8 @@
                  "source_prepare_tiles_id", tracing_info_.prepare_tiles_id);
     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
         image_.image().get(),
-        devtools_instrumentation::ScopedImageDecodeTask::GPU);
+        devtools_instrumentation::ScopedImageDecodeTask::kGpu,
+        ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type));
     cache_->DecodeImage(image_);
   }
 
@@ -399,6 +400,7 @@
 bool GpuImageDecodeCache::GetTaskForImageAndRef(const DrawImage& draw_image,
                                                 const TracingInfo& tracing_info,
                                                 scoped_refptr<TileTask>* task) {
+  DCHECK_EQ(tracing_info.task_type, TaskType::kInRaster);
   return GetTaskForImageAndRefInternal(
       draw_image, tracing_info, DecodeTaskType::PART_OF_UPLOAD_TASK, task);
 }
@@ -407,7 +409,8 @@
     const DrawImage& draw_image,
     scoped_refptr<TileTask>* task) {
   return GetTaskForImageAndRefInternal(
-      draw_image, TracingInfo(), DecodeTaskType::STAND_ALONE_DECODE_TASK, task);
+      draw_image, TracingInfo(0, TilePriority::NOW, TaskType::kOutOfRaster),
+      DecodeTaskType::STAND_ALONE_DECODE_TASK, task);
 }
 
 bool GpuImageDecodeCache::GetTaskForImageAndRefInternal(
diff --git a/cc/tiles/image_decode_cache.h b/cc/tiles/image_decode_cache.h
index 1b550a6..d0bf7be7 100644
--- a/cc/tiles/image_decode_cache.h
+++ b/cc/tiles/image_decode_cache.h
@@ -6,6 +6,7 @@
 #define CC_TILES_IMAGE_DECODE_CACHE_H_
 
 #include "base/memory/ref_counted.h"
+#include "cc/base/devtools_instrumentation.h"
 #include "cc/paint/draw_image.h"
 #include "cc/tiles/decoded_draw_image.h"
 #include "cc/tiles/tile_priority.h"
@@ -34,22 +35,43 @@
 //    thread.
 class CC_EXPORT ImageDecodeCache {
  public:
+  enum class TaskType { kInRaster, kOutOfRaster };
+
   // This information should be used strictly in tracing, UMA, and any other
   // reporting systems.
   struct TracingInfo {
     TracingInfo(uint64_t prepare_tiles_id,
-                TilePriority::PriorityBin requesting_tile_bin)
+                TilePriority::PriorityBin requesting_tile_bin,
+                TaskType task_type)
         : prepare_tiles_id(prepare_tiles_id),
-          requesting_tile_bin(requesting_tile_bin) {}
-    TracingInfo() : TracingInfo(0, TilePriority::NOW) {}
+          requesting_tile_bin(requesting_tile_bin),
+          task_type(task_type) {}
+    TracingInfo() = default;
 
     // ID for the current prepare tiles call.
-    const uint64_t prepare_tiles_id;
+    const uint64_t prepare_tiles_id = 0;
 
     // The bin of the tile that caused this image to be requested.
-    const TilePriority::PriorityBin requesting_tile_bin;
+    const TilePriority::PriorityBin requesting_tile_bin = TilePriority::NOW;
+
+    // Whether the decode is requested as a part of tile rasterization.
+    const TaskType task_type = TaskType::kInRaster;
   };
 
+  static devtools_instrumentation::ScopedImageDecodeTask::TaskType
+  ToScopedTaskType(TaskType task_type) {
+    using ScopedTaskType =
+        devtools_instrumentation::ScopedImageDecodeTask::TaskType;
+    switch (task_type) {
+      case TaskType::kInRaster:
+        return ScopedTaskType::kInRaster;
+      case TaskType::kOutOfRaster:
+        return ScopedTaskType::kOutOfRaster;
+    }
+    NOTREACHED();
+    return ScopedTaskType::kInRaster;
+  }
+
   virtual ~ImageDecodeCache() {}
 
   // Fill in an TileTask which will decode the given image when run. In
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index 68b85db..3a27f3b 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -113,7 +113,8 @@
                  tracing_info_.prepare_tiles_id);
     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
         image_.image().get(),
-        devtools_instrumentation::ScopedImageDecodeTask::SOFTWARE);
+        devtools_instrumentation::ScopedImageDecodeTask::kSoftware,
+        ImageDecodeCache::ToScopedTaskType(tracing_info_.task_type));
     cache_->DecodeImage(image_key_, image_, task_type_);
   }
 
@@ -227,6 +228,7 @@
     const DrawImage& image,
     const TracingInfo& tracing_info,
     scoped_refptr<TileTask>* task) {
+  DCHECK_EQ(tracing_info.task_type, TaskType::kInRaster);
   return GetTaskForImageAndRefInternal(
       image, tracing_info, DecodeTaskType::USE_IN_RASTER_TASKS, task);
 }
@@ -235,7 +237,8 @@
     const DrawImage& image,
     scoped_refptr<TileTask>* task) {
   return GetTaskForImageAndRefInternal(
-      image, TracingInfo(), DecodeTaskType::USE_OUT_OF_RASTER_TASKS, task);
+      image, TracingInfo(0, TilePriority::NOW, TaskType::kOutOfRaster),
+      DecodeTaskType::USE_OUT_OF_RASTER_TASKS, task);
 }
 
 bool SoftwareImageDecodeCache::GetTaskForImageAndRefInternal(
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index b34cbb8f..4db308b 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -986,8 +986,9 @@
   // TODO(vmpstr): SOON is misleading here, but these images can come from
   // several diffent tiles. Rethink what we actually want to trace here. Note
   // that I'm using SOON, since it can't be NOW (these are prepaint).
-  ImageDecodeCache::TracingInfo tracing_info(prepare_tiles_count_,
-                                             TilePriority::SOON);
+  ImageDecodeCache::TracingInfo tracing_info(
+      prepare_tiles_count_, TilePriority::SOON,
+      ImageDecodeCache::TaskType::kInRaster);
   std::vector<scoped_refptr<TileTask>> new_locked_image_tasks =
       image_controller_.SetPredecodeImages(std::move(new_locked_images),
                                            tracing_info);
@@ -1121,7 +1122,8 @@
 
   // Get the tasks for the required images.
   ImageDecodeCache::TracingInfo tracing_info(
-      prepare_tiles_count_, prioritized_tile.priority().priority_bin);
+      prepare_tiles_count_, prioritized_tile.priority().priority_bin,
+      ImageDecodeCache::TaskType::kInRaster);
   image_controller_.GetTasksForImagesAndRef(&sync_decoded_images, &decode_tasks,
                                             tracing_info);
 
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index ed16071..0a5a564 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -45,7 +45,6 @@
   int gpu_rasterization_msaa_sample_count = 0;
   float gpu_rasterization_skewport_target_time_in_seconds = 0.2f;
   bool create_low_res_tiling = false;
-  bool use_stream_video_draw_quad = false;
 
   enum ScrollbarAnimator {
     NO_ANIMATOR,
diff --git a/chrome/VERSION b/chrome/VERSION
index 72985c5..53080fca 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=61
 MINOR=0
-BUILD=3118
+BUILD=3119
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 7075f12..1b5e0a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -727,8 +727,9 @@
         if ((selectionStartAdjust != 0 || selectionEndAdjust != 0)
                 && mSelectionController.getSelectionType() == SelectionType.TAP) {
             String originalSelection = mContext == null ? null : mContext.getInitialSelectedWord();
-            if (originalSelection != null
-                    && originalSelection.equals(mSelectionController.getSelectedText())) {
+            String currentSelection = mSelectionController.getSelectedText();
+            if (currentSelection != null) currentSelection = currentSelection.trim();
+            if (originalSelection != null && originalSelection.trim().equals(currentSelection)) {
                 mSelectionController.adjustSelection(selectionStartAdjust, selectionEndAdjust);
                 mContext.onSelectionAdjusted(selectionStartAdjust, selectionEndAdjust);
             }
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index 2755e15..b9229eb8 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -35,14 +35,6 @@
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
-namespace {
-
-bool IsInfoEmpty(const std::unique_ptr<ShortcutInfo>& info) {
-  return !info || info->url.is_empty();
-}
-
-}  // anonymous namespace
-
 namespace banners {
 
 // static
@@ -56,7 +48,11 @@
     int event_request_id,
     bool is_webapk,
     webapk::InstallSource webapk_install_source) {
+  DCHECK(shortcut_info);
   const GURL url = shortcut_info->url;
+  if (url.is_empty())
+    return false;
+
   auto infobar_delegate =
       base::WrapUnique(new banners::AppBannerInfoBarDelegateAndroid(
           weak_manager, app_title, std::move(shortcut_info), primary_icon,
@@ -225,7 +221,6 @@
       install_state_(INSTALL_NOT_STARTED),
       webapk_install_source_(webapk_install_source),
       weak_ptr_factory_(this) {
-  DCHECK(!IsInfoEmpty(shortcut_info_));
   CreateJavaDelegate();
 }
 
@@ -280,8 +275,6 @@
 
 bool AppBannerInfoBarDelegateAndroid::AcceptWebApp(
     content::WebContents* web_contents) {
-  if (IsInfoEmpty(shortcut_info_))
-    return true;
   TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
 
   AppBannerSettingsHelper::RecordBannerInstallEvent(
@@ -296,9 +289,6 @@
 
 bool AppBannerInfoBarDelegateAndroid::AcceptWebApk(
     content::WebContents* web_contents) {
-  if (IsInfoEmpty(shortcut_info_))
-    return true;
-
   JNIEnv* env = base::android::AttachCurrentThread();
 
   // If the WebAPK is installed and the "Open" button is clicked, open the
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index 8d75f13b..80defa34 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -2,6 +2,11 @@
   # TODO(crbug.com/678705): Convert to using mojo interfaces in
   # //ash/public/interfaces and eliminate this.
   "+ash",
+  
+  #TODO(ananta): Remove this when we move files which display UI in
+  # chrome/browser/chromeos to chrome/browser/ui/views/chromeos
+  # crbug.com/728877
+  "+chrome/browser/ui/views/harmony/chrome_layout_provider.h",
 
   "+components/constrained_window",
   "+components/drive/drive_pref_names.h",
diff --git a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
index b88bc77..52565f8 100644
--- a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
+++ b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/singleton_tabs.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
@@ -27,7 +28,6 @@
 #include "ui/views/border.h"
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -75,8 +75,11 @@
       domain_(domain),
       callback_(callback) {
   SetLayoutManager(new views::FillLayout());
-  SetBorder(views::CreateEmptyBorder(0, views::kButtonHEdgeMarginNew, 0,
-                                     views::kButtonHEdgeMarginNew));
+
+  gfx::Insets dialog_insets = ChromeLayoutProvider::Get()->GetInsetsMetric(
+      views::INSETS_DIALOG_CONTENTS);
+  SetBorder(views::CreateEmptyBorder(0, dialog_insets.left(), 0,
+                                     dialog_insets.right()));
   const base::string16 learn_more = l10n_util::GetStringUTF16(IDS_LEARN_MORE);
   std::vector<size_t> offsets;
   base::string16 headline = l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/chromeos/enrollment_dialog_view.cc b/chrome/browser/chromeos/enrollment_dialog_view.cc
index 8b9f151..0964b48 100644
--- a/chrome/browser/chromeos/enrollment_dialog_view.cc
+++ b/chrome/browser/chromeos/enrollment_dialog_view.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/login/login_state.h"
 #include "chromeos/network/client_cert_util.h"
@@ -29,7 +30,6 @@
 #include "ui/base/page_transition_types.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -174,8 +174,11 @@
                      0,   // Ignored for USE_PREF.
                      0);  // Minimum size.
   columns = grid_layout->AddColumnSet(1);
+
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+
   columns->AddPaddingColumn(
-      0, views::kUnrelatedControlHorizontalSpacing);
+      0, provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_HORIZONTAL));
   columns->AddColumn(views::GridLayout::LEADING,  // Horizontal leading.
                      views::GridLayout::FILL,     // Vertical resize.
                      1,   // Resize weight.
@@ -185,7 +188,8 @@
 
   grid_layout->StartRow(0, 0);
   grid_layout->AddView(label);
-  grid_layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing);
+  grid_layout->AddPaddingRow(
+      0, provider->GetDistanceMetric(DISTANCE_UNRELATED_CONTROL_VERTICAL));
   grid_layout->Layout(this);
 }
 
diff --git a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
index 850938e..3474348 100644
--- a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
+++ b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h"
 #include "chrome/browser/ui/view_ids.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -36,7 +37,6 @@
 #include "ui/views/background.h"
 #include "ui/views/controls/webview/webview.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
@@ -70,23 +70,26 @@
     GridLayout* layout = new GridLayout(this);
     SetLayoutManager(layout);
 
+    const int related_horizontal_spacing =
+        ChromeLayoutProvider::Get()->GetDistanceMetric(
+            views::DISTANCE_RELATED_CONTROL_HORIZONTAL);
     // Back button.
     views::ColumnSet* column_set = layout->AddColumnSet(0);
     column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
                           GridLayout::USE_PREF, 0, 0);
-    column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+    column_set->AddPaddingColumn(0, related_horizontal_spacing);
     // Forward button.
     column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
                           GridLayout::USE_PREF, 0, 0);
-    column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+    column_set->AddPaddingColumn(0, related_horizontal_spacing);
     // Reload button.
     column_set->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
                           GridLayout::USE_PREF, 0, 0);
-    column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+    column_set->AddPaddingColumn(0, related_horizontal_spacing);
     // Location bar.
     column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
                           GridLayout::FIXED, kLocationBarHeight, 0);
-    column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing);
+    column_set->AddPaddingColumn(0, related_horizontal_spacing);
 
     layout->StartRow(0, 0);
     layout->AddView(back);
diff --git a/chrome/browser/chromeos/options/network_config_view.cc b/chrome/browser/chromeos/options/network_config_view.cc
index 497bbc0..92a42c4f 100644
--- a/chrome/browser/chromeos/options/network_config_view.cc
+++ b/chrome/browser/chromeos/options/network_config_view.cc
@@ -40,7 +40,6 @@
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
 using views::Widget;
diff --git a/chrome/browser/chromeos/power/idle_action_warning_dialog_view.cc b/chrome/browser/chromeos/power/idle_action_warning_dialog_view.cc
index 14f0290..82dac97 100644
--- a/chrome/browser/chromeos/power/idle_action_warning_dialog_view.cc
+++ b/chrome/browser/chromeos/power/idle_action_warning_dialog_view.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -20,7 +21,6 @@
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_client_view.h"
 
@@ -64,9 +64,9 @@
     : idle_action_time_(idle_action_time),
       label_(NULL) {
   label_ = new FixedWidthLabel(kIdleActionWarningContentWidth);
-  label_->SetBorder(views::CreateEmptyBorder(
-      views::kPanelVertMargin, views::kButtonHEdgeMarginNew,
-      views::kPanelVertMargin, views::kButtonHEdgeMarginNew));
+  label_->SetBorder(
+      views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
+          views::INSETS_DIALOG_CONTENTS)));
   AddChildView(label_);
   SetLayoutManager(new views::FillLayout());
 
diff --git a/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc b/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
index c4ab98d..c0f3cfa 100644
--- a/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
+++ b/chrome/browser/chromeos/profiles/multiprofiles_intro_dialog.cc
@@ -7,6 +7,7 @@
 #include "ash/shell.h"
 #include "base/macros.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -14,7 +15,6 @@
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
@@ -106,9 +106,9 @@
 }
 
 void MultiprofilesIntroView::InitDialog() {
-  SetBorder(views::CreateEmptyBorder(views::kPanelVertMargin,
-                                     views::kButtonHEdgeMarginNew, 0,
-                                     views::kButtonHEdgeMarginNew));
+  SetBorder(
+      views::CreateEmptyBorder(ChromeLayoutProvider::Get()->GetInsetsMetric(
+          views::INSETS_DIALOG_TITLE)));
   SetLayoutManager(new views::FillLayout());
 
   // Explanation string
diff --git a/chrome/browser/chromeos/ui/request_pin_view.cc b/chrome/browser/chromeos/ui/request_pin_view.cc
index 6b62ac3..fbb2000 100644
--- a/chrome/browser/chromeos/ui/request_pin_view.cc
+++ b/chrome/browser/chromeos/ui/request_pin_view.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/options/passphrase_textfield.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -19,7 +20,6 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_client_view.h"
 
@@ -178,7 +178,10 @@
   header_label_->SetEnabled(true);
   layout->AddView(header_label_);
 
-  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+  const int related_vertical_spacing =
+      ChromeLayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_RELATED_CONTROL_VERTICAL);
+  layout->AddPaddingRow(0, related_vertical_spacing);
 
   column_view_set_id++;
   column_set = layout->AddColumnSet(column_view_set_id);
@@ -192,7 +195,7 @@
   textfield_->SetEnabled(true);
   layout->AddView(textfield_);
 
-  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+  layout->AddPaddingRow(0, related_vertical_spacing);
 
   column_view_set_id++;
   column_set = layout->AddColumnSet(column_view_set_id);
diff --git a/chrome/browser/conflicts/module_inspector_win.cc b/chrome/browser/conflicts/module_inspector_win.cc
index e706b06..a17b640 100644
--- a/chrome/browser/conflicts/module_inspector_win.cc
+++ b/chrome/browser/conflicts/module_inspector_win.cc
@@ -18,13 +18,22 @@
   });
 }
 
+// Wrapper function for InspectModule() that takes the StringMapping via a
+// scoped_refptr. This saves a copy per invocation.
+std::unique_ptr<ModuleInspectionResult> InspectModuleOnBlockingSequence(
+    scoped_refptr<base::RefCountedData<StringMapping>> env_variable_mapping,
+    const ModuleInfoKey& module_key) {
+  return InspectModule(env_variable_mapping->data, module_key);
+}
+
 }  // namespace
 
 ModuleInspector::ModuleInspector(
     const OnModuleInspectedCallback& on_module_inspected_callback)
     : on_module_inspected_callback_(on_module_inspected_callback),
       inspection_task_priority_(base::TaskPriority::BACKGROUND),
-      path_mapping_(GetPathMapping()),
+      path_mapping_(base::MakeRefCounted<base::RefCountedData<StringMapping>>(
+          GetPathMapping())),
       weak_ptr_factory_(this) {}
 
 ModuleInspector::~ModuleInspector() = default;
@@ -50,7 +59,8 @@
       FROM_HERE,
       {base::MayBlock(), inspection_task_priority_,
        base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-      base::BindOnce(&InspectModule, path_mapping_, module_key),
+      base::BindOnce(&InspectModuleOnBlockingSequence, path_mapping_,
+                     module_key),
       base::BindOnce(&ModuleInspector::OnInspectionFinished,
                      weak_ptr_factory_.GetWeakPtr(), module_key));
 }
diff --git a/chrome/browser/conflicts/module_inspector_win.h b/chrome/browser/conflicts/module_inspector_win.h
index d044cd0..4b2e289a 100644
--- a/chrome/browser/conflicts/module_inspector_win.h
+++ b/chrome/browser/conflicts/module_inspector_win.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task_scheduler/task_traits.h"
 #include "base/threading/thread_checker.h"
@@ -67,7 +68,7 @@
   // The vector of paths to %env_var%, used to account for differences in
   // localization and where people keep their files.
   // e.g. c:\windows vs d:\windows
-  StringMapping path_mapping_;
+  scoped_refptr<base::RefCountedData<StringMapping>> path_mapping_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 3941ca78..8902bd59 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -26,6 +26,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "extensions/browser/app_sorting.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
 
 using content::WebContents;
@@ -34,6 +35,9 @@
 
 class ExtensionInstallUIBrowserTest : public ExtensionBrowserTest {
  public:
+  ExtensionInstallUIBrowserTest() {}
+  ~ExtensionInstallUIBrowserTest() override {}
+
   // Checks that a theme info bar is currently visible and issues an undo to
   // revert to the previous theme.
   void VerifyThemeInfoBarAndUndoInstall() {
@@ -47,18 +51,29 @@
         infobar_service->infobar_at(0)->delegate()->AsConfirmInfoBarDelegate();
     ASSERT_TRUE(delegate);
     delegate->Cancel();
+    WaitForThemeChange();
     ASSERT_EQ(0U, infobar_service->infobar_count());
   }
 
   // Install the given theme from the data dir and verify expected name.
   void InstallThemeAndVerify(const char* theme_name,
                              const std::string& expected_name) {
-    // If there is already a theme installed, the current theme should be
-    // disabled and the new one installed + enabled.
-    int expected_change = GetTheme() ? 0 : 1;
     const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_name);
-    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, expected_change,
-        browser()));
+    const bool theme_exists = GetTheme();
+    // Themes install asynchronously so we must check the number of enabled
+    // extensions after theme install completes.
+    size_t num_before = extensions::ExtensionRegistry::Get(profile())
+                            ->enabled_extensions()
+                            .size();
+    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, 1, browser()));
+    WaitForThemeChange();
+    size_t num_after = extensions::ExtensionRegistry::Get(profile())
+                           ->enabled_extensions()
+                           .size();
+    // If a theme was already installed, we're just swapping one for another, so
+    // no change in extension count.
+    EXPECT_EQ(num_before + (theme_exists ? 0 : 1), num_after);
+
     const Extension* theme = GetTheme();
     ASSERT_TRUE(theme);
     ASSERT_EQ(theme->name(), expected_name);
@@ -67,6 +82,17 @@
   const Extension* GetTheme() const {
     return ThemeServiceFactory::GetThemeForProfile(browser()->profile());
   }
+
+  void WaitForThemeChange() {
+    content::WindowedNotificationObserver theme_change_observer(
+        chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+        content::Source<ThemeService>(
+            ThemeServiceFactory::GetForProfile(browser()->profile())));
+    theme_change_observer.Wait();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ExtensionInstallUIBrowserTest);
 };
 
 // Fails on Linux and Windows (http://crbug.com/580907).
@@ -75,6 +101,7 @@
   // Install theme once and undo to verify we go back to default theme.
   base::FilePath theme_crx = PackExtension(test_data_dir_.AppendASCII("theme"));
   ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser()));
+  WaitForThemeChange();
   const Extension* theme = GetTheme();
   ASSERT_TRUE(theme);
   std::string theme_id = theme->id();
@@ -83,10 +110,12 @@
 
   // Set the same theme twice and undo to verify we go back to default theme.
   ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser()));
+  WaitForThemeChange();
   theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
   ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser()));
+  WaitForThemeChange();
   theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
@@ -104,7 +133,7 @@
   // Then install second theme.
   InstallThemeAndVerify("theme2", "snowflake theme");
   const Extension* theme2 = GetTheme();
-  EXPECT_FALSE(theme_id == theme2->id());
+  EXPECT_NE(theme_id, theme2->id());
 
   // Undo second theme will revert to first theme.
   VerifyThemeInfoBarAndUndoInstall();
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc
index 1b810fa..8d91faa8 100644
--- a/chrome/browser/extensions/extension_service_sync_unittest.cc
+++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -28,6 +29,8 @@
 #include "chrome/browser/extensions/scripting_permissions_modifier.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/sync_helper.h"
@@ -1563,6 +1566,11 @@
   // Installing a theme should not result in a sync change (themes are handled
   // separately by ThemeSyncableService).
   InstallCRX(data_dir().AppendASCII("theme.crx"), INSTALL_NEW);
+  content::WindowedNotificationObserver theme_change_observer(
+      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+      content::Source<ThemeService>(
+          ThemeServiceFactory::GetForProfile(profile())));
+  theme_change_observer.Wait();
   EXPECT_TRUE(processor->changes().empty());
 }
 
diff --git a/chrome/browser/extensions/launch_util.cc b/chrome/browser/extensions/launch_util.cc
index b911fca..bedaacf 100644
--- a/chrome/browser/extensions/launch_util.cc
+++ b/chrome/browser/extensions/launch_util.cc
@@ -35,7 +35,7 @@
 // static
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterIntegerPref(pref_names::kBookmarkAppCreationLaunchType,
-                                LAUNCH_TYPE_REGULAR);
+                                LAUNCH_TYPE_WINDOW);
 }
 
 }  // namespace launch_util
diff --git a/chrome/browser/extensions/theme_installed_infobar_delegate.cc b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
index 16d349d..e432bbdc 100644
--- a/chrome/browser/extensions/theme_installed_infobar_delegate.cc
+++ b/chrome/browser/extensions/theme_installed_infobar_delegate.cc
@@ -144,7 +144,9 @@
     const extensions::Extension* previous_theme =
         extension_service_->GetExtensionById(previous_theme_id_, true);
     if (previous_theme) {
-      theme_service_->SetTheme(previous_theme);
+      theme_service_->RevertToTheme(previous_theme);
+      // TODO(estade): while we're waiting to close, it would be nice to
+      // indicate that the theme is busy reverting.
       return false;  // The theme change will close us.
     }
   }
diff --git a/chrome/browser/infobars/infobars_browsertest.cc b/chrome/browser/infobars/infobars_browsertest.cc
index 090f91b..a887674 100644
--- a/chrome/browser/infobars/infobars_browsertest.cc
+++ b/chrome/browser/infobars/infobars_browsertest.cc
@@ -76,8 +76,8 @@
       chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
         content::NotificationService::AllSources());
   InstallExtension("theme2.crx");
-  infobar_added_2.Wait();
   infobar_removed_1.Wait();
+  infobar_added_2.Wait();
   EXPECT_EQ(
       0u,
       InfoBarService::FromWebContents(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 381c635..de65bda 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -89,6 +89,8 @@
                void(WebContents*, const GURL&, const GURL&, const GURL&));
   MOCK_METHOD3(MaybeStartProtectedPasswordEntryRequest,
                void(WebContents*, const GURL&, const std::string&));
+  MOCK_METHOD3(ShowPhishingInterstitial,
+               void(const GURL&, const std::string&, content::WebContents*));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockPasswordProtectionService);
diff --git a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
index 754ce7e..4c71b1ae 100644
--- a/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
+++ b/chrome/browser/resources/chromeos/quick_unlock/pin_keyboard.html
@@ -183,7 +183,7 @@
               has-content$="[[hasInput_(value)]]"
               label="[[getInputPlaceholder_(enablePassword)]]"
               on-keydown="onInputKeyDown_"
-              hidden="[[!showPinInput_]]">
+              hidden="[[!showPinInput_]]" autofocus>
           </paper-input>
         </div>
         <content select="[problem]"></content>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.html b/chrome/browser/resources/settings/people_page/fingerprint_list.html
index 990eea4..46be8a4 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_list.html
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.html
@@ -71,10 +71,12 @@
     </div>
     <i class="settings-box continuation">$i18n{lockScreenFingerprintWarning}</i>
 
-    <settings-setup-fingerprint-dialog id="setupFingerprint"
-        on-add-fingerprint="updateFingerprintsList_"
-        on-close="onSetupFingerprintDialogClose_">
-    </settings-setup-fingerprint-dialog>
+    <template is="dom-if" if="[[showSetupFingerprintDialog_]]" restamp>
+      <settings-setup-fingerprint-dialog
+          on-add-fingerprint="updateFingerprintsList_"
+          on-close="onSetupFingerprintDialogClose_">
+      </settings-setup-fingerprint-dialog>
+    </template>
   </template>
   <script src="fingerprint_list.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/people_page/fingerprint_list.js b/chrome/browser/resources/settings/people_page/fingerprint_list.js
index 442c53cc..474bb6c 100644
--- a/chrome/browser/resources/settings/people_page/fingerprint_list.js
+++ b/chrome/browser/resources/settings/people_page/fingerprint_list.js
@@ -31,7 +31,10 @@
       value: function() {
         return [];
       }
-    }
+    },
+
+    /** @private */
+    showSetupFingerprintDialog_: Boolean,
   },
 
   /** @private {?settings.FingerprintBrowserProxy} */
@@ -145,11 +148,12 @@
    * @private
    */
   openAddFingerprintDialog_: function() {
-    this.$.setupFingerprint.open();
+    this.showSetupFingerprintDialog_ = true;
   },
 
   /** @private */
   onSetupFingerprintDialogClose_: function() {
+    this.showSetupFingerprintDialog_ = false;
     cr.ui.focusWithoutInk(assert(this.$$('#addFingerprint')));
     this.browserProxy_.startAuthentication();
   },
@@ -162,7 +166,7 @@
   onScreenLocked_: function(screenIsLocked) {
     if (!screenIsLocked &&
         settings.getCurrentRoute() == settings.Route.FINGERPRINT) {
-      this.$.setupFingerprint.close();
+      this.onSetupFingerprintDialogClose_();
     }
   },
 });
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index 9d82240..e2b8b7d6 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -160,13 +160,17 @@
         </div>
       </template>
 
-      <settings-password-prompt-dialog id="passwordPrompt"
-          on-close="onPasswordClosed_" set-modes="{{setModes_}}">
-      </settings-password-prompt-dialog>
+      <template is="dom-if" if="[[showPasswordPromptDialog_]]" restamp>
+        <settings-password-prompt-dialog id="passwordPrompt"
+            on-close="onPasswordPromptDialogClose_" set-modes="{{setModes_}}">
+        </settings-password-prompt-dialog>
+      </template>
 
-      <settings-setup-pin-dialog id="setupPin" on-done="onPinSetupDone_"
-          on-close="onSetupPinClosed_" set-modes="[[setModes_]]">
-      </settings-setup-pin-dialog>
+      <template is="dom-if" if="[[showSetupPinDialog_]]" restamp>
+        <settings-setup-pin-dialog id="setupPin" set-modes="[[setModes_]]"
+            on-close="onSetupPinDialogClose_">
+        </settings-setup-pin-dialog>
+      </template>
 
       <template is="dom-if" if="[[showEasyUnlockTurnOffDialog_]]" restamp>
         <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog"
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index fe5be02..ac2759d 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -123,6 +123,12 @@
       type: Boolean,
       value: false,
     },
+
+    /** @private */
+    showPasswordPromptDialog_: Boolean,
+
+    /** @private */
+    showSetupPinDialog_: Boolean,
   },
 
   /** @private {?settings.EasyUnlockBrowserProxy} */
@@ -137,7 +143,7 @@
   /** @override */
   attached: function() {
     if (this.shouldAskForPassword_(settings.getCurrentRoute()))
-      this.$.passwordPrompt.open();
+      this.openPasswordPromptDialog_();
 
     this.easyUnlockBrowserProxy_ =
         settings.EasyUnlockBrowserProxyImpl.getInstance();
@@ -169,7 +175,7 @@
     }
 
     if (this.shouldAskForPassword_(newRoute)) {
-      this.$.passwordPrompt.open();
+      this.openPasswordPromptDialog_();
     } else if (newRoute != settings.Route.FINGERPRINT &&
         oldRoute != settings.Route.FINGERPRINT) {
       // If the user navigated away from the lock screen settings page they will
@@ -199,25 +205,37 @@
   onSetModesChanged_: function() {
     if (this.shouldAskForPassword_(settings.getCurrentRoute())) {
       this.$.setupPin.close();
-      this.$.passwordPrompt.open();
+      this.openPasswordPromptDialog_();
     }
   },
 
   /** @private */
-  onPasswordClosed_: function() {
+  openPasswordPromptDialog_: function() {
+    this.showPasswordPromptDialog_ = true;
+  },
+
+  /** @private */
+  onPasswordPromptDialogClose_: function() {
+    this.showPasswordPromptDialog_ = false;
     if (!this.setModes_)
-      settings.navigateTo(settings.Route.PEOPLE);
+      settings.navigateToPreviousRoute();
     else
       cr.ui.focusWithoutInk(assert(this.$$('#unlockType')));
   },
 
-  /** @private */
-  onPinSetupDone_: function() {
-    this.$.setupPin.close();
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onConfigurePin_: function(e) {
+    e.preventDefault();
+    this.writeUma_(LockScreenProgress.CHOOSE_PIN_OR_PASSWORD);
+    this.showSetupPinDialog_ = true;
   },
 
   /** @private */
-  onSetupPinClosed_: function() {
+  onSetupPinDialogClose_: function() {
+    this.showSetupPinDialog_ = false;
     cr.ui.focusWithoutInk(assert(this.$$('#setupPinButton')));
   },
 
@@ -251,16 +269,6 @@
     return this.i18n('lockScreenEditFingerprintsDescription');
   },
 
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onConfigurePin_: function(e) {
-    e.preventDefault();
-    this.$.setupPin.open();
-    this.writeUma_(LockScreenProgress.CHOOSE_PIN_OR_PASSWORD);
-  },
-
   /** @private */
   onEditFingerprints_: function() {
     settings.navigateTo(settings.Route.FINGERPRINT);
diff --git a/chrome/browser/resources/settings/people_page/password_prompt_dialog.html b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
index 0b83812b..f7c1547 100644
--- a/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
+++ b/chrome/browser/resources/settings/people_page/password_prompt_dialog.html
@@ -25,7 +25,7 @@
 
         <div class="settings-box first">$i18n{passwordPromptEnterPassword}</div>
 
-        <paper-input id="passwordInput" type="password" autofocus
+        <paper-input id="passwordInput" type="password"
             label="$i18n{passwordPromptPasswordLabel}"
             value="{{password_}}"
             invalid$="[[passwordInvalid_]]"
diff --git a/chrome/browser/resources/settings/people_page/password_prompt_dialog.js b/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
index 2625f2ba..7bbb914f 100644
--- a/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
+++ b/chrome/browser/resources/settings/people_page/password_prompt_dialog.js
@@ -97,30 +97,13 @@
 
   /** @override */
   attached: function() {
+    this.writeUma_(LockScreenProgress.START_SCREEN_LOCK);
+    this.$.dialog.showModal();
     this.async(function() {
       this.$.passwordInput.focus();
     }.bind(this));
   },
 
-  /**
-   * Open up the dialog. This will wait until the dialog has loaded before
-   * opening it.
-   */
-  open: function() {
-    // Wait until the dialog is attached to the DOM before trying to open it.
-    var dialog = /** @type {{isConnected: boolean}} */ (this.$.dialog);
-    if (!dialog.isConnected) {
-      setTimeout(this.open.bind(this));
-      return;
-    }
-
-    if (this.$.dialog.open)
-      return;
-
-    this.writeUma_(LockScreenProgress.START_SCREEN_LOCK);
-    this.$.dialog.showModal();
-  },
-
   /** @private */
   onCancelTap_: function() {
     if (this.$.dialog.open)
diff --git a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js
index 2bb23ced..74621a4 100644
--- a/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js
+++ b/chrome/browser/resources/settings/people_page/setup_fingerprint_dialog.js
@@ -79,12 +79,7 @@
     this.addWebUIListener(
         'on-fingerprint-scan-received', this.onScanReceived_.bind(this));
     this.browserProxy_ = settings.FingerprintBrowserProxyImpl.getInstance();
-  },
 
-  /**
-   * Opens the dialog.
-   */
-  open: function() {
     this.$.arc.clearCanvas();
     this.$.arc.drawBackgroundCircle();
     this.$.arc.drawShadow(10, 0, 0);
diff --git a/chrome/browser/resources/settings/people_page/setup_pin_dialog.html b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
index c1c97ef..28ea401 100644
--- a/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
+++ b/chrome/browser/resources/settings/people_page/setup_pin_dialog.html
@@ -14,6 +14,7 @@
     <style include="settings-shared">
       .error {
         color: var(--paper-red-500);
+        color: blue;
       }
 
       .error > iron-icon {
@@ -45,7 +46,8 @@
         <div id="pinKeyboardDiv" class="settings-box continuation">
           <pin-keyboard id="pinKeyboard" on-pin-change="onPinChange_"
               on-submit="onPinSubmit_" value="{{pinKeyboardValue_}}"
-              has-error$="[[hasError_(problemMessage_, problemClass_)]]">
+              has-error$="[[hasError_(problemMessage_, problemClass_)]]"
+              autofocus>
             <!-- Warning/error; only shown if title is hidden. -->
             <div id="problemDiv" class$="[[problemClass_]]"
                 hidden$="[[!problemMessage_]]" problem>
diff --git a/chrome/browser/resources/settings/people_page/setup_pin_dialog.js b/chrome/browser/resources/settings/people_page/setup_pin_dialog.js
index bd4f1e7..a2796622 100644
--- a/chrome/browser/resources/settings/people_page/setup_pin_dialog.js
+++ b/chrome/browser/resources/settings/people_page/setup_pin_dialog.js
@@ -7,8 +7,7 @@
  * 'settings-setup-pin-dialog' is the settings page for choosing a PIN.
  *
  * Example:
- *
- * <settings-setup-pin-dialog set-modes="[[quickUnlockSetModes]]">
+ * * <settings-setup-pin-dialog set-modes="[[quickUnlockSetModes]]">
  * </settings-setup-pin-dialog>
  */
 
@@ -101,11 +100,7 @@
   /** @override */
   attached: function() {
     this.resetState_();
-  },
-
-  open: function() {
     this.$.dialog.showModal();
-    this.$.pinKeyboard.focus();
   },
 
   close: function() {
@@ -276,7 +271,8 @@
       }
 
       this.resetState_();
-      this.fire('done');
+      if (this.$.dialog.open)
+        this.$.dialog.close();
     }
 
     this.setModes.call(
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 7cc87ab5..4ba04643 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -80,7 +80,7 @@
           label="$i18n{siteSettingsMic}" site="[[site]]">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.NOTIFICATIONS}}"
-          icon="settings:notifications" id="notification"
+          icon="settings:notifications" id="notifications"
           label="$i18n{siteSettingsNotifications}" site="[[site]]">
       </site-details-permission>
       <site-details-permission category="{{ContentSettingsTypes.JAVASCRIPT}}"
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chrome/browser/resources/settings/site_settings/site_details_permission.html
index 068df17..42a62ef 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.html
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.html
@@ -12,7 +12,7 @@
 <dom-module id="site-details-permission">
   <template>
     <style include="settings-shared md-select"></style>
-    <div id="details" hidden>
+    <div id="details">
       <div class="list-item underbar">
         <div>
           <iron-icon icon="[[icon]]">
diff --git a/chrome/browser/resources/settings/site_settings/site_details_permission.js b/chrome/browser/resources/settings/site_settings/site_details_permission.js
index 3408b6f..5cb9947 100644
--- a/chrome/browser/resources/settings/site_settings/site_details_permission.js
+++ b/chrome/browser/resources/settings/site_settings/site_details_permission.js
@@ -52,7 +52,6 @@
    * @private
    */
   siteChanged_: function(site) {
-    this.$.details.hidden = true;
 
     this.browserProxy.getExceptionList(this.category).then(
         function(exceptionList) {
@@ -60,7 +59,6 @@
         if (exceptionList[i].embeddingOrigin == site.embeddingOrigin &&
             this.sameOrigin_(exceptionList[i].origin, site.origin)) {
           this.$.permission.value = exceptionList[i].setting;
-          this.$.details.hidden = false;
           break;
         }
       }
@@ -94,7 +92,6 @@
     this.browserProxy.resetCategoryPermissionForOrigin(
         this.site.origin, this.site.embeddingOrigin, this.category,
         this.site.incognito);
-    this.$.details.hidden = true;
   },
 
   /**
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index d64377c..63168e7a 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -12,11 +12,17 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/common/pref_names.h"
 #include "components/browser_sync/profile_sync_service.h"
+#include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/safe_browsing_db/database_manager.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
 
 using content::BrowserThread;
 
@@ -39,6 +45,7 @@
               profile,
               ServiceAccessType::EXPLICIT_ACCESS),
           HostContentSettingsMapFactory::GetForProfile(profile)),
+      ui_manager_(sb_service->ui_manager()),
       profile_(profile),
       navigation_observer_manager_(sb_service->navigation_observer_manager()) {
   DCHECK(profile_);
@@ -82,6 +89,13 @@
 bool ChromePasswordProtectionService::IsPingingEnabled(
     const base::Feature& feature,
     RequestOutcome* reason) {
+  // Don't start pinging on an invalid profile, or if user turns off Safe
+  // Browsing service.
+  if (!profile_ ||
+      !profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
+    return false;
+  }
+
   DCHECK(feature.name == kProtectedPasswordEntryPinging.name ||
          feature.name == kPasswordFieldOnFocusPinging.name);
   if (!base::FeatureList::IsEnabled(feature)) {
@@ -123,6 +137,33 @@
          sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
 }
 
-ChromePasswordProtectionService::ChromePasswordProtectionService()
-    : PasswordProtectionService(nullptr, nullptr, nullptr, nullptr) {}
+void ChromePasswordProtectionService::ShowPhishingInterstitial(
+    const GURL& phishing_url,
+    const std::string& token,
+    content::WebContents* web_contents) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (!ui_manager_)
+    return;
+  security_interstitials::UnsafeResource resource;
+  resource.url = phishing_url;
+  resource.original_url = phishing_url;
+  resource.is_subresource = false;
+  resource.threat_type = SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL;
+  resource.threat_source =
+      safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE;
+  resource.web_contents_getter =
+      safe_browsing::SafeBrowsingUIManager::UnsafeResource::
+          GetWebContentsGetter(web_contents->GetRenderProcessHost()->GetID(),
+                               web_contents->GetMainFrame()->GetRoutingID());
+  resource.token = token;
+  if (!ui_manager_->IsWhitelisted(resource)) {
+    web_contents->GetController().DiscardNonCommittedEntries();
+  }
+  ui_manager_->DisplayBlockingPage(resource);
+}
+
+ChromePasswordProtectionService::ChromePasswordProtectionService(
+    Profile* profile)
+    : PasswordProtectionService(nullptr, nullptr, nullptr, nullptr),
+      profile_(profile) {}
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index 68e25b9f..adfd93e 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -9,10 +9,15 @@
 
 class Profile;
 
+namespace content {
+class WebContents;
+}
+
 namespace safe_browsing {
 
 class SafeBrowsingService;
 class SafeBrowsingNavigationObserverManager;
+class SafeBrowsingUIManager;
 
 // ChromePasswordProtectionService extends PasswordProtectionService by adding
 // access to SafeBrowsingNaivigationObserverManager and Profile.
@@ -45,6 +50,10 @@
   // If user enabled history syncing.
   bool IsHistorySyncEnabled() override;
 
+  void ShowPhishingInterstitial(const GURL& phishing_url,
+                                const std::string& token,
+                                content::WebContents* web_contents) override;
+
   FRIEND_TEST_ALL_PREFIXES(
       ChromePasswordProtectionServiceTest,
       VerifyFinchControlForLowReputationPingSBEROnlyNoIncognito);
@@ -59,8 +68,10 @@
 
  private:
   friend class MockChromePasswordProtectionService;
-  // Default constructor used for tests only.
-  ChromePasswordProtectionService();
+  // Constructor used for tests only.
+  explicit ChromePasswordProtectionService(Profile* profile);
+
+  scoped_refptr<SafeBrowsingUIManager> ui_manager_;
   // Profile associated with this instance.
   Profile* profile_;
   scoped_refptr<SafeBrowsingNavigationObserverManager>
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index e721bf4..348c10c5 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -3,18 +3,52 @@
 // found in the LICENSE file.
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 
+#include "base/memory/ref_counted.h"
 #include "base/test/scoped_feature_list.h"
+#include "chrome/browser/safe_browsing/ui_manager.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/variations/variations_params_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace safe_browsing {
 
+namespace {
+const char kPhishingURL[] = "http://phishing.com";
+}
+
+class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
+ public:
+  explicit MockSafeBrowsingUIManager(SafeBrowsingService* service)
+      : SafeBrowsingUIManager(service) {}
+
+  MOCK_METHOD1(DisplayBlockingPage, void(const UnsafeResource& resource));
+
+  void InvokeOnBlockingPageComplete(
+      const security_interstitials::UnsafeResource::UrlCheckCallback&
+          callback) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    if (!callback.is_null())
+      callback.Run(false);
+  }
+
+ protected:
+  virtual ~MockSafeBrowsingUIManager() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingUIManager);
+};
+
 class MockChromePasswordProtectionService
     : public ChromePasswordProtectionService {
  public:
-  MockChromePasswordProtectionService()
-      : ChromePasswordProtectionService(),
+  explicit MockChromePasswordProtectionService(Profile* profile)
+      : ChromePasswordProtectionService(profile),
         is_incognito_(false),
         is_extended_reporting_(false),
         is_history_sync_enabled_(false) {}
@@ -32,17 +66,49 @@
     is_history_sync_enabled_ = is_history_sync_enabled;
   }
 
+  void SetUIManager(scoped_refptr<SafeBrowsingUIManager> ui_manager) {
+    ui_manager_ = ui_manager;
+  }
+
+  MockSafeBrowsingUIManager* ui_manager() {
+    return static_cast<MockSafeBrowsingUIManager*>(ui_manager_.get());
+  }
+
+  void CacheVerdict(const GURL& url,
+                    LoginReputationClientResponse* verdict,
+                    const base::Time& receive_time) override {}
+
+ protected:
+  friend class ChromePasswordProtectionServiceTest;
+
  private:
   bool is_incognito_;
   bool is_extended_reporting_;
   bool is_history_sync_enabled_;
 };
 
-class ChromePasswordProtectionServiceTest : public testing::Test {
+class ChromePasswordProtectionServiceTest
+    : public ChromeRenderViewHostTestHarness {
  public:
   typedef std::map<std::string, std::string> Parameters;
+
   ChromePasswordProtectionServiceTest() {}
 
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
+    service_ = base::MakeUnique<MockChromePasswordProtectionService>(profile());
+    service_->SetUIManager(new testing::StrictMock<MockSafeBrowsingUIManager>(
+        SafeBrowsingService::CreateSafeBrowsingService()));
+  }
+
+  void TearDown() override {
+    base::RunLoop().RunUntilIdle();
+    service_.reset();
+    request_ = nullptr;
+    ChromeRenderViewHostTestHarness::TearDown();
+  }
+
   // Sets up Finch trial feature parameters.
   void SetFeatureParams(const base::Feature& feature,
                         const std::string& trial_name,
@@ -65,19 +131,38 @@
             {"history_sync", allowed_for_history_sync ? "true" : "false"}};
   }
 
+  void InitializeRequest(LoginReputationClientRequest::TriggerType type) {
+    request_ = new PasswordProtectionRequest(web_contents(), GURL(kPhishingURL),
+                                             GURL(), GURL(), std::string(),
+                                             type, service_.get(), 0);
+  }
+
+  void InitializeVerdict(LoginReputationClientResponse::VerdictType type) {
+    verdict_ = base::MakeUnique<LoginReputationClientResponse>();
+    verdict_->set_verdict_type(type);
+  }
+
+  void RequestFinished(
+      PasswordProtectionRequest* request,
+      std::unique_ptr<LoginReputationClientResponse> response) {
+    service_->RequestFinished(request, false, std::move(response));
+  }
+
  protected:
-  content::TestBrowserThreadBundle thread_bundle_;
   variations::testing::VariationParamsManager params_manager_;
   base::test::ScopedFeatureList scoped_feature_list_;
+  std::unique_ptr<MockChromePasswordProtectionService> service_;
+  scoped_refptr<PasswordProtectionRequest> request_;
+  std::unique_ptr<LoginReputationClientResponse> verdict_;
 };
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingSBEROnlyNoIncognito) {
-  MockChromePasswordProtectionService service;
   PasswordProtectionService::RequestOutcome reason;
 
   // By default kPasswordFieldOnFocusPinging feature is disabled.
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_FEATURE_DISABLED,
             reason);
 
@@ -98,40 +183,47 @@
   SetFeatureParams(kPasswordFieldOnFocusPinging, "SBEROnlyNoIncognito",
                    sber_and_no_incognito);
 
-  service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_USER_POPULATION, reason);
 
-  service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_USER_POPULATION, reason);
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingSBERAndHistorySyncNoIncognito) {
-  MockChromePasswordProtectionService service;
   PasswordProtectionService::RequestOutcome reason;
 
   // Enables kPasswordFieldOnFocusPinging feature.
@@ -150,39 +242,46 @@
       CreateParameters(false, false, true, true);
   SetFeatureParams(kPasswordFieldOnFocusPinging,
                    "SBERAndHistorySyncNoIncognito", sber_and_sync_no_incognito);
-  service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_USER_POPULATION, reason);
 
-  service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingAllButNoIncognito) {
-  MockChromePasswordProtectionService service;
   PasswordProtectionService::RequestOutcome reason;
 
   // Enables kPasswordFieldOnFocusPinging feature.
@@ -199,38 +298,45 @@
   Parameters all_users = CreateParameters(false, true, true, true);
   SetFeatureParams(kPasswordFieldOnFocusPinging, "AllButNoIncognito",
                    all_users);
-  service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 
-  service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_FALSE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_FALSE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
   EXPECT_EQ(PasswordProtectionService::DISABLED_DUE_TO_INCOGNITO, reason);
 }
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyFinchControlForLowReputationPingAll) {
-  MockChromePasswordProtectionService service;
   PasswordProtectionService::RequestOutcome reason;
 
   // Enables kPasswordFieldOnFocusPinging feature.
@@ -246,22 +352,92 @@
   // ]
   Parameters all_users = CreateParameters(true, true, true, true);
   SetFeatureParams(kPasswordFieldOnFocusPinging, "All", all_users);
-  service.ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
-  service.ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
-  EXPECT_TRUE(service.IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(false /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, false /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, false /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+  service_->ConfigService(true /*incognito*/, true /*SBER*/, true /*sync*/);
+  EXPECT_TRUE(
+      service_->IsPingingEnabled(kPasswordFieldOnFocusPinging, &reason));
+}
+
+TEST_F(ChromePasswordProtectionServiceTest,
+       ShowInterstitialOnPasswordOnFocusPhishingVerdict) {
+  // Enables kPasswordProtectionInterstitial feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordProtectionInterstitial);
+
+  InitializeRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
+  InitializeVerdict(LoginReputationClientResponse::PHISHING);
+
+  security_interstitials::UnsafeResource resource;
+  EXPECT_CALL(*service_->ui_manager(), DisplayBlockingPage(testing::_))
+      .WillOnce(testing::SaveArg<0>(&resource));
+  RequestFinished(request_.get(), std::move(verdict_));
+  EXPECT_EQ(GURL(kPhishingURL), resource.url);
+  EXPECT_EQ(GURL(kPhishingURL), resource.original_url);
+  EXPECT_FALSE(resource.is_subresource);
+  EXPECT_EQ(SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL,
+            resource.threat_type);
+  EXPECT_EQ(ThreatSource::PASSWORD_PROTECTION_SERVICE, resource.threat_source);
+  EXPECT_EQ(web_contents(), resource.web_contents_getter.Run());
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&MockSafeBrowsingUIManager::InvokeOnBlockingPageComplete,
+                     service_->ui_manager(), resource.callback));
+}
+
+TEST_F(ChromePasswordProtectionServiceTest, NoInterstitialOnOtherVerdicts) {
+  // Enables kPasswordProtectionInterstitial feature.
+  scoped_feature_list_.InitAndEnableFeature(kPasswordProtectionInterstitial);
+
+  // For password on focus request, no interstitial shown if verdict is
+  // LOW_REPUTATION.
+  InitializeRequest(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE);
+  InitializeVerdict(LoginReputationClientResponse::LOW_REPUTATION);
+
+  security_interstitials::UnsafeResource resource;
+  EXPECT_CALL(*service_->ui_manager(), DisplayBlockingPage(testing::_))
+      .Times(0);
+  RequestFinished(request_.get(), std::move(verdict_));
+
+  // For password on focus request, no interstitial shown if verdict is
+  // SAFE.
+  InitializeVerdict(LoginReputationClientResponse::SAFE);
+  RequestFinished(request_.get(), std::move(verdict_));
+
+  // For protected password entry request, no interstitial shown if verdict is
+  // PHISHING.
+  InitializeRequest(LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
+  InitializeVerdict(LoginReputationClientResponse::PHISHING);
+  RequestFinished(request_.get(), std::move(verdict_));
+
+  // For protected password entry request, no interstitial shown if verdict is
+  // LOW_REPUTATION.
+  InitializeVerdict(LoginReputationClientResponse::LOW_REPUTATION);
+  RequestFinished(request_.get(), std::move(verdict_));
+
+  // For protected password entry request, no interstitial shown if verdict is
+  // SAFE.
+  InitializeVerdict(LoginReputationClientResponse::SAFE);
+  RequestFinished(request_.get(), std::move(verdict_));
 }
 
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index b0ccf260..ba4698e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -78,7 +78,6 @@
         web_contents->GetBrowserContext()->IsOffTheRecord(),
         IsExtendedReportingEnabled(*prefs), IsScout(*prefs),
         is_proceed_anyway_disabled,
-        BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
         kHelpCenterLink);
 
     return new SafeBrowsingBlockingPage(ui_manager, web_contents,
@@ -143,7 +142,8 @@
          threat_type == SB_THREAT_TYPE_URL_MALWARE ||
          threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
          threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
-         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL;
+         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL ||
+         threat_type == SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL;
 }
 
 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index c007f56..c6e948a 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -317,7 +317,6 @@
         web_contents->GetBrowserContext()->IsOffTheRecord(),
         IsExtendedReportingEnabled(*prefs), IsScout(*prefs),
         is_proceed_anyway_disabled,
-        BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
         "cpn_safe_browsing" /* help_center_article_link */);
     return new TestSafeBrowsingBlockingPage(delegate, web_contents,
                                             main_frame_url, unsafe_resources,
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
index b4078913..82ae7443 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_unittest.cc
@@ -92,7 +92,6 @@
         web_contents->GetBrowserContext()->IsOffTheRecord(),
         IsExtendedReportingEnabled(*prefs), IsScout(*prefs),
         is_proceed_anyway_disabled,
-        BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
         "cpn_safe_browsing" /* help_center_article_link */);
     return new TestSafeBrowsingBlockingPage(manager, web_contents,
                                             main_frame_url, unsafe_resources,
@@ -174,7 +173,6 @@
         web_contents->GetBrowserContext()->IsOffTheRecord(),
         IsExtendedReportingEnabled(*prefs), IsScout(*prefs),
         is_proceed_anyway_disabled,
-        BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
         "cpn_safe_browsing" /* help_center_article_link */);
     return new TestSafeBrowsingBlockingPageQuiet(
         manager, web_contents, main_frame_url, unsafe_resources,
diff --git a/chrome/browser/safe_browsing/ui_manager_unittest.cc b/chrome/browser/safe_browsing/ui_manager_unittest.cc
index 329098d9..c200eb4 100644
--- a/chrome/browser/safe_browsing/ui_manager_unittest.cc
+++ b/chrome/browser/safe_browsing/ui_manager_unittest.cc
@@ -351,7 +351,6 @@
                 false,  // is_extended_reporting_enabled
                 false,  // is_scout_reporting_enabled
                 false,  // is_proceed_anyway_disabled
-                BaseBlockingPage::IsMainPageLoadBlocked(unsafe_resources),
                 "cpn_safe_browsing")) {  // help_center_article_link
     // Don't delay details at all for the unittest.
     SetThreatDetailsProceedDelayForTesting(0);
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index 82a9e62..590c3fd 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -165,6 +165,7 @@
         break;
       case safe_browsing::SB_THREAT_TYPE_URL_PHISHING:
       case safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL:
+      case safe_browsing::SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL:
         return security_state::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING;
         break;
       case safe_browsing::SB_THREAT_TYPE_URL_MALWARE:
diff --git a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc
index ce5099f..fa5b140d 100644
--- a/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_themes_sync_test.cc
@@ -4,20 +4,25 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
 #include "chrome/browser/sync/test/integration/sync_test.h"
 #include "chrome/browser/sync/test/integration/themes_helper.h"
 #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "components/browser_sync/profile_sync_service.h"
+#include "content/public/test/test_utils.h"
 
 using themes_helper::GetCustomTheme;
 using themes_helper::GetThemeID;
-using themes_helper::UseCustomTheme;
 using themes_helper::UseDefaultTheme;
 using themes_helper::UseSystemTheme;
 using themes_helper::UsingCustomTheme;
 using themes_helper::UsingDefaultTheme;
 using themes_helper::UsingSystemTheme;
 
+namespace {
+
 class SingleClientThemesSyncTest : public SyncTest {
  public:
   SingleClientThemesSyncTest() : SyncTest(SINGLE_CLIENT) {}
@@ -34,18 +39,18 @@
 IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, CustomTheme) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
-  ASSERT_FALSE(UsingCustomTheme(GetProfile(0)));
-  ASSERT_FALSE(UsingCustomTheme(verifier()));
+  EXPECT_FALSE(UsingCustomTheme(GetProfile(0)));
+  EXPECT_FALSE(UsingCustomTheme(verifier()));
 
-  UseCustomTheme(GetProfile(0), 0);
-  UseCustomTheme(verifier(), 0);
-  ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0)));
-  ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier()));
+  SetCustomTheme(GetProfile(0));
+  SetCustomTheme(verifier());
+  EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0)));
+  EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier()));
 
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
 
-  ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0)));
-  ASSERT_EQ(GetCustomTheme(0), GetThemeID(verifier()));
+  EXPECT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0)));
+  EXPECT_EQ(GetCustomTheme(0), GetThemeID(verifier()));
 }
 
 // TODO(sync): Fails on Chrome OS. See http://crbug.com/84575.
@@ -56,41 +61,43 @@
 #endif  // OS_CHROMEOS
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
-  UseCustomTheme(GetProfile(0), 0);
-  UseCustomTheme(verifier(), 0);
-  ASSERT_FALSE(UsingSystemTheme(GetProfile(0)));
-  ASSERT_FALSE(UsingSystemTheme(verifier()));
+  SetCustomTheme(GetProfile(0));
+  SetCustomTheme(verifier());
+  EXPECT_FALSE(UsingSystemTheme(GetProfile(0)));
+  EXPECT_FALSE(UsingSystemTheme(verifier()));
 
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
 
   UseSystemTheme(GetProfile(0));
   UseSystemTheme(verifier());
-  ASSERT_TRUE(UsingSystemTheme(GetProfile(0)));
-  ASSERT_TRUE(UsingSystemTheme(verifier()));
+  EXPECT_TRUE(UsingSystemTheme(GetProfile(0)));
+  EXPECT_TRUE(UsingSystemTheme(verifier()));
 
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
 
-  ASSERT_TRUE(UsingSystemTheme(GetProfile(0)));
-  ASSERT_TRUE(UsingSystemTheme(verifier()));
+  EXPECT_TRUE(UsingSystemTheme(GetProfile(0)));
+  EXPECT_TRUE(UsingSystemTheme(verifier()));
 }
 
 IN_PROC_BROWSER_TEST_F(SingleClientThemesSyncTest, DefaultTheme) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
-  UseCustomTheme(GetProfile(0), 0);
-  UseCustomTheme(verifier(), 0);
-  ASSERT_FALSE(UsingDefaultTheme(GetProfile(0)));
-  ASSERT_FALSE(UsingDefaultTheme(verifier()));
+  SetCustomTheme(GetProfile(0));
+  EXPECT_FALSE(UsingDefaultTheme(GetProfile(0)));
 
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  SetCustomTheme(verifier());
+  EXPECT_FALSE(UsingDefaultTheme(verifier()));
 
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
   UseDefaultTheme(GetProfile(0));
+  EXPECT_TRUE(UsingDefaultTheme(GetProfile(0)));
   UseDefaultTheme(verifier());
-  ASSERT_TRUE(UsingDefaultTheme(GetProfile(0)));
-  ASSERT_TRUE(UsingDefaultTheme(verifier()));
+  EXPECT_TRUE(UsingDefaultTheme(verifier()));
 
-  ASSERT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
+  EXPECT_TRUE(UpdatedProgressMarkerChecker(GetSyncService(0)).Wait());
 
-  ASSERT_TRUE(UsingDefaultTheme(GetProfile(0)));
-  ASSERT_TRUE(UsingDefaultTheme(verifier()));
+  EXPECT_TRUE(UsingDefaultTheme(GetProfile(0)));
+  EXPECT_TRUE(UsingDefaultTheme(verifier()));
 }
+
+}  // namespace
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.cc b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
index 42ef3e24..d9afa063 100644
--- a/chrome/browser/sync/test/integration/sync_integration_test_util.cc
+++ b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
@@ -5,7 +5,20 @@
 #include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
 
 #include "base/strings/stringprintf.h"
+#include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/sync/test/integration/themes_helper.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "components/browser_sync/profile_sync_service.h"
+#include "content/public/test/test_utils.h"
+
+void SetCustomTheme(Profile* profile, int theme_index) {
+  themes_helper::UseCustomTheme(profile, theme_index);
+  content::WindowedNotificationObserver theme_change_observer(
+      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+      content::Source<ThemeService>(
+          ThemeServiceFactory::GetForProfile(profile)));
+  theme_change_observer.Wait();
+}
 
 ServerCountMatchStatusChecker::ServerCountMatchStatusChecker(
     syncer::ModelType type,
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.h b/chrome/browser/sync/test/integration/sync_integration_test_util.h
index c3af2d7..63df4c9 100644
--- a/chrome/browser/sync/test/integration/sync_integration_test_util.h
+++ b/chrome/browser/sync/test/integration/sync_integration_test_util.h
@@ -11,10 +11,15 @@
 #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
 #include "components/sync/base/model_type.h"
 
+class Profile;
+
 namespace browser_sync {
 class ProfileSyncService;
 }  // namespace browser_sync
 
+// Sets a custom theme and wait until the asynchronous process is done.
+void SetCustomTheme(Profile* profile, int theme_index = 0);
+
 // Checker to block until the server has a given number of entities.
 class ServerCountMatchStatusChecker
     : public fake_server::FakeServerMatchStatusChecker {
diff --git a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc
index 530f209..68beb142 100644
--- a/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_themes_sync_test.cc
@@ -38,7 +38,7 @@
   ASSERT_FALSE(UsingCustomTheme(GetProfile(0)));
   ASSERT_FALSE(UsingCustomTheme(GetProfile(1)));
 
-  UseCustomTheme(GetProfile(0), 0);
+  SetCustomTheme(GetProfile(0));
   ASSERT_EQ(GetCustomTheme(0), GetThemeID(GetProfile(0)));
 
   // TODO(sync): Add functions to simulate when a pending extension
@@ -57,8 +57,8 @@
                        E2E_ENABLED(CustomThenSyncNative)) {
   ASSERT_TRUE(SetupClients());
 
-  UseCustomTheme(GetProfile(0), 0);
-  UseCustomTheme(GetProfile(1), 0);
+  SetCustomTheme(GetProfile(0));
+  SetCustomTheme(GetProfile(1));
 
   ASSERT_TRUE(SetupSync());
 
@@ -77,8 +77,8 @@
                        E2E_ENABLED(CustomThenSyncDefault)) {
   ASSERT_TRUE(SetupClients());
 
-  UseCustomTheme(GetProfile(0), 0);
-  UseCustomTheme(GetProfile(1), 0);
+  SetCustomTheme(GetProfile(0));
+  SetCustomTheme(GetProfile(1));
 
   ASSERT_TRUE(SetupSync());
 
@@ -97,7 +97,7 @@
 IN_PROC_BROWSER_TEST_F(TwoClientThemesSyncTest, E2E_ENABLED(CycleOptions)) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
 
-  UseCustomTheme(GetProfile(0), 0);
+  SetCustomTheme(GetProfile(0));
 
   ASSERT_TRUE(
       ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(0)).Wait());
@@ -115,7 +115,7 @@
   EXPECT_TRUE(UsingDefaultTheme(GetProfile(0)));
   EXPECT_TRUE(UsingDefaultTheme(GetProfile(1)));
 
-  UseCustomTheme(GetProfile(0), 1);
+  SetCustomTheme(GetProfile(0), 1);
   ASSERT_TRUE(
       ThemePendingInstallChecker(GetProfile(1), GetCustomTheme(1)).Wait());
   EXPECT_EQ(GetCustomTheme(1), GetThemeID(GetProfile(0)));
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index a352c67..4f3da008 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -546,13 +546,13 @@
 }
 
 // static
-scoped_refptr<BrowserThemePack> BrowserThemePack::BuildFromExtension(
-    const Extension* extension) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+void BrowserThemePack::BuildFromExtension(
+    const extensions::Extension* extension,
+    scoped_refptr<BrowserThemePack> pack) {
   DCHECK(extension);
   DCHECK(extension->is_theme());
+  DCHECK(!pack->is_valid());
 
-  scoped_refptr<BrowserThemePack> pack(new BrowserThemePack);
   pack->BuildHeader(extension);
   pack->BuildTintsFromJSON(extensions::ThemeInfo::GetTints(extension));
   pack->BuildColorsFromJSON(extensions::ThemeInfo::GetColors(extension));
@@ -567,14 +567,14 @@
       &file_paths);
   pack->BuildSourceImagesArray(file_paths);
 
-  if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_on_ui_thread_))
-    return NULL;
+  if (!pack->LoadRawBitmapsTo(file_paths, &pack->images_))
+    return;
 
-  pack->CreateImages(&pack->images_on_ui_thread_);
+  pack->CreateImages(&pack->images_);
 
   // Make sure the |images_on_file_thread_| has bitmaps for supported
   // scale factors before passing to FILE thread.
-  pack->images_on_file_thread_ = pack->images_on_ui_thread_;
+  pack->images_on_file_thread_ = pack->images_;
   for (ImageCache::iterator it = pack->images_on_file_thread_.begin();
        it != pack->images_on_file_thread_.end(); ++it) {
     gfx::ImageSkia* image_skia =
@@ -582,13 +582,13 @@
     image_skia->MakeThreadSafe();
   }
 
-  // Set ThemeImageSource on |images_on_ui_thread_| to resample the source
+  // Set ThemeImageSource on |images_| to resample the source
   // image if a caller of BrowserThemePack::GetImageNamed() requests an
   // ImageSkiaRep for a scale factor not specified by the theme author.
   // Callers of BrowserThemePack::GetImageNamed() to be able to retrieve
   // ImageSkiaReps for all supported scale factors.
-  for (ImageCache::iterator it = pack->images_on_ui_thread_.begin();
-       it != pack->images_on_ui_thread_.end(); ++it) {
+  for (ImageCache::iterator it = pack->images_.begin();
+       it != pack->images_.end(); ++it) {
     const gfx::ImageSkia source_image_skia = it->second.AsImageSkia();
     ThemeImageSource* source = new ThemeImageSource(source_image_skia);
     // image_skia takes ownership of source.
@@ -603,7 +603,7 @@
   }
 
   // The BrowserThemePack is now in a consistent state.
-  return pack;
+  pack->is_valid_ = true;
 }
 
 // static
@@ -671,6 +671,7 @@
                 << "from those supported by platform.";
     return NULL;
   }
+  pack->is_valid_ = true;
   return pack;
 }
 
@@ -683,6 +684,13 @@
   return false;
 }
 
+BrowserThemePack::BrowserThemePack() : CustomThemeSupplier(EXTENSION) {
+  scale_factors_ = ui::GetSupportedScaleFactors();
+  // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default.
+  if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P))
+    scale_factors_.push_back(ui::SCALE_FACTOR_100P);
+}
+
 bool BrowserThemePack::WriteToDisk(const base::FilePath& path) const {
   // Add resources for each of the property arrays.
   RawDataForWriting resources;
@@ -771,8 +779,8 @@
     return gfx::Image();
 
   // Check if the image is cached.
-  ImageCache::const_iterator image_iter = images_on_ui_thread_.find(prs_id);
-  if (image_iter != images_on_ui_thread_.end())
+  ImageCache::const_iterator image_iter = images_.find(prs_id);
+  if (image_iter != images_.end())
     return image_iter->second;
 
   ThemeImagePngSource::PngMap png_map;
@@ -786,7 +794,7 @@
     gfx::ImageSkia image_skia(new ThemeImagePngSource(png_map), 1.0f);
     // |image_skia| takes ownership of ThemeImagePngSource.
     gfx::Image ret = gfx::Image(image_skia);
-    images_on_ui_thread_[prs_id] = ret;
+    images_[prs_id] = ret;
     return ret;
   }
 
@@ -830,19 +838,6 @@
 
 // private:
 
-BrowserThemePack::BrowserThemePack()
-    : CustomThemeSupplier(EXTENSION),
-      header_(NULL),
-      tints_(NULL),
-      colors_(NULL),
-      display_properties_(NULL),
-      source_images_(NULL) {
-  scale_factors_ = ui::GetSupportedScaleFactors();
-  // On Windows HiDPI SCALE_FACTOR_100P may not be supported by default.
-  if (!base::ContainsValue(scale_factors_, ui::SCALE_FACTOR_100P))
-    scale_factors_.push_back(ui::SCALE_FACTOR_100P);
-}
-
 void BrowserThemePack::BuildHeader(const Extension* extension) {
   header_ = new BrowserThemePackHeader;
   header_->version = kThemePackVersion;
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h
index cc975cc..d527e973 100644
--- a/chrome/browser/themes/browser_theme_pack.h
+++ b/chrome/browser/themes/browser_theme_pack.h
@@ -53,11 +53,11 @@
 // will trip our IO on the UI thread detector.
 class BrowserThemePack : public CustomThemeSupplier {
  public:
-  // Builds the theme pack from all data from |extension|. This is often done
-  // on a separate thread as it takes so long. This can fail and return NULL in
-  // the case where the theme has invalid data.
-  static scoped_refptr<BrowserThemePack> BuildFromExtension(
-      const extensions::Extension* extension);
+  // Builds the theme from |extension| into |pack|. This may be done on a
+  // separate thread as it takes so long. This can fail in the case where the
+  // theme has invalid data, in which case |pack->is_valid()| will be false.
+  static void BuildFromExtension(const extensions::Extension* extension,
+                                 scoped_refptr<BrowserThemePack> pack);
 
   // Builds the theme pack from a previously performed WriteToDisk(). This
   // operation should be relatively fast, as it should be an mmap() and some
@@ -69,6 +69,11 @@
   // in the data pack.
   static bool IsPersistentImageID(int id);
 
+  // Default. Everything is empty.
+  BrowserThemePack();
+
+  bool is_valid() const { return is_valid_; }
+
   // Builds a data pack on disk at |path| for future quick loading by
   // BuildFromDataPack(). Often (but not always) called from the file thread;
   // implementation should be threadsafe because neither thread will write to
@@ -103,9 +108,6 @@
   // Maps image ids to maps of scale factors to file paths.
   typedef std::map<int, ScaleFactorToFileMap> FilePathMap;
 
-  // Default. Everything is empty.
-  BrowserThemePack();
-
   ~BrowserThemePack() override;
 
   // Builds a header ready to write to disk.
@@ -217,7 +219,7 @@
 
     // theme_id without NULL terminator.
     uint8_t theme_id[16];
-  } *header_;
+  }* header_ = nullptr;
 
   // The remaining structs represent individual entries in an array. For the
   // following three structs, BrowserThemePack will either allocate an array or
@@ -227,21 +229,21 @@
     double h;
     double s;
     double l;
-  } *tints_;
+  }* tints_ = nullptr;
 
   struct ColorPair {
     int32_t id;
     SkColor color;
-  } *colors_;
+  }* colors_ = nullptr;
 
   struct DisplayPropertyPair {
     int32_t id;
     int32_t property;
-  } *display_properties_;
+  }* display_properties_ = nullptr;
 
   // A list of included source images. A pointer to a -1 terminated array of
   // our persistent IDs.
-  int* source_images_;
+  int* source_images_ = nullptr;
 #pragma pack(pop)
 
   // The scale factors represented by the images in the theme pack.
@@ -254,9 +256,8 @@
   RawImages image_memory_;
 
   // Loaded images. These are loaded from |image_memory_|, from |data_pack_|,
-  // and by BuildFromExtension(). These images should only be accessed on the UI
-  // thread.
-  ImageCache images_on_ui_thread_;
+  // and by BuildFromExtension().
+  ImageCache images_;
 
   // Cache of images created in BuildFromExtension(). Once the theme pack is
   // created, this cache should only be accessed on the file thread. There
@@ -264,6 +265,10 @@
   // or vice versa.
   ImageCache images_on_file_thread_;
 
+  // Whether the theme pack has been succesfully initialized and is ready to
+  // use.
+  bool is_valid_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(BrowserThemePack);
 };
 
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index 1180081..22e9d2f 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/json/json_file_value_serializer.h"
 #include "base/json/json_reader.h"
 #include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "chrome/browser/themes/theme_properties.h"
@@ -34,14 +35,16 @@
 
 class BrowserThemePackTest : public ::testing::Test {
  public:
-  BrowserThemePackTest() {
+  BrowserThemePackTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
+        theme_pack_(new BrowserThemePack()) {
     std::vector<ui::ScaleFactor> scale_factors;
     scale_factors.push_back(ui::SCALE_FACTOR_100P);
     scale_factors.push_back(ui::SCALE_FACTOR_200P);
     scoped_set_supported_scale_factors_.reset(
-      new ui::test::ScopedSetSupportedScaleFactors(scale_factors));
-    theme_pack_ = new BrowserThemePack();
+        new ui::test::ScopedSetSupportedScaleFactors(scale_factors));
   }
+  ~BrowserThemePackTest() override {}
 
   // Transformation for link underline colors.
   SkColor BuildThirdOpacity(SkColor color_link) {
@@ -142,33 +145,22 @@
   }
 
   bool LoadRawBitmapsTo(const TestFilePathMap& out_file_paths) {
-    return theme_pack_->LoadRawBitmapsTo(out_file_paths,
-                                         &theme_pack_->images_on_ui_thread_);
+    return theme_pack_->LoadRawBitmapsTo(out_file_paths, &theme_pack_->images_);
   }
 
   // This function returns void in order to be able use ASSERT_...
   // The BrowserThemePack is returned in |pack|.
   void BuildFromUnpackedExtension(const base::FilePath& extension_path,
-                                  scoped_refptr<BrowserThemePack>& pack) {
-    base::FilePath manifest_path =
-        extension_path.AppendASCII("manifest.json");
-    std::string error;
-    JSONFileValueDeserializer deserializer(manifest_path);
-    std::unique_ptr<base::DictionaryValue> valid_value =
-        base::DictionaryValue::From(deserializer.Deserialize(NULL, &error));
-    EXPECT_EQ("", error);
-    ASSERT_TRUE(valid_value.get());
-    scoped_refptr<Extension> extension(
-        Extension::Create(
-            extension_path,
-            extensions::Manifest::INVALID_LOCATION,
-            *valid_value,
-            Extension::REQUIRE_KEY,
-            &error));
-    ASSERT_TRUE(extension.get());
-    ASSERT_EQ("", error);
-    pack = BrowserThemePack::BuildFromExtension(extension.get());
-    ASSERT_TRUE(pack.get());
+                                  scoped_refptr<BrowserThemePack>* pack) {
+    io_waiter_.reset(new base::WaitableEvent(
+        base::WaitableEvent::ResetPolicy::AUTOMATIC,
+        base::WaitableEvent::InitialState::NOT_SIGNALED));
+    content::BrowserThread::PostTask(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(&BrowserThemePackTest::DoBuildFromUnpackedExtension,
+                   base::Unretained(this), extension_path, pack));
+    io_waiter_->Wait();
+    ASSERT_TRUE((*pack)->is_valid());
   }
 
   base::FilePath GetStarGazingPath() {
@@ -347,12 +339,33 @@
     }
   }
 
-  content::TestBrowserThreadBundle test_browser_thread_bundle_;
-
+ protected:
   typedef std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors>
       ScopedSetSupportedScaleFactors;
   ScopedSetSupportedScaleFactors scoped_set_supported_scale_factors_;
+
+  void DoBuildFromUnpackedExtension(const base::FilePath& extension_path,
+                                    scoped_refptr<BrowserThemePack>* pack) {
+    base::FilePath manifest_path = extension_path.AppendASCII("manifest.json");
+    std::string error;
+    JSONFileValueDeserializer deserializer(manifest_path);
+    std::unique_ptr<base::DictionaryValue> valid_value =
+        base::DictionaryValue::From(deserializer.Deserialize(NULL, &error));
+    EXPECT_EQ("", error);
+    ASSERT_TRUE(valid_value.get());
+    scoped_refptr<Extension> extension(Extension::Create(
+        extension_path, extensions::Manifest::INVALID_LOCATION, *valid_value,
+        Extension::REQUIRE_KEY, &error));
+    ASSERT_TRUE(extension.get());
+    ASSERT_EQ("", error);
+    *pack = new BrowserThemePack;
+    BrowserThemePack::BuildFromExtension(extension.get(), *pack);
+    io_waiter_->Signal();
+  }
+
+  content::TestBrowserThreadBundle thread_bundle_;
   scoped_refptr<BrowserThemePack> theme_pack_;
+  std::unique_ptr<base::WaitableEvent> io_waiter_;
 };
 
 // 'ntp_section' used to correspond to ThemeProperties::COLOR_NTP_SECTION,
@@ -569,7 +582,7 @@
   {
     base::FilePath star_gazing_path = GetStarGazingPath();
     scoped_refptr<BrowserThemePack> pack;
-    BuildFromUnpackedExtension(star_gazing_path, pack);
+    BuildFromUnpackedExtension(star_gazing_path, &pack);
     ASSERT_TRUE(pack->WriteToDisk(file));
     VerifyStarGazing(pack.get());
   }
@@ -593,7 +606,7 @@
   {
     base::FilePath hidpi_path = GetHiDpiThemePath();
     scoped_refptr<BrowserThemePack> pack;
-    BuildFromUnpackedExtension(hidpi_path, pack);
+    BuildFromUnpackedExtension(hidpi_path, &pack);
     ASSERT_TRUE(pack->WriteToDisk(file));
     VerifyHiDpiTheme(pack.get());
   }
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index 6a9d0e1..34cd105 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -17,10 +17,12 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/browser_theme_pack.h"
 #include "chrome/browser/themes/custom_theme_supplier.h"
@@ -262,7 +264,7 @@
     case extensions::NOTIFICATION_EXTENSION_ENABLED: {
       const Extension* extension = Details<const Extension>(details).ptr();
       if (extension->is_theme())
-        SetTheme(extension);
+        DoSetTheme(extension, true);
       break;
     }
     default:
@@ -271,40 +273,18 @@
 }
 
 void ThemeService::SetTheme(const Extension* extension) {
+  DoSetTheme(extension, false);
+}
+
+void ThemeService::RevertToTheme(const Extension* extension) {
   DCHECK(extension->is_theme());
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (!service->IsExtensionEnabled(extension->id())) {
-    // |extension| is disabled when reverting to the previous theme via an
-    // infobar.
-    service->EnableExtension(extension->id());
-    // Enabling the extension will call back to SetTheme().
-    return;
-  }
-
-  std::string previous_theme_id = GetThemeID();
-
-  // Clear our image cache.
-  FreePlatformCaches();
-
-  BuildFromExtension(extension);
-  SaveThemeID(extension->id());
-
-  NotifyThemeChanged();
-  base::RecordAction(UserMetricsAction("Themes_Installed"));
-
-  if (previous_theme_id != kDefaultThemeID &&
-      previous_theme_id != extension->id() &&
-      service->GetInstalledExtension(previous_theme_id)) {
-    // Do not disable the previous theme if it is already uninstalled. Sending
-    // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be
-    // uninstalled when the notification causes the remaining infobar to close
-    // and does not open any new infobars. See crbug.com/468280.
-
-    // Disable the old theme.
-    service->DisableExtension(previous_theme_id,
-                              extensions::Extension::DISABLE_USER_ACTION);
-  }
+  DCHECK(!service->IsExtensionEnabled(extension->id()));
+  // |extension| is disabled when reverting to the previous theme via an
+  // infobar.
+  service->EnableExtension(extension->id());
+  // Enabling the extension will call back to SetTheme().
 }
 
 void ThemeService::UseDefaultTheme() {
@@ -349,8 +329,10 @@
 void ThemeService::OnInfobarDestroyed() {
   number_of_infobars_--;
 
-  if (number_of_infobars_ == 0)
+  if (number_of_infobars_ == 0 &&
+      !build_extension_task_tracker_.HasTrackedTasks()) {
     RemoveUnusedThemes(false);
+  }
 }
 
 void ThemeService::RemoveUnusedThemes(bool ignore_infobars) {
@@ -375,8 +357,8 @@
   for (extensions::ExtensionSet::const_iterator it = extensions->begin();
        it != extensions->end(); ++it) {
     const extensions::Extension* extension = it->get();
-    if (extension->is_theme() &&
-        extension->id() != current_theme) {
+    if (extension->is_theme() && extension->id() != current_theme &&
+        extension->id() != building_extension_id_) {
       // Only uninstall themes which are not disabled or are disabled with
       // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled
       // themes because externally installed themes are initially disabled.
@@ -578,7 +560,7 @@
 
   // If we don't have a file pack, we're updating from an old version.
   base::FilePath path = prefs->GetFilePath(prefs::kCurrentThemePackFilename);
-  if (path != base::FilePath()) {
+  if (!path.empty()) {
     path = path.Append(chrome::kThemePackFilename);
     SwapThemeSupplier(BrowserThemePack::BuildFromDataPack(path, current_id));
     if (theme_supplier_)
@@ -685,6 +667,15 @@
   return SkColorSetA(separator_color, alpha);
 }
 
+void ThemeService::DoSetTheme(const Extension* extension,
+                              bool suppress_infobar) {
+  DCHECK(extension->is_theme());
+  DCHECK(extensions::ExtensionSystem::Get(profile_)
+             ->extension_service()
+             ->IsExtensionEnabled(extension->id()));
+  BuildFromExtension(extension, suppress_infobar);
+}
+
 gfx::ImageSkia* ThemeService::GetImageSkiaNamed(int id, bool incognito) const {
   gfx::Image image = GetImageNamed(id, incognito);
   if (image.IsEmpty())
@@ -785,10 +776,6 @@
     // be recreated from the extension.
     MigrateTheme();
     set_ready();
-
-    // Send notification in case anyone requested data and cached it when the
-    // theme service was not ready yet.
-    NotifyThemeChanged();
   }
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -806,15 +793,18 @@
 }
 
 void ThemeService::MigrateTheme() {
-  // TODO(erg): We need to pop up a dialog informing the user that their
-  // theme is being migrated.
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   const Extension* extension =
       service ? service->GetExtensionById(GetThemeID(), false) : nullptr;
   if (extension) {
     DLOG(ERROR) << "Migrating theme";
-    BuildFromExtension(extension);
+    // Theme migration is done on the UI thread. Blocking the UI from appearing
+    // until it's ready is deemed better than showing a blip of the default
+    // theme.
+    scoped_refptr<BrowserThemePack> pack(new BrowserThemePack);
+    BrowserThemePack::BuildFromExtension(extension, pack);
+    OnThemeBuiltFromExtension(extension->id(), pack, true);
     base::RecordAction(UserMetricsAction("Themes.Migrated"));
   } else {
     DLOG(ERROR) << "Theme is mysteriously gone.";
@@ -841,10 +831,26 @@
   profile_->GetPrefs()->SetString(prefs::kCurrentThemeID, id);
 }
 
-void ThemeService::BuildFromExtension(const Extension* extension) {
-  scoped_refptr<BrowserThemePack> pack(
-      BrowserThemePack::BuildFromExtension(extension));
-  if (!pack.get()) {
+void ThemeService::BuildFromExtension(const Extension* extension,
+                                      bool suppress_infobar) {
+  build_extension_task_tracker_.TryCancelAll();
+  building_extension_id_ = extension->id();
+  scoped_refptr<BrowserThemePack> pack(new BrowserThemePack);
+  auto task_runner = base::CreateTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::USER_BLOCKING});
+  build_extension_task_tracker_.PostTaskAndReply(
+      task_runner.get(), FROM_HERE,
+      base::Bind(&BrowserThemePack::BuildFromExtension, extension, pack),
+      base::Bind(&ThemeService::OnThemeBuiltFromExtension,
+                 weak_ptr_factory_.GetWeakPtr(), extension->id(), pack,
+                 suppress_infobar));
+}
+
+void ThemeService::OnThemeBuiltFromExtension(
+    const extensions::ExtensionId& extension_id,
+    scoped_refptr<BrowserThemePack> pack,
+    bool suppress_infobar) {
+  if (!pack->is_valid()) {
     // TODO(erg): We've failed to install the theme; perhaps we should tell the
     // user? http://crbug.com/34780
     LOG(ERROR) << "Could not load theme.";
@@ -855,16 +861,57 @@
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   if (!service)
     return;
+  const Extension* extension = extensions::ExtensionRegistry::Get(profile_)
+                                   ->enabled_extensions()
+                                   .GetByID(extension_id);
+  if (!extension)
+    return;
 
   // Write the packed file to disk.
   service->GetFileTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&WritePackToDiskCallback, base::RetainedRef(pack),
                             extension->path()));
 
+  const std::string previous_theme_id = GetThemeID();
+  const bool previous_using_system_theme = UsingSystemTheme();
+
   // Save only the extension path. The packed file will be loaded via
   // LoadThemePrefs().
   SavePackName(extension->path());
   SwapThemeSupplier(pack);
+
+  // Clear our image cache.
+  FreePlatformCaches();
+  SaveThemeID(extension->id());
+  NotifyThemeChanged();
+
+  // Same old theme, but the theme has changed (migrated) or auto-updated.
+  if (previous_theme_id == extension->id())
+    return;
+
+  base::RecordAction(UserMetricsAction("Themes_Installed"));
+
+  bool can_revert_theme = previous_theme_id == kDefaultThemeID;
+  if (previous_theme_id != kDefaultThemeID &&
+      service->GetInstalledExtension(previous_theme_id)) {
+    // Do not disable the previous theme if it is already uninstalled. Sending
+    // NOTIFICATION_BROWSER_THEME_CHANGED causes the previous theme to be
+    // uninstalled when the notification causes the remaining infobar to close
+    // and does not open any new infobars. See crbug.com/468280.
+
+    // Disable the old theme.
+    service->DisableExtension(previous_theme_id,
+                              extensions::Extension::DISABLE_USER_ACTION);
+
+    can_revert_theme = true;
+  }
+
+  // Offer to revert to the old theme.
+  if (can_revert_theme && !suppress_infobar) {
+    ThemeInstalledInfoBarDelegate::Create(
+        extension, profile_, previous_theme_id, previous_using_system_theme);
+  }
+  building_extension_id_.clear();
 }
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
index 51c676c..c941a63 100644
--- a/chrome/browser/themes/theme_service.h
+++ b/chrome/browser/themes/theme_service.h
@@ -16,14 +16,17 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
+#include "base/task/cancelable_task_tracker.h"
 #include "build/build_config.h"
 #include "chrome/common/features.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/common/extension_id.h"
 #include "extensions/features/features.h"
 #include "ui/base/theme_provider.h"
 
+class BrowserThemePack;
 class CustomThemeSupplier;
 class ThemeSyncableService;
 class Profile;
@@ -82,6 +85,9 @@
   // ExtensionService.
   virtual void SetTheme(const extensions::Extension* extension);
 
+  // Similar to SetTheme, but doesn't show an undo infobar.
+  void RevertToTheme(const extensions::Extension* extension);
+
   // Reset the theme to default.
   virtual void UseDefaultTheme();
 
@@ -230,6 +236,9 @@
   // and contrasting with the foreground tab is the most important).
   static SkColor GetSeparatorColor(SkColor tab_color, SkColor frame_color);
 
+  void DoSetTheme(const extensions::Extension* extension,
+                  bool suppress_infobar);
+
   // These methods provide the implementation for ui::ThemeProvider (exposed
   // via BrowserThemeProvider).
   gfx::ImageSkia* GetImageSkiaNamed(int id, bool incognito) const;
@@ -270,8 +279,15 @@
   void SaveThemeID(const std::string& id);
 
   // Implementation of SetTheme() (and the fallback from LoadThemePrefs() in
-  // case we don't have a theme pack).
-  void BuildFromExtension(const extensions::Extension* extension);
+  // case we don't have a theme pack). |new_theme| indicates whether this is a
+  // newly installed theme or a migration.
+  void BuildFromExtension(const extensions::Extension* extension,
+                          bool new_theme);
+
+  // Callback when |pack| has finished or failed building.
+  void OnThemeBuiltFromExtension(const extensions::ExtensionId& extension_id,
+                                 scoped_refptr<BrowserThemePack> pack,
+                                 bool new_theme);
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   // Returns true if the profile belongs to a supervised user.
@@ -328,6 +344,14 @@
 
   SEQUENCE_CHECKER(sequence_checker_);
 
+  // Allows us to cancel building a theme pack from an extension.
+  base::CancelableTaskTracker build_extension_task_tracker_;
+
+  // The ID of the theme that's currently being built on a different thread.
+  // We hold onto this just to be sure not to uninstall the extension view
+  // RemoveUnusedThemes while it's still being built.
+  std::string building_extension_id_;
+
   base::WeakPtrFactory<ThemeService> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ThemeService);
diff --git a/chrome/browser/themes/theme_service_browsertest.cc b/chrome/browser/themes/theme_service_browsertest.cc
index 7ed17415..d9d19f9 100644
--- a/chrome/browser/themes/theme_service_browsertest.cc
+++ b/chrome/browser/themes/theme_service_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/threading/thread_restrictions.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/component_loader.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
@@ -15,6 +16,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/test/test_utils.h"
 
 namespace {
 
@@ -59,6 +61,14 @@
             profile->GetPrefs()->GetFilePath(prefs::kCurrentThemePackFilename));
 
   InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
+  // The theme isn't installed synchronously.
+  EXPECT_FALSE(UsingCustomTheme(*theme_service));
+
+  // Wait for the theme to be loaded.
+  content::WindowedNotificationObserver theme_change_observer(
+      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+      content::Source<ThemeService>(theme_service));
+  theme_change_observer.Wait();
 
   // Check that the theme was installed.
   EXPECT_TRUE(UsingCustomTheme(*theme_service));
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc
index 7f6807ee..83114e6 100644
--- a/chrome/browser/themes/theme_service_unittest.cc
+++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -77,8 +78,7 @@
     installer->Load(temp_dir);
     std::string extension_id = observer.WaitForExtensionLoaded()->id();
 
-    // Let the ThemeService finish creating the theme pack.
-    base::RunLoop().RunUntilIdle();
+    WaitForThemeInstall();
 
     return extension_id;
   }
@@ -111,6 +111,14 @@
     return theme_service->get_theme_supplier();
   }
 
+  void WaitForThemeInstall() {
+    content::WindowedNotificationObserver theme_change_observer(
+        chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+        content::Source<ThemeService>(
+            ThemeServiceFactory::GetForProfile(profile())));
+    theme_change_observer.Wait();
+  }
+
   // Alpha blends a non-opaque foreground color against an opaque background.
   // This is not the same as color_utils::AlphaBlend() since it gets the opacity
   // from the foreground color and then does not blend the two colors' alpha
@@ -163,8 +171,6 @@
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
-  // Let the ThemeService uninstall unused themes.
-  base::RunLoop().RunUntilIdle();
 
   base::ScopedTempDir temp_dir1;
   ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
@@ -188,19 +194,19 @@
 
   // 2) Enabling a disabled theme extension should swap the current theme.
   service_->EnableExtension(extension1_id);
-  base::RunLoop().RunUntilIdle();
+  WaitForThemeInstall();
   EXPECT_EQ(extension1_id, theme_service->GetThemeID());
   EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
   EXPECT_TRUE(registry_->GetExtensionById(extension2_id,
                                           ExtensionRegistry::DISABLED));
 
-  // 3) Using SetTheme() with a disabled theme should enable and set the
+  // 3) Using RevertToTheme() with a disabled theme should enable and set the
   // theme. This is the case when the user reverts to the previous theme
   // via an infobar.
   const extensions::Extension* extension2 =
       service_->GetInstalledExtension(extension2_id);
-  theme_service->SetTheme(extension2);
-  base::RunLoop().RunUntilIdle();
+  theme_service->RevertToTheme(extension2);
+  WaitForThemeInstall();
   EXPECT_EQ(extension2_id, theme_service->GetThemeID());
   EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
   EXPECT_TRUE(registry_->GetExtensionById(extension1_id,
@@ -340,18 +346,21 @@
   // Show an infobar.
   theme_service->OnInfobarDisplayed();
 
-  // Install another theme. Emulate the infobar destroying itself (and
-  // causing unused themes to be uninstalled) as a result of the
-  // NOTIFICATION_BROWSER_THEME_CHANGED notification.
+  // Install another theme. The first extension shouldn't be uninstalled yet as
+  // it should be possible to revert to it. Emulate the infobar destroying
+  // itself as a result of the NOTIFICATION_BROWSER_THEME_CHANGED notification.
   {
     InfobarDestroyerOnThemeChange destroyer(profile_.get());
     const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.GetPath());
-    ASSERT_EQ(extension2_id, theme_service->GetThemeID());
-    ASSERT_FALSE(service_->GetInstalledExtension(extension1_id));
+    EXPECT_EQ(extension2_id, theme_service->GetThemeID());
   }
 
+  auto* extension1 = service_->GetInstalledExtension(extension1_id);
+  ASSERT_TRUE(extension1);
+
   // Check that it is possible to reinstall extension1.
-  ASSERT_EQ(extension1_id, LoadUnpackedThemeAt(temp_dir1.GetPath()));
+  ThemeServiceFactory::GetForProfile(profile_.get())->RevertToTheme(extension1);
+  WaitForThemeInstall();
   EXPECT_EQ(extension1_id, theme_service->GetThemeID());
 }
 
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 44f2a80..ddeed1a 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -310,6 +310,10 @@
   HideAutofillPopup();
 }
 
+void ChromeAutofillClient::DidAttachInterstitialPage() {
+  HideAutofillPopup();
+}
+
 #if !defined(OS_ANDROID)
 void ChromeAutofillClient::OnZoomChanged(
     const zoom::ZoomController::ZoomChangedEventData& data) {
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index ec684ab..0e9dd28 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -94,6 +94,8 @@
   // content::WebContentsObserver implementation.
   void MainFrameWasResized(bool width_changed) override;
   void WebContentsDestroyed() override;
+  // Hide autofill popup if an interstitial is shown.
+  void DidAttachInterstitialPage() override;
 
 #if !defined(OS_ANDROID)
   // ZoomObserver implementation.
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.cc b/chrome/browser/ui/extensions/extension_install_ui_default.cc
index 53fda5b..6114b11 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.cc
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.cc
@@ -9,7 +9,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/theme_installed_infobar_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
@@ -141,25 +140,13 @@
     content::BrowserContext* context)
     : profile_(Profile::FromBrowserContext(context)),
       skip_post_install_ui_(false),
-      previous_using_system_theme_(false),
-      use_app_installed_bubble_(false) {
-  // |profile| can be NULL during tests.
-  if (profile_) {
-    // Remember the current theme in case the user presses undo.
-    const Extension* previous_theme =
-        ThemeServiceFactory::GetThemeForProfile(profile_);
-    if (previous_theme)
-      previous_theme_id_ = previous_theme->id();
-    previous_using_system_theme_ =
-        ThemeServiceFactory::GetForProfile(profile_)->UsingSystemTheme();
-  }
-}
+      use_app_installed_bubble_(false) {}
 
 ExtensionInstallUIDefault::~ExtensionInstallUIDefault() {}
 
 void ExtensionInstallUIDefault::OnInstallSuccess(const Extension* extension,
                                                  const SkBitmap* icon) {
-  if (skip_post_install_ui_)
+  if (skip_post_install_ui_ || extension->is_theme())
     return;
 
   if (!profile_) {
@@ -169,12 +156,6 @@
     return;
   }
 
-  if (extension->is_theme()) {
-    ThemeInstalledInfoBarDelegate::Create(
-        extension, profile_, previous_theme_id_, previous_using_system_theme_);
-    return;
-  }
-
   // Extensions aren't enabled by default in incognito so we confirm
   // the install in a normal window.
   Profile* current_profile = profile_->GetOriginalProfile();
diff --git a/chrome/browser/ui/extensions/extension_install_ui_default.h b/chrome/browser/ui/extensions/extension_install_ui_default.h
index 32d40e1..2586f2e 100644
--- a/chrome/browser/ui/extensions/extension_install_ui_default.h
+++ b/chrome/browser/ui/extensions/extension_install_ui_default.h
@@ -35,10 +35,6 @@
   // Whether or not to show the default UI after completing the installation.
   bool skip_post_install_ui_;
 
-  // Used to undo theme installation.
-  std::string previous_theme_id_;
-  bool previous_using_system_theme_;
-
   // Whether to show an installed bubble on app install, or use the default
   // action of opening a new tab page.
   bool use_app_installed_bubble_;
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 7bc09d7..e61e99b4 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -291,8 +291,7 @@
   void InstallThemeAndVerify(const std::string& theme_dir,
                              const std::string& theme_name) {
     const extensions::Extension* theme =
-        ThemeServiceFactory::GetThemeForProfile(
-            ExtensionBrowserTest::browser()->profile());
+        ThemeServiceFactory::GetThemeForProfile(profile());
     // If there is already a theme installed, the current theme should be
     // disabled and the new one installed + enabled.
     int expected_change = theme ? 0 : 1;
@@ -300,9 +299,13 @@
     const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir);
     ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
         theme_path, expected_change, ExtensionBrowserTest::browser()));
+    content::WindowedNotificationObserver theme_change_observer(
+        chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
+        content::Source<ThemeService>(
+            ThemeServiceFactory::GetForProfile(profile())));
+    theme_change_observer.Wait();
     const extensions::Extension* new_theme =
-        ThemeServiceFactory::GetThemeForProfile(
-            ExtensionBrowserTest::browser()->profile());
+        ThemeServiceFactory::GetThemeForProfile(profile());
     ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme);
     ASSERT_EQ(new_theme->name(), theme_name);
   }
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index feb52eef..2ea4346 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -30,7 +30,6 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/table/table_view.h"
 #include "ui/views/layout/fill_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_client_view.h"
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 06cc9d02..990fa4a 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -253,11 +253,6 @@
       IDR_WEBRTC_DESKTOP_CAPTURE_PRIVATE_CUSTOM_BINDINGS_JS);
   source_map->RegisterSource("webstore", IDR_WEBSTORE_CUSTOM_BINDINGS_JS);
 
-  // Custom types sources.
-  source_map->RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
-  source_map->RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
-  source_map->RegisterSource("ChromeDirectSetting",
-                             IDR_CHROME_DIRECT_SETTING_JS);
 
   // Platform app sources that are not API-specific..
   source_map->RegisterSource("chromeWebViewInternal",
@@ -283,8 +278,15 @@
   source_map->RegisterSource("url/mojo/url.mojom", IDR_MOJO_URL_MOJOM_JS);
 
   // These bindings are unnecessary with native bindings enabled.
-  if (!extensions::FeatureSwitch::native_crx_bindings()->IsEnabled())
+  if (!extensions::FeatureSwitch::native_crx_bindings()->IsEnabled()) {
     source_map->RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
+
+    // Custom types sources.
+    source_map->RegisterSource("ChromeSetting", IDR_CHROME_SETTING_JS);
+    source_map->RegisterSource("ContentSetting", IDR_CONTENT_SETTING_JS);
+    source_map->RegisterSource("ChromeDirectSetting",
+                               IDR_CHROME_DIRECT_SETTING_JS);
+  }
 }
 
 void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
diff --git a/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js b/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js
index 6beb9b7..7510ace 100644
--- a/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/cast_streaming_receiver_session_custom_bindings.js
@@ -4,17 +4,20 @@
 
 // Custom binding for the Cast Streaming Session API.
 
-var binding = require('binding').Binding.create(
-    'cast.streaming.receiverSession');
+var binding =
+    apiBridge ||
+    require('binding').Binding.create('cast.streaming.receiverSession');
 var natives = requireNative('cast_streaming_natives');
 
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
   var apiFunctions = bindingsAPI.apiFunctions;
-  apiFunctions.setHandleRequest('createAndBind',
+  apiFunctions.setHandleRequest(
+      'createAndBind',
       function(ap, vp, local, weidgth, height, fr, url, cb, op) {
         natives.StartCastRtpReceiver(
             ap, vp, local, weidgth, height, fr, url, cb, op);
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/chrome/renderer/resources/extensions/cast_streaming_rtp_stream_custom_bindings.js b/chrome/renderer/resources/extensions/cast_streaming_rtp_stream_custom_bindings.js
index dbcf8be..17ac6a5 100644
--- a/chrome/renderer/resources/extensions/cast_streaming_rtp_stream_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/cast_streaming_rtp_stream_custom_bindings.js
@@ -4,7 +4,8 @@
 
 // Custom binding for the Cast Streaming RtpStream API.
 
-var binding = require('binding').Binding.create('cast.streaming.rtpStream');
+var binding = apiBridge ||
+              require('binding').Binding.create('cast.streaming.rtpStream');
 var natives = requireNative('cast_streaming_natives');
 
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
@@ -40,4 +41,5 @@
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/chrome/renderer/resources/extensions/cast_streaming_session_custom_bindings.js b/chrome/renderer/resources/extensions/cast_streaming_session_custom_bindings.js
index b0f40a69..3277edc 100644
--- a/chrome/renderer/resources/extensions/cast_streaming_session_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/cast_streaming_session_custom_bindings.js
@@ -4,7 +4,8 @@
 
 // Custom binding for the Cast Streaming Session API.
 
-var binding = require('binding').Binding.create('cast.streaming.session');
+var binding = apiBridge ||
+              require('binding').Binding.create('cast.streaming.session');
 var natives = requireNative('cast_streaming_natives');
 
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
@@ -15,4 +16,5 @@
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/chrome/renderer/resources/extensions/cast_streaming_udp_transport_custom_bindings.js b/chrome/renderer/resources/extensions/cast_streaming_udp_transport_custom_bindings.js
index d1389b6..0ec5990 100644
--- a/chrome/renderer/resources/extensions/cast_streaming_udp_transport_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/cast_streaming_udp_transport_custom_bindings.js
@@ -4,7 +4,8 @@
 
 // Custom binding for the Cast Streaming UdpTransport API.
 
-var binding = require('binding').Binding.create('cast.streaming.udpTransport');
+var binding = apiBridge ||
+              require('binding').Binding.create('cast.streaming.udpTransport');
 var natives = requireNative('cast_streaming_natives');
 
 binding.registerCustomHook(function(bindingsAPI, extensionId) {
@@ -23,4 +24,5 @@
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/chrome/renderer/resources/extensions/page_action_custom_bindings.js b/chrome/renderer/resources/extensions/page_action_custom_bindings.js
index 6b189cc1..572187f 100644
--- a/chrome/renderer/resources/extensions/page_action_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/page_action_custom_bindings.js
@@ -4,19 +4,22 @@
 
 // Custom binding for the pageAction API.
 
-var binding = require('binding').Binding.create('pageAction');
-
+var binding = apiBridge || require('binding').Binding.create('pageAction');
 var setIcon = require('setIcon').setIcon;
-var sendRequest = require('sendRequest').sendRequest;
+var sendRequest = bindingUtil ?
+    $Function.bind(bindingUtil.sendRequest, bindingUtil) :
+    require('sendRequest').sendRequest;
 
 binding.registerCustomHook(function(bindingsAPI) {
   var apiFunctions = bindingsAPI.apiFunctions;
 
   apiFunctions.setHandleRequest('setIcon', function(details, callback) {
-    setIcon(details, function(args) {
-      sendRequest(this.name, [args, callback], this.definition.parameters);
-    }.bind(this));
+    setIcon(details, $Function.bind(function(args) {
+      sendRequest('pageAction.setIcon', [args, callback],
+                  bindingUtil ? undefined : this.definition.parameters);
+    }, this));
   });
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/chrome/renderer/resources/extensions/web_view/chrome_web_view.js b/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
index 0080e96..f025f3e 100644
--- a/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
+++ b/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
@@ -5,7 +5,9 @@
 // This module implements chrome-specific <webview> API.
 // See web_view_api_methods.js for details.
 
-var ChromeWebView = require('chromeWebViewInternal').ChromeWebView;
+var ChromeWebView = getInternalApi ?
+    getInternalApi('chromeWebViewInternal') :
+    require('chromeWebViewInternal').ChromeWebView;
 var ChromeWebViewSchema =
     requireNative('schema_registry').GetSchema('chromeWebViewInternal');
 var CreateEvent = require('guestViewEvents').CreateEvent;
diff --git a/chrome/renderer/resources/extensions/web_view/chrome_web_view_internal_custom_bindings.js b/chrome/renderer/resources/extensions/web_view/chrome_web_view_internal_custom_bindings.js
index 79bf906f..3cc2e3d 100644
--- a/chrome/renderer/resources/extensions/web_view/chrome_web_view_internal_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/web_view/chrome_web_view_internal_custom_bindings.js
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-var binding = require('binding').Binding.create('chromeWebViewInternal');
+var binding = apiBridge ||
+              require('binding').Binding.create('chromeWebViewInternal');
 var contextMenusHandlers = require('contextMenusHandlers');
 
 binding.registerCustomHook(function(bindingsAPI) {
@@ -21,7 +22,7 @@
 
   apiFunctions.setHandleRequest(
       'contextMenusRemoveAll', handlers.requestHandlers.removeAll);
-
 });
 
-exports.$set('ChromeWebView', binding.generate());
+if (!apiBridge)
+  exports.$set('ChromeWebView', binding.generate());
diff --git a/chrome/test/data/webui/settings/fingerprint_browsertest_chromeos.js b/chrome/test/data/webui/settings/fingerprint_browsertest_chromeos.js
index 3ef38c3f..8a42a3a 100644
--- a/chrome/test/data/webui/settings/fingerprint_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/fingerprint_browsertest_chromeos.js
@@ -120,6 +120,13 @@
     return {model: {index: index, item: opt_label || ''}};
   }
 
+  function openDialog() {
+    MockInteractions.tap(fingerprintList.$$('.action-button'));
+    Polymer.dom.flush();
+    dialog = fingerprintList.$$('settings-setup-fingerprint-dialog');
+    addAnotherButton = dialog.$$('#addAnotherButton');
+  }
+
   /**
    * @param {!Element} element
    */
@@ -134,8 +141,6 @@
     PolymerTest.clearBody();
     fingerprintList = document.createElement('settings-fingerprint-list');
     document.body.appendChild(fingerprintList);
-    dialog = fingerprintList.$.setupFingerprint;
-    addAnotherButton = dialog.$.addAnotherButton;
     Polymer.dom.flush();
     return Promise.all([
         browserProxy.whenCalled('startAuthentication'),
@@ -148,10 +153,9 @@
   // Verify running through the enroll session workflow
   // (settings-setup-fingerprint-dialog) works as expected.
   test('EnrollingFingerprint', function() {
-    assertFalse(dialog.$.dialog.open);
-    MockInteractions.tap(fingerprintList.$$('.action-button'));
+    openDialog();
     return browserProxy.whenCalled('startEnroll').then(function() {
-      assertTrue(dialog.$.dialog.open);
+      assertTrue(dialog.$$('#dialog').open);
       assertEquals(0, dialog.receivedScanCount_);
       assertEquals(settings.FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, false);
@@ -163,17 +167,17 @@
       browserProxy.scanReceived(settings.FingerprintResultType.TOO_FAST, false);
       assertEquals(1, dialog.receivedScanCount_);
       assertEquals('visible',
-          window.getComputedStyle(dialog.$.problemDiv).visibility);
+          window.getComputedStyle(dialog.$$('#problemDiv')).visibility);
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, false);
       assertEquals('hidden',
-          window.getComputedStyle(dialog.$.problemDiv).visibility);
+          window.getComputedStyle(dialog.$$('#problemDiv')).visibility);
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, false);
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, true);
       assertEquals(settings.FingerprintSetupStep.READY, dialog.step_);
 
       // Verify that by tapping the continue button we should exit the dialog
       // and the fingerprint list should have one fingerprint registered.
-      MockInteractions.tap(dialog.$.closeButton);
+      MockInteractions.tap(dialog.$$('#closeButton'));
       return PolymerTest.flushTasks().then(function() {
         Promise.all([
              browserProxy.whenCalled('startAuthentication'),
@@ -188,18 +192,17 @@
   // Verify enrolling a fingerprint, then enrolling another without closing the
   // dialog works as intended.
   test('EnrollingAnotherFingerprint', function() {
-    assertFalse(dialog.$.dialog.open);
-    MockInteractions.tap(fingerprintList.$$('.action-button'));
+    openDialog();
     return browserProxy.whenCalled('startEnroll').then(function() {
       browserProxy.resetResolver('startEnroll');
 
-      assertTrue(dialog.$.dialog.open);
+      assertTrue(dialog.$$('#dialog').open);
       assertEquals(0, dialog.receivedScanCount_);
       assertFalse(isVisible(addAnotherButton));
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, true);
       assertEquals(settings.FingerprintSetupStep.READY, dialog.step_);
 
-      assertTrue(dialog.$.dialog.open);
+      assertTrue(dialog.$$('#dialog').open);
       assertTrue(isVisible(addAnotherButton));
       MockInteractions.tap(addAnotherButton);
 
@@ -211,13 +214,13 @@
     }).then(function() {
       browserProxy.resetResolver('getFingerprintsList');
 
-      assertTrue(dialog.$.dialog.open);
+      assertTrue(dialog.$$('#dialog').open);
       assertFalse(isVisible(addAnotherButton));
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, true);
 
       // Verify that by tapping the continue button we should exit the dialog
       // and the fingerprint list should have two fingerprints registered.
-      MockInteractions.tap(dialog.$.closeButton);
+      MockInteractions.tap(dialog.$$('#closeButton'));
       return browserProxy.whenCalled('getFingerprintsList');
     }).then(function() {
        assertEquals(2, fingerprintList.fingerprints_.length);
@@ -225,10 +228,9 @@
   });
 
   test('CancelEnrollingFingerprint', function() {
-    assertFalse(dialog.$.dialog.open);
-    MockInteractions.tap(fingerprintList.$$('.action-button'));
+    openDialog();
     return browserProxy.whenCalled('startEnroll').then(function() {
-      assertTrue(dialog.$.dialog.open);
+      assertTrue(dialog.$$('#dialog').open);
       assertEquals(0, dialog.receivedScanCount_);
       assertEquals(settings.FingerprintSetupStep.LOCATE_SCANNER, dialog.step_);
       browserProxy.scanReceived(settings.FingerprintResultType.SUCCESS, false);
@@ -237,7 +239,7 @@
 
       // Verify that by tapping the exit button we should exit the dialog
       // and the fingerprint list should have zero fingerprints registered.
-      MockInteractions.tap(dialog.$.closeButton);
+      MockInteractions.tap(dialog.$$('#closeButton'));
       return Promise.all([
           browserProxy.whenCalled('cancelCurrentEnroll'),
           browserProxy.whenCalled('startAuthentication')]);
diff --git a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
index 9557b9d..4b6864f6 100644
--- a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
@@ -305,8 +305,9 @@
 
         Polymer.dom.flush();
         MockInteractions.tap(getFromElement('#setupPinButton'));
+        Polymer.dom.flush();
         var setupPinDialog = getFromElement('#setupPin');
-        assertTrue(setupPinDialog.$.dialog.open);
+        assertTrue(setupPinDialog.$$('#dialog').open);
         assertEquals(1, fakeUma.getHistogramValue(
             LockScreenProgress.CHOOSE_PIN_OR_PASSWORD));
       });
@@ -337,8 +338,6 @@
         document.body.appendChild(element);
         Polymer.dom.flush();
 
-        element.open();
-
         titleDiv = getFromElement('div[class="title"]');
         problemDiv = getFromElement('#problemDiv');
         pinKeyboard = getFromElement('pin-keyboard');
@@ -448,7 +447,7 @@
       // Hitting cancel at the setup step dismisses the dialog.
       test('HittingBackButtonResetsState', function() {
         MockInteractions.tap(backButton);
-        assertFalse(element.$.dialog.open);
+        assertFalse(element.$$('#dialog').open);
       });
 
       // Hitting cancel at the confirm step dismisses the dialog.
@@ -456,7 +455,7 @@
         pinKeyboard.value = '1111';
         MockInteractions.tap(continueButton);
         MockInteractions.tap(backButton);
-        assertFalse(element.$.dialog.open);
+        assertFalse(element.$$('#dialog').open);
       });
 
       // User has to re-enter PIN for confirm step.
diff --git a/chrome/test/data/webui/settings/site_details_permission_tests.js b/chrome/test/data/webui/settings/site_details_permission_tests.js
index 309f555..58a654d 100644
--- a/chrome/test/data/webui/settings/site_details_permission_tests.js
+++ b/chrome/test/data/webui/settings/site_details_permission_tests.js
@@ -48,6 +48,11 @@
     settings.SiteSettingsPrefsBrowserProxyImpl.instance_ = browserProxy;
     PolymerTest.clearBody();
     testElement = document.createElement('site-details-permission');
+
+    // Set the camera icon on <site-details-permission> manually to avoid
+    // failures on undefined icons during teardown in PolymerTest.testIronIcons.
+    // In practice, this is done from the parent.
+    testElement.icon = 'settings:videocam';
     document.body.appendChild(testElement);
   });
 
@@ -77,19 +82,6 @@
         });
   };
 
-  test('empty state', function() {
-    browserProxy.setPrefs(prefsEmpty);
-    testElement.category = settings.ContentSettingsTypes.CAMERA;
-    testElement.site = {
-      origin: 'http://www.google.com',
-      embeddingOrigin: '',
-    };
-
-    return browserProxy.whenCalled('getExceptionList').then(function() {
-      assertTrue(testElement.$.details.hidden);
-    });
-  });
-
   test('camera category', function() {
     var origin = 'https://www.example.com';
     browserProxy.setPrefs(prefs);
@@ -155,25 +147,4 @@
               origin, settings.PermissionValues.BLOCK);
         });
   });
-
-  test('disappear on empty', function() {
-    var origin = 'https://www.example.com';
-    browserProxy.setPrefs(prefs);
-    testElement.category = settings.ContentSettingsTypes.CAMERA;
-    testElement.site = {
-      origin: origin,
-      embeddingOrigin: '',
-    };
-
-    return browserProxy.whenCalled('getExceptionList')
-        .then(function() {
-          assertFalse(testElement.$.details.hidden);
-
-          browserProxy.setPrefs(prefsEmpty);
-          return browserProxy.whenCalled('getExceptionList');
-        })
-        .then(function() {
-          assertTrue(testElement.$.details.hidden);
-        });
-  });
 });
diff --git a/chrome/test/data/webui/settings/site_details_tests.js b/chrome/test/data/webui/settings/site_details_tests.js
index 732be78..95517a1 100644
--- a/chrome/test/data/webui/settings/site_details_tests.js
+++ b/chrome/test/data/webui/settings/site_details_tests.js
@@ -123,55 +123,6 @@
     document.body.appendChild(testElement);
   });
 
-  test('empty state', function() {
-    var category = settings.ContentSettingsTypes.NOTIFICATIONS;
-    var site = {
-      origin: 'http://www.google.com',
-      displayName: 'http://www.google.com',
-      embeddingOrigin: '',
-    };
-    browserProxy.setPrefs(prefsEmpty);
-    testElement.category = category;
-    testElement.site = site
-
-    // expect usage to not be rendered
-    assertFalse(!!testElement.$$('#usage'));
-
-    // TODO(finnur): Check for the Permission heading hiding when no
-    // permissions are showing.
-
-    var msg = 'No category should be showing, height';
-    assertEquals(0, testElement.$.camera.offsetHeight, msg);
-    assertEquals(0, testElement.$.cookies.offsetHeight, msg);
-    assertEquals(0, testElement.$.geolocation.offsetHeight, msg);
-    assertEquals(0, testElement.$.javascript.offsetHeight, msg);
-    assertEquals(0, testElement.$.mic.offsetHeight, msg);
-    assertEquals(0, testElement.$.notification.offsetHeight, msg);
-    assertEquals(0, testElement.$.popups.offsetHeight, msg);
-  });
-
-  test('all categories visible', function() {
-    var category = settings.ContentSettingsTypes.NOTIFICATIONS;
-    var site = {
-      origin: 'https://foo-allow.com:443',
-      displayName: 'https://foo-allow.com:443',
-      embeddingOrigin: '',
-    };
-
-    browserProxy.setPrefs(prefs);
-    testElement.category = category;
-    testElement.site = site;
-
-    var msg = 'All categories should be showing';
-    assertFalse(testElement.$.camera.hidden, msg);
-    assertFalse(testElement.$.cookies.hidden, msg);
-    assertFalse(testElement.$.geolocation.hidden, msg);
-    assertFalse(testElement.$.javascript.hidden, msg);
-    assertFalse(testElement.$.mic.hidden, msg);
-    assertFalse(testElement.$.notification.hidden, msg);
-    assertFalse(testElement.$.popups.hidden, msg);
-  });
-
   test('usage heading shows on storage available', function() {
     // Remove the current website-usage-private-api element.
     var parent = testElement.$.usageApi.parentNode;
diff --git a/components/component_updater/default_component_installer.cc b/components/component_updater/default_component_installer.cc
index 62842079..02e7f4e 100644
--- a/components/component_updater/default_component_installer.cc
+++ b/components/component_updater/default_component_installer.cc
@@ -41,8 +41,12 @@
 
 }  // namespace
 
-ComponentInstallerTraits::~ComponentInstallerTraits() {
-}
+ComponentInstallerTraits::~ComponentInstallerTraits() {}
+
+DefaultComponentInstaller::RegistrationInfo::RegistrationInfo()
+    : version(kNullVersion) {}
+
+DefaultComponentInstaller::RegistrationInfo::~RegistrationInfo() = default;
 
 DefaultComponentInstaller::DefaultComponentInstaller(
     std::unique_ptr<ComponentInstallerTraits> installer_traits)
@@ -65,12 +69,14 @@
                << "has no installer traits.";
     return;
   }
+
+  auto registration_info = base::MakeRefCounted<RegistrationInfo>();
   task_runner_->PostTaskAndReply(
       FROM_HERE,
-      base::Bind(&DefaultComponentInstaller::StartRegistration,
-                 this, cus),
-      base::Bind(&DefaultComponentInstaller::FinishRegistration,
-                 this, cus, callback));
+      base::Bind(&DefaultComponentInstaller::StartRegistration, this,
+                 registration_info, cus),
+      base::Bind(&DefaultComponentInstaller::FinishRegistration, this,
+                 registration_info, cus, callback));
 }
 
 void DefaultComponentInstaller::OnUpdateError(int error) {
@@ -147,11 +153,10 @@
 
   current_version_ = version;
   current_install_dir_ = install_path;
+
   // TODO(ddorwin): Change parameter to std::unique_ptr<base::DictionaryValue>
   // so we can avoid this DeepCopy.
-  current_manifest_.reset(manifest.DeepCopy());
-  std::unique_ptr<base::DictionaryValue> manifest_copy(
-      current_manifest_->DeepCopy());
+  std::unique_ptr<base::DictionaryValue> manifest_copy(manifest.DeepCopy());
   main_task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&DefaultComponentInstaller::ComponentReady,
@@ -177,7 +182,8 @@
 }
 
 bool DefaultComponentInstaller::FindPreinstallation(
-    const base::FilePath& root) {
+    const base::FilePath& root,
+    const scoped_refptr<RegistrationInfo>& registration_info) {
   base::FilePath path = root.Append(installer_traits_->GetRelativeInstallDir());
   if (!base::PathExists(path)) {
     DVLOG(1) << "Relative install dir does not exist: " << path.MaybeAsASCII();
@@ -212,13 +218,16 @@
           << " at " << path.MaybeAsASCII() << " with version " << version
           << ".";
 
-  current_install_dir_ = path;
-  current_manifest_ = std::move(manifest);
-  current_version_ = version;
+  registration_info->install_dir = path;
+  registration_info->version = version;
+  registration_info->manifest = std::move(manifest);
+
   return true;
 }
 
-void DefaultComponentInstaller::StartRegistration(ComponentUpdateService* cus) {
+void DefaultComponentInstaller::StartRegistration(
+    const scoped_refptr<RegistrationInfo>& registration_info,
+    ComponentUpdateService* cus) {
   VLOG(1) << __func__ << " for " << installer_traits_->GetName();
   DCHECK(task_runner_.get());
   DCHECK(task_runner_->RunsTasksOnCurrentThread());
@@ -228,16 +237,17 @@
   // First check for an installation set up alongside Chrome itself.
   base::FilePath root;
   if (PathService::Get(DIR_COMPONENT_PREINSTALLED, &root) &&
-      FindPreinstallation(root)) {
-    latest_version = current_version_;
+      FindPreinstallation(root, registration_info)) {
+    latest_version = registration_info->version;
   }
 
   // If there is a distinct alternate root, check there as well, and override
   // anything found in the basic root.
   base::FilePath root_alternate;
   if (PathService::Get(DIR_COMPONENT_PREINSTALLED_ALT, &root_alternate) &&
-      root != root_alternate && FindPreinstallation(root_alternate)) {
-    latest_version = current_version_;
+      root != root_alternate &&
+      FindPreinstallation(root_alternate, registration_info)) {
+    latest_version = registration_info->version;
   }
 
   // Then check for a higher-versioned user-wide installation.
@@ -302,13 +312,11 @@
   }
 
   if (latest_manifest) {
-    current_version_ = latest_version;
-    current_manifest_ = std::move(latest_manifest);
-    current_install_dir_ = latest_path;
-    // TODO(ddorwin): Remove these members and pass them directly to
-    // FinishRegistration().
+    registration_info->version = latest_version;
+    registration_info->manifest = std::move(latest_manifest);
+    registration_info->install_dir = latest_path;
     base::ReadFileToString(latest_path.AppendASCII("manifest.fingerprint"),
-                           &current_fingerprint_);
+                           &registration_info->fingerprint);
   }
 
   // Remove older versions of the component. None should be in use during
@@ -352,11 +360,16 @@
 }
 
 void DefaultComponentInstaller::FinishRegistration(
+    const scoped_refptr<RegistrationInfo>& registration_info,
     ComponentUpdateService* cus,
     const base::Closure& callback) {
   VLOG(1) << __func__ << " for " << installer_traits_->GetName();
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  current_install_dir_ = registration_info->install_dir;
+  current_version_ = registration_info->version;
+  current_fingerprint_ = registration_info->fingerprint;
+
   update_client::CrxComponent crx;
   installer_traits_->GetHash(&crx.pk_hash);
   crx.installer = this;
@@ -379,14 +392,12 @@
   if (!callback.is_null())
     callback.Run();
 
-  if (!current_manifest_) {
+  if (!registration_info->manifest) {
     DVLOG(1) << "No component found for " << installer_traits_->GetName();
     return;
   }
 
-  std::unique_ptr<base::DictionaryValue> manifest_copy(
-      current_manifest_->DeepCopy());
-  ComponentReady(std::move(manifest_copy));
+  ComponentReady(std::move(registration_info->manifest));
 }
 
 void DefaultComponentInstaller::ComponentReady(
diff --git a/components/component_updater/default_component_installer.h b/components/component_updater/default_component_installer.h
index 61e6c56..5ca9782 100644
--- a/components/component_updater/default_component_installer.h
+++ b/components/component_updater/default_component_installer.h
@@ -125,27 +125,49 @@
   bool Uninstall() override;
 
  private:
+  struct RegistrationInfo : base::RefCountedThreadSafe<RegistrationInfo> {
+    RegistrationInfo();
+
+    base::FilePath install_dir;
+    base::Version version;
+    std::string fingerprint;
+    std::unique_ptr<base::DictionaryValue> manifest;
+
+   private:
+    friend class base::RefCountedThreadSafe<RegistrationInfo>;
+
+    ~RegistrationInfo();
+
+    DISALLOW_COPY_AND_ASSIGN(RegistrationInfo);
+  };
+
   ~DefaultComponentInstaller() override;
 
   // If there is a installation of the component set up alongside Chrome's
   // files (as opposed to in the user data directory), sets current_* to the
   // values associated with that installation and returns true; otherwise,
   // returns false.
-  bool FindPreinstallation(const base::FilePath& root);
+  bool FindPreinstallation(
+      const base::FilePath& root,
+      const scoped_refptr<RegistrationInfo>& registration_info);
   update_client::CrxInstaller::Result InstallHelper(
       const base::DictionaryValue& manifest,
       const base::FilePath& unpack_path,
       const base::FilePath& install_path);
-  void StartRegistration(ComponentUpdateService* cus);
-  void FinishRegistration(ComponentUpdateService* cus,
-                          const base::Closure& callback);
+  void StartRegistration(
+      const scoped_refptr<RegistrationInfo>& registration_info,
+      ComponentUpdateService* cus);
+  void FinishRegistration(
+      const scoped_refptr<RegistrationInfo>& registration_info,
+      ComponentUpdateService* cus,
+      const base::Closure& callback);
   void ComponentReady(std::unique_ptr<base::DictionaryValue> manifest);
   void UninstallOnTaskRunner();
 
   base::FilePath current_install_dir_;
   base::Version current_version_;
   std::string current_fingerprint_;
-  std::unique_ptr<base::DictionaryValue> current_manifest_;
+
   std::unique_ptr<ComponentInstallerTraits> installer_traits_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/components/component_updater/default_component_installer_unittest.cc b/components/component_updater/default_component_installer_unittest.cc
index d012be1..52fe601e 100644
--- a/components/component_updater/default_component_installer_unittest.cc
+++ b/components/component_updater/default_component_installer_unittest.cc
@@ -244,6 +244,8 @@
     base::Closure quit_closure_;
   };
 
+  base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
+
   const std::string id("jebgalgnebhfojomionfpkfelancnnkf");
 
   // Quit after one update check has been fired.
diff --git a/components/safe_browsing/base_blocking_page.cc b/components/safe_browsing/base_blocking_page.cc
index 52852688..184a1b2 100644
--- a/components/safe_browsing/base_blocking_page.cc
+++ b/components/safe_browsing/base_blocking_page.cc
@@ -79,7 +79,6 @@
       false,                 // is_extended_reporting
       false,                 // is_scout
       false,                 // kSafeBrowsingProceedAnywayDisabled
-      true,                  // is_resource_cancellable
       "cpn_safe_browsing");  // help_center_article_link
 }
 
@@ -265,6 +264,8 @@
       return "from_device_v4";
     case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION:
       return "from_client_side_detection";
+    case safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE:
+      return "from_password_protection_service";
     case safe_browsing::ThreatSource::UNKNOWN:
       break;
   }
@@ -288,7 +289,8 @@
       harmful = true;
     } else {
       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
-             threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
+             threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
+             threat_type == SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL);
     }
   }
 
diff --git a/components/safe_browsing/base_ping_manager.cc b/components/safe_browsing/base_ping_manager.cc
index 30fdf1c..d397c2a 100644
--- a/components/safe_browsing/base_ping_manager.cc
+++ b/components/safe_browsing/base_ping_manager.cc
@@ -201,7 +201,9 @@
          hit_report.threat_type == SB_THREAT_TYPE_URL_UNWANTED ||
          hit_report.threat_type == SB_THREAT_TYPE_BINARY_MALWARE_URL ||
          hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
-         hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
+         hit_report.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL ||
+         hit_report.threat_type ==
+             SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL);
   std::string url = ProtocolManagerHelper::ComposeUrl(
       url_prefix_, "report", client_name_, version_, std::string(),
       hit_report.extended_reporting_level);
@@ -226,6 +228,9 @@
     case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
       threat_list = "malcsdhit";
       break;
+    case SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL:
+      threat_list = "phishpphit";
+      break;
     default:
       NOTREACHED();
   }
@@ -247,6 +252,9 @@
     case safe_browsing::ThreatSource::CLIENT_SIDE_DETECTION:
       threat_source = "csd";
       break;
+    case safe_browsing::ThreatSource::PASSWORD_PROTECTION_SERVICE:
+      threat_source = "pps";
+      break;
     case safe_browsing::ThreatSource::UNKNOWN:
       NOTREACHED();
   }
diff --git a/components/safe_browsing/base_resource_throttle.cc b/components/safe_browsing/base_resource_throttle.cc
index 87a8812..ff2ebeb 100644
--- a/components/safe_browsing/base_resource_throttle.cc
+++ b/components/safe_browsing/base_resource_throttle.cc
@@ -82,19 +82,6 @@
           net::NetLogWithSource::Make(request->net_log().net_log(),
                                       NetLogSourceType::SAFE_BROWSING)) {}
 
-// static
-BaseResourceThrottle* BaseResourceThrottle::MaybeCreate(
-    net::URLRequest* request,
-    content::ResourceType resource_type,
-    scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
-    scoped_refptr<BaseUIManager> ui_manager) {
-  if (database_manager->IsSupported()) {
-    return new BaseResourceThrottle(request, resource_type,
-                                    database_manager, ui_manager);
-  }
-  return nullptr;
-}
-
 BaseResourceThrottle::~BaseResourceThrottle() {
   if (defer_state_ != DEFERRED_NONE) {
     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr);
diff --git a/components/safe_browsing/base_resource_throttle.h b/components/safe_browsing/base_resource_throttle.h
index 1fe92f3..154913f 100644
--- a/components/safe_browsing/base_resource_throttle.h
+++ b/components/safe_browsing/base_resource_throttle.h
@@ -50,15 +50,6 @@
       public SafeBrowsingDatabaseManager::Client,
       public base::SupportsWeakPtr<BaseResourceThrottle> {
  public:
-  // Construct a BaseResourceThrottle, or return nullptr if we
-  // cannot access the safe browsing API on Android
-  static BaseResourceThrottle* MaybeCreate(
-      net::URLRequest* request,
-      content::ResourceType resource_type,
-      scoped_refptr<SafeBrowsingDatabaseManager>
-          database_manager,
-      scoped_refptr<BaseUIManager> ui_manager);
-
   // content::ResourceThrottle implementation (called on IO thread):
   void WillStartRequest(bool* defer) override;
   void WillRedirectRequest(const net::RedirectInfo& redirect_info,
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc
index 0e6cfb8c..4a75c4c 100644
--- a/components/safe_browsing/browser/threat_details.cc
+++ b/components/safe_browsing/browser/threat_details.cc
@@ -76,6 +76,8 @@
       return ClientSafeBrowsingReportRequest::CLIENT_SIDE_PHISHING_URL;
     case SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL:
       return ClientSafeBrowsingReportRequest::CLIENT_SIDE_MALWARE_URL;
+    case SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL:
+      return ClientSafeBrowsingReportRequest::PASSWORD_PROTECTION_PHISHING_URL;
     default:  // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails.
       NOTREACHED() << "We should not send report for threat type "
                    << threat_type;
@@ -359,6 +361,9 @@
     report_->set_type(GetReportTypeFromSBThreatType(resource_.threat_type));
   }
 
+  if (resource_.threat_type == SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL)
+    report_->set_token(resource_.token);
+
   GURL referrer_url;
   NavigationEntry* nav_entry = resource_.GetNavigationEntryForResource();
   if (nav_entry) {
diff --git a/components/safe_browsing/csd.proto b/components/safe_browsing/csd.proto
index 7bb5920..8d8b415 100644
--- a/components/safe_browsing/csd.proto
+++ b/components/safe_browsing/csd.proto
@@ -262,6 +262,10 @@
 
   // Deprecated.
   optional bool DEPRECATED_cache_expression_exact_match = 4 [deprecated = true];
+
+  // A token unique to each request which correlates response and post-warning
+  // actions.
+  optional bytes verdict_token = 5;
 }
 
 message ClientMalwareResponse {
@@ -904,6 +908,7 @@
     DANGEROUS_DOWNLOAD_RECOVERY = 6;
     DANGEROUS_DOWNLOAD_WARNING = 7;
     DANGEROUS_DOWNLOAD_BY_API = 10;
+    PASSWORD_PROTECTION_PHISHING_URL = 12;
   }
 
   message HTTPHeader {
@@ -984,9 +989,10 @@
   // Whether user visited this origin before.
   optional bool repeat_visit = 9;
 
-  // The same token in ClientDownloadResponse. This field is only set if its
-  // report type is DANGEROUS_DOWNLOAD_RECOVERY, DANGEROUS_DOWNLOAD_WARNING or
-  // DANGEROUS_DOWNLOAD_BY_API.
+  // The same token in ClientDownloadResponse or LoginReputationClientResponse.
+  // This field is only set if its report type is DANGEROUS_DOWNLOAD_RECOVERY,
+  // DANGEROUS_DOWNLOAD_WARNING, DANGEROUS_DOWNLOAD_BY_API or
+  // PASSWORD_PROTECTION_PHISHING_URL.
   optional bytes token = 15;
 }
 
diff --git a/components/safe_browsing/password_protection/password_protection_request.cc b/components/safe_browsing/password_protection/password_protection_request.cc
index 18207083..0f74a1e 100644
--- a/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/password_protection/password_protection_request.cc
@@ -247,7 +247,7 @@
                               outcome, PasswordProtectionService::MAX_OUTCOME);
   }
 
-  if (response) {
+  if (outcome == PasswordProtectionService::SUCCEEDED && response) {
     switch (request_type_) {
       case LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE:
         UMA_HISTOGRAM_ENUMERATION(
@@ -267,7 +267,9 @@
   }
 
   DCHECK(password_protection_service_);
-  password_protection_service_->RequestFinished(this, std::move(response));
+  password_protection_service_->RequestFinished(
+      this, outcome == PasswordProtectionService::RESPONSE_ALREADY_CACHED,
+      std::move(response));
 }
 
 void PasswordProtectionRequest::Cancel(bool timed_out) {
diff --git a/components/safe_browsing/password_protection/password_protection_request.h b/components/safe_browsing/password_protection/password_protection_request.h
index 89fcf77..2bb4499 100644
--- a/components/safe_browsing/password_protection/password_protection_request.h
+++ b/components/safe_browsing/password_protection/password_protection_request.h
@@ -67,7 +67,15 @@
 
   GURL main_frame_url() const { return main_frame_url_; }
 
-  LoginReputationClientRequest* request_proto() { return request_proto_.get(); }
+  const LoginReputationClientRequest* request_proto() const {
+    return request_proto_.get();
+  }
+
+  content::WebContents* web_contents() const { return web_contents_; }
+
+  LoginReputationClientRequest::TriggerType request_type() const {
+    return request_type_;
+  }
 
  private:
   friend class base::RefCountedThreadSafe<PasswordProtectionRequest>;
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index bdc9cff8..a16ef3af 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -74,6 +74,9 @@
 const base::Feature kProtectedPasswordEntryPinging{
     "ProtectedPasswordEntryPinging", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kPasswordProtectionInterstitial{
+    "PasswordProtectionInterstitial", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const char kPasswordOnFocusRequestOutcomeHistogramName[] =
     "PasswordProtection.RequestOutcome.PasswordFieldOnFocus";
 const char kPasswordEntryRequestOutcomeHistogramName[] =
@@ -319,12 +322,26 @@
 
 void PasswordProtectionService::RequestFinished(
     PasswordProtectionRequest* request,
+    bool already_cached,
     std::unique_ptr<LoginReputationClientResponse> response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   DCHECK(request);
-  if (response)
-    CacheVerdict(request->main_frame_url(), response.get(), base::Time::Now());
+
+  if (response) {
+    if (!already_cached) {
+      CacheVerdict(request->main_frame_url(), response.get(),
+                   base::Time::Now());
+    }
+
+    if (request->request_type() ==
+            LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE &&
+        response->verdict_type() == LoginReputationClientResponse::PHISHING &&
+        base::FeatureList::IsEnabled(kPasswordProtectionInterstitial)) {
+      ShowPhishingInterstitial(request->main_frame_url(),
+                               response->verdict_token(),
+                               request->web_contents());
+    }
+  }
 
   // Finished processing this request. Remove it from pending list.
   for (auto it = requests_.begin(); it != requests_.end(); it++) {
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index 7060bb20..4800ae9 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -39,6 +39,7 @@
 
 extern const base::Feature kPasswordFieldOnFocusPinging;
 extern const base::Feature kProtectedPasswordEntryPinging;
+extern const base::Feature kPasswordProtectionInterstitial;
 extern const char kPasswordOnFocusRequestOutcomeHistogramName[];
 extern const char kPasswordEntryRequestOutcomeHistogramName[];
 
@@ -68,6 +69,7 @@
     URL_NOT_VALID_FOR_REPUTATION_COMPUTING = 14,
     MAX_OUTCOME
   };
+
   PasswordProtectionService(
       const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
       scoped_refptr<net::URLRequestContextGetter> request_context_getter,
@@ -89,9 +91,9 @@
 
   // Stores |verdict| in |settings| based on |url|, |verdict| and
   // |receive_time|.
-  void CacheVerdict(const GURL& url,
-                    LoginReputationClientResponse* verdict,
-                    const base::Time& receive_time);
+  virtual void CacheVerdict(const GURL& url,
+                            LoginReputationClientResponse* verdict,
+                            const base::Time& receive_time);
 
   // Removes all the expired verdicts from cache.
   void CleanUpExpiredVerdicts();
@@ -141,6 +143,7 @@
   // itself from |requests_|.
   virtual void RequestFinished(
       PasswordProtectionRequest* request,
+      bool already_cached,
       std::unique_ptr<LoginReputationClientResponse> response);
 
   // Cancels all requests in |requests_|, empties it, and releases references to
@@ -181,6 +184,10 @@
 
   virtual bool IsHistorySyncEnabled() = 0;
 
+  virtual void ShowPhishingInterstitial(const GURL& phishing_url,
+                                        const std::string& token,
+                                        content::WebContents* web_contents) = 0;
+
   void CheckCsdWhitelistOnIOThread(const GURL& url, bool* check_result);
 
   HostContentSettingsMap* content_settings() const { return content_settings_; }
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 3deb72a..6169728 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -78,6 +78,7 @@
 
   void RequestFinished(
       PasswordProtectionRequest* request,
+      bool already_cached_unused,
       std::unique_ptr<LoginReputationClientResponse> response) override {
     latest_request_ = request;
     latest_response_ = std::move(response);
@@ -105,6 +106,10 @@
     return true;
   }
 
+  void ShowPhishingInterstitial(const GURL& phishing_url,
+                                const std::string& token,
+                                content::WebContents* web_contents) override {}
+
   bool IsHistorySyncEnabled() override { return false; }
 
   LoginReputationClientResponse* latest_response() {
@@ -115,7 +120,7 @@
 
   size_t GetPendingRequestsCount() { return requests_.size(); }
 
-  LoginReputationClientRequest* GetLatestRequestProto() {
+  const LoginReputationClientRequest* GetLatestRequestProto() {
     return latest_request_ ? latest_request_->request_proto() : nullptr;
   }
 
@@ -609,7 +614,7 @@
   request_->OnURLFetchComplete(&fetcher);
   base::RunLoop().RunUntilIdle();
 
-  LoginReputationClientRequest* actual_request =
+  const LoginReputationClientRequest* actual_request =
       password_protection_service_->GetLatestRequestProto();
   EXPECT_EQ(kTargetUrl, actual_request->page_url());
   EXPECT_EQ(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
@@ -638,7 +643,7 @@
   request_->OnURLFetchComplete(&fetcher);
   base::RunLoop().RunUntilIdle();
 
-  LoginReputationClientRequest* actual_request =
+  const LoginReputationClientRequest* actual_request =
       password_protection_service_->GetLatestRequestProto();
   EXPECT_EQ(kTargetUrl, actual_request->page_url());
   EXPECT_EQ(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
diff --git a/components/safe_browsing_db/hit_report.h b/components/safe_browsing_db/hit_report.h
index 4fecc44c..9df6a90 100644
--- a/components/safe_browsing_db/hit_report.h
+++ b/components/safe_browsing_db/hit_report.h
@@ -21,6 +21,7 @@
   LOCAL_PVER4,            // From V4LocalDatabaseManager, protocol v4
   REMOTE,                 // From RemoteSafeBrowsingDatabaseManager
   CLIENT_SIDE_DETECTION,  // From ClientSideDetectionHost
+  PASSWORD_PROTECTION_SERVICE,  // From PasswordProtectionService
 };
 
 // Data to report about the contents of a particular threat (malware, phishing,
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h
index 1619fd5..54b5225 100644
--- a/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -118,6 +118,9 @@
 
   // CSD Phishing whitelist.  This "threat" means a URL matched the whitelist.
   SB_THREAT_TYPE_CSD_WHITELIST,
+
+  // Url detected by password protection service.
+  SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL,
 };
 
 // The information required to uniquely identify each list the client is
diff --git a/components/security_interstitials/content/unsafe_resource.cc b/components/security_interstitials/content/unsafe_resource.cc
index c6204cb..e8dd701 100644
--- a/components/security_interstitials/content/unsafe_resource.cc
+++ b/components/security_interstitials/content/unsafe_resource.cc
@@ -40,10 +40,13 @@
   if (is_subresource)
     return false;
 
-  // Client-side phishing detection interstitials never block the main frame
-  // load, since they happen after the page is finished loading.
+  // Client-side phishing/malware detection and password protection phishing
+  // interstitials never block the main frame load, since they happen after the
+  // page is finished loading.
   if (threat_type == safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL ||
-      threat_type == safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
+      threat_type == safe_browsing::SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL ||
+      threat_type ==
+          safe_browsing::SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL) {
     return false;
   }
 
diff --git a/components/security_interstitials/content/unsafe_resource.h b/components/security_interstitials/content/unsafe_resource.h
index b26da33d..bb10b65b 100644
--- a/components/security_interstitials/content/unsafe_resource.h
+++ b/components/security_interstitials/content/unsafe_resource.h
@@ -67,6 +67,9 @@
   scoped_refptr<base::SingleThreadTaskRunner> callback_thread;
   base::Callback<content::WebContents*(void)> web_contents_getter;
   safe_browsing::ThreatSource threat_source;
+  // |token| field is only set if |threat_type| is
+  // SB_THREAT_TYPE_PASSWORD_PROTECTION_PHISHING_URL
+  std::string token;
 };
 
 }  // security_interstitials
diff --git a/components/security_interstitials/core/base_safe_browsing_error_ui.cc b/components/security_interstitials/core/base_safe_browsing_error_ui.cc
index 127f5bc..ad7c340 100644
--- a/components/security_interstitials/core/base_safe_browsing_error_ui.cc
+++ b/components/security_interstitials/core/base_safe_browsing_error_ui.cc
@@ -31,7 +31,6 @@
     bool is_extended_reporting_enabled,
     bool is_scout_reporting_enabled,
     bool is_proceed_anyway_disabled,
-    bool is_resource_cancellable,
     const std::string& help_center_article_link)
     : is_main_frame_load_blocked(is_main_frame_load_blocked),
       is_extended_reporting_opt_in_allowed(
@@ -40,7 +39,6 @@
       is_extended_reporting_enabled(is_extended_reporting_enabled),
       is_scout_reporting_enabled(is_scout_reporting_enabled),
       is_proceed_anyway_disabled(is_proceed_anyway_disabled),
-      is_resource_cancellable(is_resource_cancellable),
       help_center_article_link(help_center_article_link) {}
 
 BaseSafeBrowsingErrorUI::SBErrorDisplayOptions::SBErrorDisplayOptions(
@@ -52,7 +50,6 @@
       is_extended_reporting_enabled(other.is_extended_reporting_enabled),
       is_scout_reporting_enabled(other.is_scout_reporting_enabled),
       is_proceed_anyway_disabled(other.is_proceed_anyway_disabled),
-      is_resource_cancellable(other.is_resource_cancellable),
       help_center_article_link(other.help_center_article_link) {}
 
 }  // security_interstitials
diff --git a/components/security_interstitials/core/base_safe_browsing_error_ui.h b/components/security_interstitials/core/base_safe_browsing_error_ui.h
index 6de0e41..1306fbdc 100644
--- a/components/security_interstitials/core/base_safe_browsing_error_ui.h
+++ b/components/security_interstitials/core/base_safe_browsing_error_ui.h
@@ -32,7 +32,6 @@
                           bool is_extended_reporting_enabled,
                           bool is_scout_reporting_enabled,
                           bool is_proceed_anyway_disabled,
-                          bool is_resource_cancellable,
                           const std::string& help_center_article_link);
 
     SBErrorDisplayOptions(const SBErrorDisplayOptions& other);
@@ -55,10 +54,6 @@
     // Indicates if kSafeBrowsingProceedAnywayDisabled preference is set.
     bool is_proceed_anyway_disabled;
 
-    // Indicates if "back to safety" should cancel the pending navigation or
-    // navigate back after it's committed.
-    bool is_resource_cancellable;
-
     // The p= query parameter used when visiting the Help Center. If this is
     // nullptr, then a default value will be used for the SafeBrowsing article.
     std::string help_center_article_link;
@@ -100,10 +95,6 @@
     return display_options_.is_proceed_anyway_disabled;
   }
 
-  bool is_resource_cancellable() const {
-    return display_options_.is_resource_cancellable;
-  }
-
   const std::string& get_help_center_article_link() const {
     return display_options_.help_center_article_link;
   }
diff --git a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
index b121190..12e67e3 100644
--- a/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
+++ b/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -130,7 +130,7 @@
       // User pressed on the button to return to safety.
       // Don't record the user action here because there are other ways of
       // triggering DontProceed, like clicking the back button.
-      if (is_resource_cancellable()) {
+      if (is_main_frame_load_blocked()) {
         // If the load is blocked, we want to close the interstitial and discard
         // the pending entry.
         controller()->GoBack();
diff --git a/content/browser/generic_sensor_browsertest.cc b/content/browser/generic_sensor_browsertest.cc
index 745cbfea..364e308 100644
--- a/content/browser/generic_sensor_browsertest.cc
+++ b/content/browser/generic_sensor_browsertest.cc
@@ -27,10 +27,11 @@
 
 class FakeAmbientLightSensor : public device::PlatformSensor {
  public:
-  FakeAmbientLightSensor(device::mojom::SensorType type,
-                         mojo::ScopedSharedBufferMapping mapping,
+  FakeAmbientLightSensor(mojo::ScopedSharedBufferMapping mapping,
                          device::PlatformSensorProvider* provider)
-      : PlatformSensor(type, std::move(mapping), provider) {}
+      : PlatformSensor(device::mojom::SensorType::AMBIENT_LIGHT,
+                       std::move(mapping),
+                       provider) {}
 
   device::mojom::ReportingMode GetReportingMode() override {
     return device::mojom::ReportingMode::ON_CHANGE;
@@ -46,7 +47,7 @@
     return true;
   }
 
-  void StopSensor() override{};
+  void StopSensor() override {};
 
  protected:
   ~FakeAmbientLightSensor() override = default;
@@ -55,9 +56,7 @@
     return true;
   }
   device::PlatformSensorConfiguration GetDefaultConfiguration() override {
-    device::PlatformSensorConfiguration default_configuration;
-    default_configuration.set_frequency(60);
-    return default_configuration;
+    return device::PlatformSensorConfiguration(60 /* frequency */);
   }
 };
 
@@ -78,7 +77,7 @@
     switch (type) {
       case device::mojom::SensorType::AMBIENT_LIGHT: {
         scoped_refptr<device::PlatformSensor> sensor =
-            new FakeAmbientLightSensor(type, std::move(mapping), this);
+            new FakeAmbientLightSensor(std::move(mapping), this);
         callback.Run(std::move(sensor));
         break;
       }
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index 1c8ae85..3ff8d94 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -151,12 +151,11 @@
   void SetUp() override {
     browser_context_.reset(new TestBrowserContext);
     InitializeResourceContext(browser_context_.get());
-    SetUpWithHelper(new EmbeddedWorkerTestHelper(base::FilePath()));
   }
 
-  void SetUpWithHelper(EmbeddedWorkerTestHelper* helper,
+  void SetUpWithHelper(std::unique_ptr<EmbeddedWorkerTestHelper> helper,
                        bool set_main_script_http_response_info = true) {
-    helper_.reset(helper);
+    helper_ = std::move(helper);
 
     registration_ = new ServiceWorkerRegistration(
         GURL("https://example.com/"), 1L, helper_->context()->AsWeakPtr());
@@ -366,6 +365,8 @@
 };
 
 TEST_F(ServiceWorkerURLRequestJobTest, Simple) {
+  SetUpWithHelper(base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath()));
+
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   TestRequest(200, "OK", std::string(), true /* expect_valid_ssl */);
 
@@ -385,6 +386,8 @@
 }
 
 TEST_F(ServiceWorkerURLRequestJobTest, CustomTimeout) {
+  SetUpWithHelper(base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath()));
+
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
 
   // Set mock clock on version_ to check timeout behavior.
@@ -429,11 +432,12 @@
   DISALLOW_COPY_AND_ASSIGN(ProviderDeleteHelper);
 };
 
+// Shouldn't crash if the ProviderHost is deleted prior to completion of the
+// fetch event.
 TEST_F(ServiceWorkerURLRequestJobTest, DeletedProviderHostOnFetchEvent) {
+  SetUpWithHelper(base::MakeUnique<ProviderDeleteHelper>());
+
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
-  // Shouldn't crash if the ProviderHost is deleted prior to completion of
-  // the fetch event.
-  SetUpWithHelper(new ProviderDeleteHelper);
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   TestRequest(500, "Service Worker Response Error", std::string(),
@@ -453,6 +457,8 @@
 }
 
 TEST_F(ServiceWorkerURLRequestJobTest, DeletedProviderHostBeforeFetchEvent) {
+  SetUpWithHelper(base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath()));
+
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
       GURL("https://example.com/foo.html"), net::DEFAULT_PRIORITY,
@@ -520,6 +526,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, BlobResponse) {
   ChromeBlobStorageContext* blob_storage_context =
       ChromeBlobStorageContext::GetFor(browser_context_.get());
+  // Wait for chrome_blob_storage_context to finish initializing.
+  base::RunLoop().RunUntilIdle();
+
   std::string expected_response;
   expected_response.reserve((sizeof(kTestData) - 1) * 1024);
   for (int i = 0; i < 1024; ++i) {
@@ -528,8 +537,8 @@
   }
   std::unique_ptr<storage::BlobDataHandle> blob_handle =
       blob_storage_context->context()->AddFinishedBlob(blob_data_.get());
-  SetUpWithHelper(
-      new BlobResponder(blob_handle->uuid(), expected_response.size()));
+  SetUpWithHelper(base::MakeUnique<BlobResponder>(blob_handle->uuid(),
+                                                  expected_response.size()));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   TestRequest(200, "OK", expected_response, true /* expect_valid_ssl */);
@@ -549,7 +558,8 @@
 }
 
 TEST_F(ServiceWorkerURLRequestJobTest, NonExistentBlobUUIDResponse) {
-  SetUpWithHelper(new BlobResponder("blob-id:nothing-is-here", 0));
+  SetUpWithHelper(
+      base::MakeUnique<BlobResponder>("blob-id:nothing-is-here", 0));
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   TestRequest(500, "Service Worker Response Error", std::string(),
               true /* expect_valid_ssl */);
@@ -612,8 +622,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -665,8 +676,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_ConsecutiveRead) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -712,8 +724,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponseAndCancel) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -766,8 +779,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_Abort) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -819,8 +833,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_AbortBeforeData) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
 
@@ -877,8 +892,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_AbortAfterData) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
 
@@ -921,8 +937,9 @@
 TEST_F(ServiceWorkerURLRequestJobTest, StreamResponse_ConsecutiveReadAndAbort) {
   blink::mojom::ServiceWorkerStreamCallbackPtr stream_callback;
   mojo::DataPipe data_pipe;
-  SetUpWithHelper(new StreamResponder(mojo::MakeRequest(&stream_callback),
-                                      std::move(data_pipe.consumer_handle)));
+  SetUpWithHelper(
+      base::MakeUnique<StreamResponder>(mojo::MakeRequest(&stream_callback),
+                                        std::move(data_pipe.consumer_handle)));
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -991,7 +1008,7 @@
 };
 
 TEST_F(ServiceWorkerURLRequestJobTest, FailFetchDispatch) {
-  SetUpWithHelper(new FailFetchHelper);
+  SetUpWithHelper(base::MakeUnique<FailFetchHelper>());
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   request_ = url_request_context_.CreateRequest(
@@ -1020,6 +1037,7 @@
 }
 
 TEST_F(ServiceWorkerURLRequestJobTest, FailToActivate_MainResource) {
+  SetUpWithHelper(base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath()));
   RunFailToActivateTest(RESOURCE_TYPE_MAIN_FRAME);
 
   // The load should fail and we should have fallen back to network because
@@ -1036,6 +1054,7 @@
 }
 
 TEST_F(ServiceWorkerURLRequestJobTest, FailToActivate_Subresource) {
+  SetUpWithHelper(base::MakeUnique<EmbeddedWorkerTestHelper>(base::FilePath()));
   RunFailToActivateTest(RESOURCE_TYPE_IMAGE);
 
   // The load should fail and we should not fall back to network because
@@ -1091,8 +1110,9 @@
 // This simulates the case when a response is returned and the fetch event is
 // still in flight.
 TEST_F(ServiceWorkerURLRequestJobTest, EarlyResponse) {
-  EarlyResponseHelper* helper = new EarlyResponseHelper;
-  SetUpWithHelper(helper);
+  SetUpWithHelper(base::MakeUnique<EarlyResponseHelper>());
+  EarlyResponseHelper* helper =
+      static_cast<EarlyResponseHelper*>(helper_.get());
 
   version_->SetStatus(ServiceWorkerVersion::ACTIVATED);
   TestRequest(200, "OK", std::string(), true /* expect_valid_ssl */);
@@ -1162,8 +1182,9 @@
 
 // Test cancelling the URLRequest while the fetch event is in flight.
 TEST_F(ServiceWorkerURLRequestJobTest, CancelRequest) {
-  DelayedResponseHelper* helper = new DelayedResponseHelper;
-  SetUpWithHelper(helper);
+  SetUpWithHelper(base::MakeUnique<DelayedResponseHelper>());
+  DelayedResponseHelper* helper =
+      static_cast<DelayedResponseHelper*>(helper_.get());
 
   // Start the URL request. The job will be waiting for the
   // worker to respond to the fetch event.
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index bfbf51e..b332498 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -451,7 +451,6 @@
   bool using_synchronous_compositor =
       GetContentClient()->UsingSynchronousCompositing();
 
-  settings.use_stream_video_draw_quad = true;
   settings.using_synchronous_renderer_compositor = using_synchronous_compositor;
   if (using_synchronous_compositor) {
     // Android WebView uses system scrollbars, so make ours invisible.
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
index 6632d54..1d62713 100644
--- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
+++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -4576,4 +4576,54 @@
   EXPECT_EQ(0x23u, device->GetAdvertisingDataFlags().value());
 }
 
+TEST_F(BluetoothBlueZTest, SetConnectionLatency) {
+  GetAdapter();
+  DiscoverDevices();
+
+  // SetConnectionLatency is supported on LE devices.
+  bluez::FakeBluetoothDeviceClient::Properties* properties =
+      fake_bluetooth_device_client_->GetProperties(dbus::ObjectPath(
+          bluez::FakeBluetoothDeviceClient::kConnectUnpairablePath));
+  properties->type.ReplaceValue(BluetoothDeviceClient::kTypeLe);
+  BluetoothDevice* device = adapter_->GetDevice(
+      bluez::FakeBluetoothDeviceClient::kConnectUnpairableAddress);
+  ASSERT_TRUE(device);
+
+  device->SetConnectionLatency(
+      BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_LOW, GetCallback(),
+      GetErrorCallback());
+  EXPECT_EQ(1, callback_count_);
+  EXPECT_EQ(0, error_callback_count_);
+
+  device->SetConnectionLatency(
+      BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_HIGH,
+      GetCallback(), GetErrorCallback());
+  EXPECT_EQ(2, callback_count_);
+  EXPECT_EQ(0, error_callback_count_);
+
+  // Dual mode devices should be supported as well.
+  properties->type.ReplaceValue(BluetoothDeviceClient::kTypeDual);
+  device->SetConnectionLatency(
+      BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_MEDIUM,
+      GetCallback(), GetErrorCallback());
+  EXPECT_EQ(3, callback_count_);
+  EXPECT_EQ(0, error_callback_count_);
+
+  // This API is not supported for BR/EDR devices.
+  properties->type.ReplaceValue(BluetoothDeviceClient::kTypeBredr);
+  device->SetConnectionLatency(
+      BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_MEDIUM,
+      GetCallback(), GetErrorCallback());
+  EXPECT_EQ(3, callback_count_);
+  EXPECT_EQ(1, error_callback_count_);
+
+  // Return an error if the type is not valid.
+  properties->type.set_valid(false);
+  device->SetConnectionLatency(
+      BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_MEDIUM,
+      GetCallback(), GetErrorCallback());
+  EXPECT_EQ(3, callback_count_);
+  EXPECT_EQ(2, error_callback_count_);
+}
+
 }  // namespace bluez
diff --git a/device/bluetooth/dbus/fake_bluetooth_device_client.cc b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
index cc4eaefd..4f0243d 100644
--- a/device/bluetooth/dbus/fake_bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
@@ -601,8 +601,9 @@
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
   Properties* properties = GetProperties(object_path);
-  if (!properties->connected.value()) {
-    error_callback.Run(bluetooth_device::kErrorNotConnected, "Not Connected");
+  if (!properties->type.is_valid() || properties->type.value() == kTypeBredr) {
+    error_callback.Run(bluetooth_device::kErrorFailed,
+                       "BR/EDR devices not supported");
     return;
   }
 
diff --git a/device/vr/vr_service_impl.cc b/device/vr/vr_service_impl.cc
index 7ceb154d..81223fa 100644
--- a/device/vr/vr_service_impl.cc
+++ b/device/vr/vr_service_impl.cc
@@ -15,7 +15,9 @@
 namespace device {
 
 VRServiceImpl::VRServiceImpl()
-    : listening_for_activate_(false), weak_ptr_factory_(this) {}
+    : listening_for_activate_(false),
+      connected_devices_(0),
+      weak_ptr_factory_(this) {}
 
 VRServiceImpl::~VRServiceImpl() {
   // Destroy VRDisplay before calling RemoveService below. RemoveService might
@@ -35,13 +37,12 @@
                               SetClientCallback callback) {
   DCHECK(!client_.get());
   client_ = std::move(service_client);
-  VRDeviceManager* device_manager = VRDeviceManager::GetInstance();
   // Once a client has been connected AddService will force any VRDisplays to
   // send ConnectDevice to it so that it's populated with the currently active
   // displays. Thereafter it will stay up to date by virtue of listening for new
   // connected events.
-  device_manager->AddService(this);
-  std::move(callback).Run(device_manager->GetNumberOfConnectedDevices());
+  VRDeviceManager::GetInstance()->AddService(this);
+  std::move(callback).Run(connected_devices_);
 }
 
 void VRServiceImpl::ConnectDevice(VRDevice* device) {
@@ -70,14 +71,16 @@
                    "process is not established";
     return;
   }
+
   if (!display_info) {
     // If we get passed a null display info it means the device does not exist.
     // This can happen for example if VR services are not installed. We will not
-    // instantiate a display in this case.
+    // instantiate a display in this case and don't count it as connected.
     return;
   }
   displays_[device] = base::MakeUnique<VRDisplayImpl>(
       device, this, client_.get(), std::move(display_info));
+  connected_devices_++;
 }
 
 VRDisplayImpl* VRServiceImpl::GetVRDisplayImplForTesting(VRDevice* device) {
diff --git a/device/vr/vr_service_impl.h b/device/vr/vr_service_impl.h
index 6b0c4b65..e66e54c 100644
--- a/device/vr/vr_service_impl.h
+++ b/device/vr/vr_service_impl.h
@@ -60,6 +60,7 @@
   mojom::VRServiceClientPtr client_;
 
   bool listening_for_activate_;
+  unsigned connected_devices_;
 
   base::WeakPtrFactory<VRServiceImpl> weak_ptr_factory_;
 
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index af7dd84a..7cdd26f8 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -787,15 +787,18 @@
       {"printerProvider", IDR_PRINTER_PROVIDER_CUSTOM_BINDINGS_JS},
       {"runtime", IDR_RUNTIME_CUSTOM_BINDINGS_JS},
       {"webViewRequest", IDR_WEB_VIEW_REQUEST_CUSTOM_BINDINGS_JS},
-      {"binding", IDR_BINDING_JS},
-
-      // Custom types sources.
-      {"StorageArea", IDR_STORAGE_AREA_JS},
 
       // Platform app sources that are not API-specific..
       {"platformApp", IDR_PLATFORM_APP_JS},
   };
 
+  if (!FeatureSwitch::native_crx_bindings()->IsEnabled()) {
+    resources.emplace_back("binding", IDR_BINDING_JS);
+
+    // Custom types sources.
+    resources.emplace_back("StorageArea", IDR_STORAGE_AREA_JS);
+  }
+
   if (base::FeatureList::IsEnabled(::features::kGuestViewCrossProcessFrames)) {
     resources.emplace_back("guestViewIframe", IDR_GUEST_VIEW_IFRAME_JS);
     resources.emplace_back("guestViewIframeContainer",
diff --git a/extensions/renderer/resources/extension_custom_bindings.js b/extensions/renderer/resources/extension_custom_bindings.js
index a7a5977..cb13513 100644
--- a/extensions/renderer/resources/extension_custom_bindings.js
+++ b/extensions/renderer/resources/extension_custom_bindings.js
@@ -4,7 +4,7 @@
 
 // Custom binding for the extension API.
 
-var binding = require('binding').Binding.create('extension');
+var binding = apiBridge || require('binding').Binding.create('extension');
 
 var messaging = require('messaging');
 var runtimeNatives = requireNative('runtime');
@@ -113,4 +113,5 @@
   }
 });
 
-exports.$set('binding', binding.generate());
+if (!apiBridge)
+  exports.$set('binding', binding.generate());
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
index 4333398a..0fa17f0 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_action_requests.js
@@ -7,7 +7,9 @@
 
 var MessagingNatives = requireNative('messaging_natives');
 var WebViewConstants = require('webViewConstants').WebViewConstants;
-var WebViewInternal = require('webViewInternal').WebViewInternal;
+var WebViewInternal = getInternalApi ?
+    getInternalApi('webViewInternal') :
+    require('webViewInternal').WebViewInternal;
 
 var PERMISSION_TYPES = ['media',
                         'geolocation',
diff --git a/extensions/renderer/resources/guest_view/web_view/web_view_internal.js b/extensions/renderer/resources/guest_view/web_view/web_view_internal.js
index 4d2c36c..ff9b319 100644
--- a/extensions/renderer/resources/guest_view/web_view/web_view_internal.js
+++ b/extensions/renderer/resources/guest_view/web_view/web_view_internal.js
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-exports.$set(
-    'WebViewInternal',
-    require('binding').Binding.create('webViewInternal').generate());
+if (!apiBridge) {
+  exports.$set(
+      'WebViewInternal',
+      require('binding').Binding.create('webViewInternal').generate());
+}
diff --git a/ios/chrome/browser/metrics/BUILD.gn b/ios/chrome/browser/metrics/BUILD.gn
index 3ac24ce..feff38a2 100644
--- a/ios/chrome/browser/metrics/BUILD.gn
+++ b/ios/chrome/browser/metrics/BUILD.gn
@@ -147,6 +147,7 @@
     "//ios/testing:ocmock_support",
     "//ios/web",
     "//ios/web/public/test",
+    "//ios/web/public/test/fakes",
     "//testing/gtest",
     "//third_party/ocmock",
   ]
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder.mm b/ios/chrome/browser/metrics/tab_usage_recorder.mm
index b8cd3ba..f4d1b87 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder.mm
@@ -8,6 +8,9 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 #import "ios/chrome/browser/tabs/tab.h"
+#import "ios/web/public/navigation_item.h"
+#import "ios/web/public/navigation_manager.h"
+#import "ios/web/public/web_state/web_state.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -298,7 +301,11 @@
 bool TabUsageRecorder::ShouldIgnoreTab(Tab* tab) {
   // Do not count chrome:// urls to avoid data noise.  For example, if they were
   // counted, every new tab created would add noise to the page load count.
-  return [tab url].SchemeIs(kChromeUIScheme);
+  web::NavigationItem* pending_item =
+      tab.webState->GetNavigationManager()->GetPendingItem();
+  if (pending_item)
+    return pending_item->GetURL().SchemeIs(kChromeUIScheme);
+  return tab.lastCommittedURL.SchemeIs(kChromeUIScheme);
 }
 
 bool TabUsageRecorder::TabAlreadyEvicted(Tab* tab) {
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm
index ca0817b..31672db7 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_unittest.mm
@@ -4,6 +4,7 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/stl_util.h"
@@ -13,6 +14,8 @@
 #import "ios/chrome/browser/metrics/tab_usage_recorder_delegate.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #include "ios/testing/ocmock_complex_type_helper.h"
+#import "ios/web/public/test/fakes/test_navigation_manager.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -25,9 +28,16 @@
 
 @interface TURTestTabMock : OCMockComplexTypeHelper {
   GURL _url;
+  GURL _lastCommittedURL;
+  GURL _visibleURL;
+  web::TestWebState _webState;
 }
 
 @property(nonatomic, assign) const GURL& url;
+@property(nonatomic, assign) const GURL& lastCommittedURL;
+@property(nonatomic, assign) const GURL& visibleURL;
+@property(nonatomic, readonly) web::WebState* webState;
+
 @end
 
 @implementation TURTestTabMock
@@ -37,6 +47,25 @@
 - (void)setUrl:(const GURL&)url {
   _url = url;
 }
+- (const GURL&)lastCommittedURL {
+  return _lastCommittedURL;
+}
+- (void)setLastCommittedURL:(const GURL&)lastCommittedURL {
+  _lastCommittedURL = lastCommittedURL;
+}
+- (const GURL&)visibleURL {
+  return _visibleURL;
+}
+- (void)setVisibleURL:(const GURL&)visibleURL {
+  _visibleURL = visibleURL;
+}
+- (web::WebState*)webState {
+  if (!_webState.GetNavigationManager()) {
+    _webState.SetNavigationManager(
+        base::MakeUnique<web::TestNavigationManager>());
+  }
+  return &_webState;
+}
 @end
 
 // A mock TabUsageRecorderDelegate which allows the unit tests to control
@@ -106,6 +135,8 @@
     [[[tab_mock stub] andReturn:web_controller_mock] webController];
     [[[tab_mock stub] andReturnBool:false] isPrerenderTab];
     [tab_mock setUrl:webUrl_];
+    [tab_mock setLastCommittedURL:webUrl_];
+    [tab_mock setVisibleURL:webUrl_];
     [[[web_controller_mock stub] andReturnBool:inMemory] isViewAlive];
     [[web_controller_mock stub] removeObserver:OCMOCK_ANY];
     return tab_mock;
@@ -173,7 +204,11 @@
   id tab_mock_a = MockTab(true);
   id tab_mock_b = MockTab(false);
   [tab_mock_a setUrl:nativeUrl_];
+  [tab_mock_a setLastCommittedURL:nativeUrl_];
+  [tab_mock_a setVisibleURL:nativeUrl_];
   [tab_mock_b setUrl:nativeUrl_];
+  [tab_mock_b setLastCommittedURL:nativeUrl_];
+  [tab_mock_b setVisibleURL:nativeUrl_];
 
   // Call reload an arbitrary number of times.
   const int kNumReloads = 4;
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn
index 16d626da..9eb6181a8 100644
--- a/ios/chrome/browser/sync/BUILD.gn
+++ b/ios/chrome/browser/sync/BUILD.gn
@@ -11,6 +11,8 @@
     "ios_chrome_sync_client.mm",
     "ios_chrome_synced_tab_delegate.h",
     "ios_chrome_synced_tab_delegate.mm",
+    "ios_user_event_service_factory.cc",
+    "ios_user_event_service_factory.h",
     "sync_observer_bridge.h",
     "sync_observer_bridge.mm",
     "sync_setup_service.cc",
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h
index 0647a7f..71dbf5fb 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h
@@ -43,7 +43,7 @@
   IOSChromeProfileSyncServiceFactory();
   ~IOSChromeProfileSyncServiceFactory() override;
 
-  // BrowserContextKeyedServiceFactory:
+  // BrowserStateKeyedServiceFactory implementation.
   std::unique_ptr<KeyedService> BuildServiceInstanceFor(
       web::BrowserState* context) const override;
 };
diff --git a/ios/chrome/browser/sync/ios_user_event_service_factory.cc b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
new file mode 100644
index 0000000..dcca1a8
--- /dev/null
+++ b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/sync/ios_user_event_service_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/singleton.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/sync/base/model_type.h"
+#include "components/sync/base/report_unrecoverable_error.h"
+#include "components/sync/user_events/no_op_user_event_service.h"
+#include "components/sync/user_events/user_event_service_impl.h"
+#include "components/sync/user_events/user_event_sync_bridge.h"
+#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#include "ios/chrome/common/channel_info.h"
+#include "ios/web/public/browser_state.h"
+
+// static
+syncer::UserEventService* IOSUserEventServiceFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<syncer::UserEventService*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+// static
+IOSUserEventServiceFactory* IOSUserEventServiceFactory::GetInstance() {
+  return base::Singleton<IOSUserEventServiceFactory>::get();
+}
+
+IOSUserEventServiceFactory::IOSUserEventServiceFactory()
+    : BrowserStateKeyedServiceFactory(
+          "UserEventService",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+IOSUserEventServiceFactory::~IOSUserEventServiceFactory() {}
+
+std::unique_ptr<KeyedService>
+IOSUserEventServiceFactory::BuildServiceInstanceFor(
+    web::BrowserState* browser_state) const {
+  if (browser_state->IsOffTheRecord()) {
+    return base::MakeUnique<syncer::NoOpUserEventService>();
+  }
+
+  syncer::ModelTypeStoreFactory store_factory =
+      browser_sync::ProfileSyncService::GetModelTypeStoreFactory(
+          syncer::USER_EVENTS, browser_state->GetStatePath());
+  syncer::ModelTypeSyncBridge::ChangeProcessorFactory processor_factory =
+      base::BindRepeating(&syncer::ModelTypeChangeProcessor::Create,
+                          base::BindRepeating(&syncer::ReportUnrecoverableError,
+                                              ::GetChannel()));
+  auto bridge = base::MakeUnique<syncer::UserEventSyncBridge>(
+      std::move(store_factory), std::move(processor_factory));
+  return base::MakeUnique<syncer::UserEventServiceImpl>(
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(
+          ios::ChromeBrowserState::FromBrowserState(browser_state)),
+      std::move(bridge));
+}
+
+web::BrowserState* IOSUserEventServiceFactory::GetBrowserStateToUse(
+    web::BrowserState* context) const {
+  return GetBrowserStateOwnInstanceInIncognito(context);
+}
diff --git a/ios/chrome/browser/sync/ios_user_event_service_factory.h b/ios/chrome/browser/sync/ios_user_event_service_factory.h
new file mode 100644
index 0000000..31071e1b
--- /dev/null
+++ b/ios/chrome/browser/sync/ios_user_event_service_factory.h
@@ -0,0 +1,47 @@
+// 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_SYNC_IOS_USER_EVENT_SERVICE_FACTORY_H_
+#define IOS_CHROME_BROWSER_SYNC_IOS_USER_EVENT_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+namespace syncer {
+class UserEventService;
+}  // namespace syncer
+
+// Singleton that associates UserEventServices to ChromeBrowserStates.
+class IOSUserEventServiceFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static syncer::UserEventService* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+  static IOSUserEventServiceFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<IOSUserEventServiceFactory>;
+
+  IOSUserEventServiceFactory();
+  ~IOSUserEventServiceFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* context) const override;
+};
+
+#endif  // IOS_CHROME_BROWSER_SYNC_IOS_USER_EVENT_SERVICE_FACTORY_H_
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index 9a04f5b..121979a2 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -459,6 +459,8 @@
       "android_video_surface_chooser_impl_unittest.cc",
       "avda_codec_allocator_unittest.cc",
       "content_video_view_overlay_allocator_unittest.cc",
+      "mock_surface_texture_gl_owner.cc",
+      "mock_surface_texture_gl_owner.h",
       "surface_texture_gl_owner_unittest.cc",
     ]
     if (enable_media_codec_video_decoder) {
diff --git a/media/gpu/android/fake_codec_allocator.h b/media/gpu/android/fake_codec_allocator.h
index 903dfce..f14e7fc 100644
--- a/media/gpu/android/fake_codec_allocator.h
+++ b/media/gpu/android/fake_codec_allocator.h
@@ -27,15 +27,17 @@
   // implementation of their respective functions.  This allows tests to set
   // expectations on them.
   MOCK_METHOD2(MockCreateMediaCodecSync,
-               void(AndroidOverlay*, gl::SurfaceTexture*));
+               void(AndroidOverlay*, SurfaceTextureGLOwner*));
   MOCK_METHOD2(MockCreateMediaCodecAsync,
-               void(AndroidOverlay*, gl::SurfaceTexture*));
+               void(AndroidOverlay*, SurfaceTextureGLOwner*));
 
   // Note that this doesn't exactly match the signature, since unique_ptr
   // doesn't work.  plus, we expand |surface_bundle| a bit to make it more
   // convenient to set expectations.
   MOCK_METHOD3(MockReleaseMediaCodec,
-               void(MediaCodecBridge*, AndroidOverlay*, gl::SurfaceTexture*));
+               void(MediaCodecBridge*,
+                    AndroidOverlay*,
+                    SurfaceTextureGLOwner*));
 
   std::unique_ptr<MediaCodecBridge> CreateMediaCodecSync(
       scoped_refptr<CodecConfig> codec_config) override;
@@ -69,7 +71,7 @@
   // Returns the most recent overlay / etc. that we were given during codec
   // allocation (sync or async).
   AndroidOverlay* most_recent_overlay() { return most_recent_overlay_; }
-  gl::SurfaceTexture* most_recent_surface_texture() {
+  SurfaceTextureGLOwner* most_recent_surface_texture() {
     return most_recent_surface_texture_;
   }
 
@@ -90,7 +92,7 @@
   AndroidOverlay* most_recent_overlay_ = nullptr;
 
   // The most recent surface texture provided during codec allocation.
-  gl::SurfaceTexture* most_recent_surface_texture_ = nullptr;
+  SurfaceTextureGLOwner* most_recent_surface_texture_ = nullptr;
 
   // Whether CreateMediaCodecSync() is allowed to succeed.
   bool allow_sync_creation = true;
diff --git a/media/gpu/android/media_codec_video_decoder.cc b/media/gpu/android/media_codec_video_decoder.cc
index b40bfa0..7dd4a38e 100644
--- a/media/gpu/android/media_codec_video_decoder.cc
+++ b/media/gpu/android/media_codec_video_decoder.cc
@@ -150,7 +150,7 @@
   DVLOG(2) << __func__;
   lazy_init_pending_ = false;
   // TODO(watk): Initialize surface_texture_ properly.
-  surface_texture_ = SurfaceTextureGLOwner::Create();
+  surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
   InitializeSurfaceChooser();
 }
 
diff --git a/media/gpu/avda_codec_image.cc b/media/gpu/avda_codec_image.cc
index 6d38a49..d8688d2 100644
--- a/media/gpu/avda_codec_image.cc
+++ b/media/gpu/avda_codec_image.cc
@@ -148,6 +148,7 @@
   if (shared_state == shared_state_)
     return false;
   shared_state_ = shared_state;
+  most_recent_bounds_ = gfx::Rect();
   return true;
 }
 
diff --git a/media/gpu/avda_picture_buffer_manager.cc b/media/gpu/avda_picture_buffer_manager.cc
index 9215cdd..e129b64 100644
--- a/media/gpu/avda_picture_buffer_manager.cc
+++ b/media/gpu/avda_picture_buffer_manager.cc
@@ -54,12 +54,12 @@
 
   if (!surface_bundle->overlay) {
     // Create the surface texture.
-    surface_texture_ = SurfaceTextureGLOwner::Create();
+    surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
     if (!surface_texture_)
       return false;
 
     surface_bundle->surface_texture_surface =
-        gl::ScopedJavaSurface(surface_texture_.get());
+        surface_texture_->CreateJavaSurface();
     surface_bundle->surface_texture = surface_texture_;
   }
 
diff --git a/media/gpu/avda_shared_state.h b/media/gpu/avda_shared_state.h
index 65111a5e..4b86d30 100644
--- a/media/gpu/avda_shared_state.h
+++ b/media/gpu/avda_shared_state.h
@@ -29,7 +29,7 @@
   AVDASharedState(scoped_refptr<AVDASurfaceBundle> surface_bundle);
 
   GLuint surface_texture_service_id() const {
-    return surface_texture() ? surface_texture()->texture_id() : 0;
+    return surface_texture() ? surface_texture()->GetTextureId() : 0;
   }
 
   SurfaceTextureGLOwner* surface_texture() const {
@@ -43,11 +43,11 @@
   // Context and surface that |surface_texture_| is bound to, if
   // |surface_texture_| is not null.
   gl::GLContext* context() const {
-    return surface_texture() ? surface_texture()->context() : nullptr;
+    return surface_texture() ? surface_texture()->GetContext() : nullptr;
   }
 
   gl::GLSurface* surface() const {
-    return surface_texture() ? surface_texture()->surface() : nullptr;
+    return surface_texture() ? surface_texture()->GetSurface() : nullptr;
   }
 
   // Helper method for coordinating the interactions between
diff --git a/media/gpu/avda_surface_bundle.cc b/media/gpu/avda_surface_bundle.cc
index f38b4eb..8ccf550 100644
--- a/media/gpu/avda_surface_bundle.cc
+++ b/media/gpu/avda_surface_bundle.cc
@@ -16,7 +16,7 @@
 AVDASurfaceBundle::AVDASurfaceBundle(
     scoped_refptr<SurfaceTextureGLOwner> surface_texture_owner)
     : surface_texture(std::move(surface_texture_owner)),
-      surface_texture_surface(gl::ScopedJavaSurface(surface_texture.get())) {}
+      surface_texture_surface(surface_texture->CreateJavaSurface()) {}
 
 AVDASurfaceBundle::~AVDASurfaceBundle() {
   // Explicitly free the surface first, just to be sure that it's deleted before
@@ -25,7 +25,7 @@
 
   // Also release the back buffers.
   if (surface_texture)
-    surface_texture->ReleaseSurfaceTexture();
+    surface_texture->ReleaseBackBuffers();
   surface_texture = nullptr;
 }
 
diff --git a/media/gpu/mock_surface_texture_gl_owner.cc b/media/gpu/mock_surface_texture_gl_owner.cc
new file mode 100644
index 0000000..e55e6b4b
--- /dev/null
+++ b/media/gpu/mock_surface_texture_gl_owner.cc
@@ -0,0 +1,11 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/gpu/mock_surface_texture_gl_owner.h"
+namespace media {
+
+MockSurfaceTextureGLOwner::MockSurfaceTextureGLOwner() = default;
+MockSurfaceTextureGLOwner::~MockSurfaceTextureGLOwner() = default;
+
+}  // namespace media
diff --git a/media/gpu/mock_surface_texture_gl_owner.h b/media/gpu/mock_surface_texture_gl_owner.h
new file mode 100644
index 0000000..aa2a286
--- /dev/null
+++ b/media/gpu/mock_surface_texture_gl_owner.h
@@ -0,0 +1,35 @@
+// 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 MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
+#define MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
+
+#include "media/gpu/surface_texture_gl_owner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class MockSurfaceTextureGLOwner : public SurfaceTextureGLOwner {
+ public:
+  MockSurfaceTextureGLOwner();
+  MOCK_CONST_METHOD0(GetTextureId, GLuint());
+  MOCK_CONST_METHOD0(GetContext, gl::GLContext*());
+  MOCK_CONST_METHOD0(GetSurface, gl::GLSurface*());
+  MOCK_CONST_METHOD0(CreateJavaSurface, gl::ScopedJavaSurface());
+  MOCK_METHOD0(UpdateTexImage, void());
+  MOCK_METHOD1(GetTransformMatrix, void(float mtx[16]));
+  MOCK_METHOD0(ReleaseBackBuffers, void());
+  MOCK_METHOD0(SetReleaseTimeToNow, void());
+  MOCK_METHOD0(IgnorePendingRelease, void());
+  MOCK_METHOD0(IsExpectingFrameAvailable, bool());
+  MOCK_METHOD0(WaitForFrameAvailable, void());
+
+ protected:
+  ~MockSurfaceTextureGLOwner();
+};
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_MOCK_SURFACE_TEXTURE_GL_OWNER_H_
diff --git a/media/gpu/surface_texture_gl_owner.cc b/media/gpu/surface_texture_gl_owner.cc
index 5714505..59ab65b3 100644
--- a/media/gpu/surface_texture_gl_owner.cc
+++ b/media/gpu/surface_texture_gl_owner.cc
@@ -14,7 +14,7 @@
 namespace media {
 
 // FrameAvailableEvent is a RefCounted wrapper for a WaitableEvent
-// because it's not possible to put one in RefCountedData.
+// (it's not possible to put one in RefCountedData).
 // This lets us safely signal an event on any thread.
 struct FrameAvailableEvent
     : public base::RefCountedThreadSafe<FrameAvailableEvent> {
@@ -29,7 +29,7 @@
   ~FrameAvailableEvent() = default;
 };
 
-scoped_refptr<SurfaceTextureGLOwner> SurfaceTextureGLOwner::Create() {
+scoped_refptr<SurfaceTextureGLOwner> SurfaceTextureGLOwnerImpl::Create() {
   GLuint texture_id;
   glGenTextures(1, &texture_id);
   if (!texture_id)
@@ -44,25 +44,25 @@
   glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
   DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
 
-  return new SurfaceTextureGLOwner(texture_id);
+  return new SurfaceTextureGLOwnerImpl(texture_id);
 }
 
-SurfaceTextureGLOwner::SurfaceTextureGLOwner(GLuint texture_id)
-    : SurfaceTexture(CreateJavaSurfaceTexture(texture_id)),
+SurfaceTextureGLOwnerImpl::SurfaceTextureGLOwnerImpl(GLuint texture_id)
+    : surface_texture_(gl::SurfaceTexture::Create(texture_id)),
+      texture_id_(texture_id),
       context_(gl::GLContext::GetCurrent()),
       surface_(gl::GLSurface::GetCurrent()),
-      texture_id_(texture_id),
       frame_available_event_(new FrameAvailableEvent()) {
   DCHECK(context_);
   DCHECK(surface_);
-  SetFrameAvailableCallbackOnAnyThread(
+  surface_texture_->SetFrameAvailableCallbackOnAnyThread(
       base::Bind(&FrameAvailableEvent::Signal, frame_available_event_));
 }
 
-SurfaceTextureGLOwner::~SurfaceTextureGLOwner() {
+SurfaceTextureGLOwnerImpl::~SurfaceTextureGLOwnerImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
   // Make sure that the SurfaceTexture isn't using the GL objects.
-  DestroyJavaObject();
+  surface_texture_ = nullptr;
 
   ui::ScopedMakeCurrent scoped_make_current(context_.get(), surface_.get());
   if (scoped_make_current.Succeeded()) {
@@ -71,19 +71,47 @@
   }
 }
 
-void SurfaceTextureGLOwner::SetReleaseTimeToNow() {
+GLuint SurfaceTextureGLOwnerImpl::GetTextureId() const {
+  return texture_id_;
+}
+
+gl::ScopedJavaSurface SurfaceTextureGLOwnerImpl::CreateJavaSurface() const {
+  return gl::ScopedJavaSurface(surface_texture_.get());
+}
+
+void SurfaceTextureGLOwnerImpl::UpdateTexImage() {
+  surface_texture_->UpdateTexImage();
+}
+
+void SurfaceTextureGLOwnerImpl::GetTransformMatrix(float mtx[]) {
+  surface_texture_->GetTransformMatrix(mtx);
+}
+
+void SurfaceTextureGLOwnerImpl::ReleaseBackBuffers() {
+  surface_texture_->ReleaseBackBuffers();
+}
+
+gl::GLContext* SurfaceTextureGLOwnerImpl::GetContext() const {
+  return context_.get();
+}
+
+gl::GLSurface* SurfaceTextureGLOwnerImpl::GetSurface() const {
+  return surface_.get();
+}
+
+void SurfaceTextureGLOwnerImpl::SetReleaseTimeToNow() {
   release_time_ = base::TimeTicks::Now();
 }
 
-void SurfaceTextureGLOwner::IgnorePendingRelease() {
+void SurfaceTextureGLOwnerImpl::IgnorePendingRelease() {
   release_time_ = base::TimeTicks();
 }
 
-bool SurfaceTextureGLOwner::IsExpectingFrameAvailable() {
+bool SurfaceTextureGLOwnerImpl::IsExpectingFrameAvailable() {
   return !release_time_.is_null();
 }
 
-void SurfaceTextureGLOwner::WaitForFrameAvailable() {
+void SurfaceTextureGLOwnerImpl::WaitForFrameAvailable() {
   DCHECK(!release_time_.is_null());
 
   // 5msec covers >99.9% of cases, so just wait for up to that much before
@@ -113,12 +141,4 @@
   }
 }
 
-void SurfaceTextureGLOwner::AttachToGLContext() {
-  NOTIMPLEMENTED();
-}
-
-void SurfaceTextureGLOwner::DetachFromGLContext() {
-  NOTIMPLEMENTED();
-}
-
 }  // namespace media
diff --git a/media/gpu/surface_texture_gl_owner.h b/media/gpu/surface_texture_gl_owner.h
index dfdcdb7..957a462 100644
--- a/media/gpu/surface_texture_gl_owner.h
+++ b/media/gpu/surface_texture_gl_owner.h
@@ -9,6 +9,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_checker.h"
 #include "media/gpu/media_gpu_export.h"
+#include "ui/gl/android/scoped_java_surface.h"
 #include "ui/gl/android/surface_texture.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_context.h"
@@ -18,57 +19,88 @@
 
 struct FrameAvailableEvent;
 
-// Handy subclass of SurfaceTexture which creates and maintains ownership of the
-// GL texture also.  This texture is only destroyed with the object; one may
-// ReleaseSurfaceTexture without destroying the GL texture.  It must be deleted
-// on the same thread on which it is constructed.
-class MEDIA_GPU_EXPORT SurfaceTextureGLOwner : public gl::SurfaceTexture {
+// A SurfaceTexture wrapper that creates and maintains ownership of the
+// attached GL texture. The texture is destroyed with the object but it's
+// possible to call ReleaseSurfaceTexture() without destroying the GL texture.
+// It must be deleted on the thread it was constructed on.
+// This is a virtual interface to make it mockable; see
+// SurfaceTextureGLOwnerImpl.
+class MEDIA_GPU_EXPORT SurfaceTextureGLOwner
+    : public base::RefCountedThreadSafe<SurfaceTextureGLOwner> {
  public:
-  // Must be called with a platform gl context current.  Creates the GL texture
-  // using this context, and memorizes it to delete the texture later.
-  static scoped_refptr<SurfaceTextureGLOwner> Create();
+  SurfaceTextureGLOwner() = default;
 
-  // Return the GL texture id that we created.
-  GLuint texture_id() const { return texture_id_; }
+  // Returns the GL texture id that the SurfaceTexture is attached to.
+  virtual GLuint GetTextureId() const = 0;
+  virtual gl::GLContext* GetContext() const = 0;
+  virtual gl::GLSurface* GetSurface() const = 0;
 
-  gl::GLContext* context() const { return context_.get(); }
-  gl::GLSurface* surface() const { return surface_.get(); }
+  // Create a java surface for the SurfaceTexture.
+  virtual gl::ScopedJavaSurface CreateJavaSurface() const = 0;
 
-  // Start expecting a new frame because a buffer was just released to this
-  // surface.
-  void SetReleaseTimeToNow();
+  // See gl::SurfaceTexture for the following.
+  virtual void UpdateTexImage() = 0;
+  virtual void GetTransformMatrix(float mtx[16]) = 0;
+  virtual void ReleaseBackBuffers() = 0;
+
+  // Sets the expectation of onFrameAVailable for a new frame because a buffer
+  // was just released to this surface.
+  virtual void SetReleaseTimeToNow() = 0;
 
   // Ignores a pending release that was previously indicated with
   // SetReleaseTimeToNow().
   // TODO(watk): This doesn't seem necessary. It actually may be detrimental
   // because the next time we release a buffer we may confuse its
   // onFrameAvailable with the one we're ignoring.
-  void IgnorePendingRelease();
+  virtual void IgnorePendingRelease() = 0;
 
   // Whether we're expecting onFrameAvailable. True when SetReleaseTimeToNow()
   // was called but neither IgnorePendingRelease() nor WaitForFrameAvailable()
   // have been called since.
-  bool IsExpectingFrameAvailable();
+  virtual bool IsExpectingFrameAvailable() = 0;
 
   // Waits for onFrameAvailable until it's been 5ms since the buffer was
   // released. This must only be called if IsExpectingFrameAvailable().
-  void WaitForFrameAvailable();
+  virtual void WaitForFrameAvailable() = 0;
 
-  // We don't support these.  In principle, we could, but they're fairly buggy
-  // anyway on many devices.
-  void AttachToGLContext() override;
-  void DetachFromGLContext() override;
+ protected:
+  friend class base::RefCountedThreadSafe<SurfaceTextureGLOwner>;
+  virtual ~SurfaceTextureGLOwner() = default;
 
  private:
-  SurfaceTextureGLOwner(GLuint texture_id);
-  ~SurfaceTextureGLOwner() override;
+  DISALLOW_COPY_AND_ASSIGN(SurfaceTextureGLOwner);
+};
 
-  // Context and surface that were used to create |texture_id_|.
+class MEDIA_GPU_EXPORT SurfaceTextureGLOwnerImpl
+    : public SurfaceTextureGLOwner {
+ public:
+  // Creates a GL texture using the current platform GL context and returns a
+  // new SurfaceTextureGLOwnerImpl attached to it. Returns null on failure.
+  static scoped_refptr<SurfaceTextureGLOwner> Create();
+
+  GLuint GetTextureId() const override;
+  gl::GLContext* GetContext() const override;
+  gl::GLSurface* GetSurface() const override;
+  gl::ScopedJavaSurface CreateJavaSurface() const override;
+  void UpdateTexImage() override;
+  void GetTransformMatrix(float mtx[16]) override;
+  void ReleaseBackBuffers() override;
+  void SetReleaseTimeToNow() override;
+  void IgnorePendingRelease() override;
+  bool IsExpectingFrameAvailable() override;
+  void WaitForFrameAvailable() override;
+
+ private:
+  SurfaceTextureGLOwnerImpl(GLuint texture_id);
+  ~SurfaceTextureGLOwnerImpl() override;
+
+  scoped_refptr<gl::SurfaceTexture> surface_texture_;
+  GLuint texture_id_;
+
+  // The context and surface that were used to create |texture_id_|.
   scoped_refptr<gl::GLContext> context_;
   scoped_refptr<gl::GLSurface> surface_;
 
-  GLuint texture_id_;
-
   // When SetReleaseTimeToNow() was last called. i.e., when the last
   // codec buffer was released to this surface. Or null if
   // IgnorePendingRelease() or WaitForFrameAvailable() have been called since.
@@ -76,6 +108,7 @@
   scoped_refptr<FrameAvailableEvent> frame_available_event_;
 
   base::ThreadChecker thread_checker_;
+  DISALLOW_COPY_AND_ASSIGN(SurfaceTextureGLOwnerImpl);
 };
 
 }  // namespace media
diff --git a/media/gpu/surface_texture_gl_owner_unittest.cc b/media/gpu/surface_texture_gl_owner_unittest.cc
index 4f077dd..1eee962f 100644
--- a/media/gpu/surface_texture_gl_owner_unittest.cc
+++ b/media/gpu/surface_texture_gl_owner_unittest.cc
@@ -43,8 +43,8 @@
     context_->Initialize(surface_.get(), gl::GLContextAttribs());
     ASSERT_TRUE(context_->MakeCurrent(surface_.get()));
 
-    surface_texture_ = SurfaceTextureGLOwner::Create();
-    texture_id_ = surface_texture_->texture_id();
+    surface_texture_ = SurfaceTextureGLOwnerImpl::Create();
+    texture_id_ = surface_texture_->GetTextureId();
     // Bind and un-bind the texture, since that's required for glIsTexture to
     // return true.
     glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
@@ -77,16 +77,16 @@
   ASSERT_FALSE(glIsTexture(texture_id_));
 }
 
-// Calling ReleaseSurfaceTexture shouldn't deallocate the texture handle.
+// Calling ReleaseBackBuffers shouldn't deallocate the texture handle.
 TEST_F(SurfaceTextureGLOwnerTest, ReleaseDoesntDestroyTexture) {
-  surface_texture_->ReleaseSurfaceTexture();
+  surface_texture_->ReleaseBackBuffers();
   ASSERT_TRUE(glIsTexture(texture_id_));
 }
 
 // Make sure that |surface_texture_| remembers the correct context and surface.
 TEST_F(SurfaceTextureGLOwnerTest, ContextAndSurfaceAreCaptured) {
-  ASSERT_EQ(context_, surface_texture_->context());
-  ASSERT_EQ(surface_, surface_texture_->surface());
+  ASSERT_EQ(context_, surface_texture_->GetContext());
+  ASSERT_EQ(surface_, surface_texture_->GetSurface());
 }
 
 // Verify that destruction works even if some other context is current.
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index 530422f..b748016 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -50,6 +50,8 @@
 {%-  for constant in interface.constants %}
 {%-   if constant.kind|is_string_kind %}
 const char {{interface.name}}::{{constant.name}}[] = {{constant|constant_value}};
+{%-   else %}
+constexpr {{constant.kind|cpp_pod_type}} {{interface.name}}::{{constant.name}};
 {%-   endif %}
 {%- endfor %}
 
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
index d54d043..cbbe1be 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -59,6 +59,8 @@
 {%-   for constant in struct.constants %}
 {%-     if constant.kind|is_string_kind %}
 const char {{struct.name}}::{{constant.name}}[] = {{constant|constant_value}};
+{%-     else %}
+constexpr {{constant.kind|cpp_pod_type}} {{struct.name}}::{{constant.name}};
 {%-     endif %}
 {%-   endfor %}
 {%- endfor %}
diff --git a/net/cert/internal/nist_pkits_unittest.cc b/net/cert/internal/nist_pkits_unittest.cc
index 8980709..6697ded9 100644
--- a/net/cert/internal/nist_pkits_unittest.cc
+++ b/net/cert/internal/nist_pkits_unittest.cc
@@ -57,15 +57,18 @@
 }
 
 void PkitsTestInfo::SetInitialExplicitPolicy(bool b) {
-  initial_explicit_policy = b;
+  initial_explicit_policy =
+      b ? InitialExplicitPolicy::kTrue : InitialExplicitPolicy::kFalse;
 }
 
 void PkitsTestInfo::SetInitialPolicyMappingInhibit(bool b) {
-  initial_policy_mapping_inhibit = b;
+  initial_policy_mapping_inhibit = b ? InitialPolicyMappingInhibit::kTrue
+                                     : InitialPolicyMappingInhibit::kFalse;
 }
 
 void PkitsTestInfo::SetInitialInhibitAnyPolicy(bool b) {
-  initial_inhibit_any_policy = b;
+  initial_inhibit_any_policy =
+      b ? InitialAnyPolicyInhibit::kTrue : InitialAnyPolicyInhibit::kFalse;
 }
 
 PkitsTestInfo::~PkitsTestInfo() = default;
diff --git a/net/cert/internal/nist_pkits_unittest.h b/net/cert/internal/nist_pkits_unittest.h
index adc064b6..8f9ef42 100644
--- a/net/cert/internal/nist_pkits_unittest.h
+++ b/net/cert/internal/nist_pkits_unittest.h
@@ -46,13 +46,15 @@
   std::set<der::Input> initial_policy_set;
 
   // The value of "initial-explicit-policy".
-  bool initial_explicit_policy = false;
+  InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse;
 
   // The value of "initial-policy-mapping-inhibit".
-  bool initial_policy_mapping_inhibit = false;
+  InitialPolicyMappingInhibit initial_policy_mapping_inhibit =
+      InitialPolicyMappingInhibit::kFalse;
 
   // The value of "initial-inhibit-any-policy".
-  bool initial_inhibit_any_policy = false;
+  InitialAnyPolicyInhibit initial_inhibit_any_policy =
+      InitialAnyPolicyInhibit::kFalse;
 
   // This is the time when PKITS was published.
   der::GeneralizedTime time = {2011, 4, 15, 0, 0, 0};
diff --git a/net/cert/internal/path_builder.cc b/net/cert/internal/path_builder.cc
index d1ce0bdb..05b66d6 100644
--- a/net/cert/internal/path_builder.cc
+++ b/net/cert/internal/path_builder.cc
@@ -604,9 +604,12 @@
 
   // Verify the entire certificate chain.
   auto result_path = base::MakeUnique<ResultPath>();
-  VerifyCertificateChain(next_path_.certs, next_path_.last_cert_trust,
-                         signature_policy_, time_, key_purpose_,
-                         &result_path->errors);
+  // TODO(eroman): don't pass placeholder for policy.
+  VerifyCertificateChain(
+      next_path_.certs, next_path_.last_cert_trust, signature_policy_, time_,
+      key_purpose_, InitialExplicitPolicy::kFalse, {AnyPolicy()},
+      InitialPolicyMappingInhibit::kFalse, InitialAnyPolicyInhibit::kFalse,
+      nullptr /*user_constrained_policy_set*/, &result_path->errors);
   bool verify_result = !result_path->errors.ContainsHighSeverityErrors();
 
   DVLOG(1) << "CertPathBuilder VerifyCertificateChain result = "
diff --git a/net/cert/internal/test_helpers.cc b/net/cert/internal/test_helpers.cc
index 16c39cf1..70bd6447 100644
--- a/net/cert/internal/test_helpers.cc
+++ b/net/cert/internal/test_helpers.cc
@@ -125,7 +125,8 @@
   return ::testing::AssertionSuccess();
 }
 
-VerifyCertChainTest::VerifyCertChainTest() = default;
+VerifyCertChainTest::VerifyCertChainTest()
+    : user_initial_policy_set{AnyPolicy()} {}
 VerifyCertChainTest::~VerifyCertChainTest() = default;
 
 bool VerifyCertChainTest::HasHighSeverityErrors() const {
diff --git a/net/cert/internal/test_helpers.h b/net/cert/internal/test_helpers.h
index dceb068..d8b1c69 100644
--- a/net/cert/internal/test_helpers.h
+++ b/net/cert/internal/test_helpers.h
@@ -95,6 +95,16 @@
   // The Key Purpose to use when verifying the chain.
   KeyPurpose key_purpose = KeyPurpose::ANY_EKU;
 
+  InitialExplicitPolicy initial_explicit_policy = InitialExplicitPolicy::kFalse;
+
+  std::set<der::Input> user_initial_policy_set;
+
+  InitialPolicyMappingInhibit initial_policy_mapping_inhibit =
+      InitialPolicyMappingInhibit::kFalse;
+
+  InitialAnyPolicyInhibit initial_any_policy_inhibit =
+      InitialAnyPolicyInhibit::kFalse;
+
   // The expected errors/warnings from verification (as a string).
   std::string expected_errors;
 
diff --git a/net/cert/internal/verify_certificate_chain.cc b/net/cert/internal/verify_certificate_chain.cc
index 2560b942..3985cd8a 100644
--- a/net/cert/internal/verify_certificate_chain.cc
+++ b/net/cert/internal/verify_certificate_chain.cc
@@ -4,6 +4,7 @@
 
 #include "net/cert/internal/verify_certificate_chain.h"
 
+#include <algorithm>
 #include <memory>
 
 #include "base/logging.h"
@@ -63,6 +64,9 @@
                      "The extended key usage does not include client auth");
 DEFINE_CERT_ERROR_ID(kCertIsNotTrustAnchor,
                      "Certificate is not a trust anchor");
+DEFINE_CERT_ERROR_ID(kNoValidPolicy, "No valid policy");
+DEFINE_CERT_ERROR_ID(kPolicyMappingAnyPolicy,
+                     "PolicyMappings must not map anyPolicy");
 
 bool IsHandledCriticalExtensionOid(const der::Input& oid) {
   if (oid == BasicConstraintsOid())
@@ -78,8 +82,19 @@
     return true;
   if (oid == SubjectAltNameOid())
     return true;
+  // TODO(eroman): The policy qualifiers are not processed (or in some cases
+  // even parsed). This is fine when the policies extension is non-critical,
+  // however if it is critical the code should also ensure that the policy
+  // qualifiers are only recognized ones (CPS and User Notice).
+  if (oid == CertificatePoliciesOid())
+    return true;
+  if (oid == PolicyMappingsOid())
+    return true;
+  if (oid == PolicyConstraintsOid())
+    return true;
+  if (oid == InhibitAnyPolicyOid())
+    return true;
 
-  // TODO(eroman): Make this more complete.
   return false;
 }
 
@@ -120,7 +135,7 @@
 //    The validity period for a certificate is the period of time from
 //    notBefore through notAfter, inclusive.
 void VerifyTimeValidity(const ParsedCertificate& cert,
-                        const der::GeneralizedTime time,
+                        const der::GeneralizedTime& time,
                         CertErrors* errors) {
   if (time < cert.tbs().validity_not_before)
     errors->AddError(kValidityFailedNotBefore);
@@ -216,16 +231,545 @@
   }
 }
 
-// This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate
-// Processing" procedure.
-void BasicCertificateProcessing(
+// Returns |true| if |policies| contains the OID |search_oid|.
+bool SetContains(const std::set<der::Input>& policies,
+                 const der::Input& search_oid) {
+  return policies.count(search_oid) > 0;
+}
+
+// Representation of RFC 5280's "valid_policy_tree", used to keep track of the
+// valid policies and policy re-mappings.
+//
+// ValidPolicyTree differs slightly from RFC 5280's description in that:
+//
+//  (1) It does not track "qualifier_set". This is not needed as it is not
+//      output by this implementation.
+//
+//  (2) It only stores the most recent level of the policy tree rather than
+//      the full tree of nodes.
+class ValidPolicyTree {
+ public:
+  ValidPolicyTree() {}
+
+  struct Node {
+    // |root_policy| is equivalent to |valid_policy|, but in the domain of the
+    // caller.
+    //
+    // The reason for this distinction is the Policy Mappings extension.
+    //
+    // So whereas |valid_policy| is in the remapped domain defined by the
+    // issuing certificate, |root_policy| is in the fixed domain of the caller.
+    //
+    // OIDs in "user_initial_policy_set" and "user_constrained_policy_set" are
+    // directly comparable to |root_policy| values, but not necessarily to
+    // |valid_policy|.
+    //
+    // In terms of the valid policy tree, |root_policy| can be found by
+    // starting at the node's root ancestor, and finding the first node with a
+    // valid_policy other than anyPolicy. This is effectively the same process
+    // as used during policy tree intersection in RFC 5280 6.1.5.g.iii.1
+    der::Input root_policy;
+
+    // The same as RFC 5280's "valid_policy" variable.
+    der::Input valid_policy;
+
+    // The same as RFC 5280s "expected_policy_set" variable.
+    std::set<der::Input> expected_policy_set;
+
+    // Note that RFC 5280's "qualifier_set" is omitted.
+  };
+
+  // Level represents all the nodes at depth "i" in the valid_policy_tree.
+  using Level = std::vector<Node>;
+
+  // Initializes the ValidPolicyTree for the given "user_initial_policy_set".
+  //
+  // In RFC 5280, the valid_policy_tree is initialized to a root node at depth
+  // 0 of "anyPolicy"; the intersection with the "user_initial_policy_set" is
+  // done at the end (Wrap Up) as described in section 6.1.5 step g.
+  //
+  // Whereas in this implementation, the restriction on policies is added here,
+  // and intersecting the valid policy tree during Wrap Up is no longer needed.
+  //
+  // The final "user_constrained_policy_set" obtained will be the same. The
+  // advantages of this approach is simpler code.
+  void Init(const std::set<der::Input>& user_initial_policy_set) {
+    Clear();
+    for (const der::Input& policy_oid : user_initial_policy_set)
+      AddRootNode(policy_oid);
+  }
+
+  // Returns the current level (i.e. all nodes at depth i in the valid
+  // policy tree).
+  const Level& current_level() const { return current_level_; }
+  Level& current_level() { return current_level_; }
+
+  // In RFC 5280 valid_policy_tree may be set to null. That is represented here
+  // by emptiness.
+  bool IsNull() const { return current_level_.empty(); }
+  void SetNull() { Clear(); }
+
+  // This implementation keeps only the last level of the valid policy
+  // tree. Calling StartLevel() returns the nodes for the previous
+  // level, and starts a new level.
+  Level StartLevel() {
+    Level prev_level;
+    std::swap(prev_level, current_level_);
+    return prev_level;
+  }
+
+  // Gets the set of policies (in terms of root authority's policy domain) that
+  // are valid at the curent level of the policy tree.
+  //
+  // For example:
+  //
+  //  * If the valid policy tree was initialized with anyPolicy, then this
+  //    function returns what X.509 calls "authorities-constrained-policy-set".
+  //
+  //  * If the valid policy tree was instead initialized with the
+  //    "user-initial-policy_set", then this function returns what X.509
+  //    calls "user-constrained-policy-set"
+  //    ("authorities-constrained-policy-set" intersected with the
+  //    "user-initial-policy-set").
+  void GetValidRootPolicySet(std::set<der::Input>* policy_set) {
+    policy_set->clear();
+    for (const Node& node : current_level_)
+      policy_set->insert(node.root_policy);
+
+    // If the result includes anyPolicy, simplify it to a set of size 1.
+    if (policy_set->size() > 1 && SetContains(*policy_set, AnyPolicy()))
+      *policy_set = {AnyPolicy()};
+  }
+
+  // Adds a node |n| to the current level which is a child of |parent|
+  // such that:
+  //   * n.valid_policy = policy_oid
+  //   * n.expected_policy_set = {policy_oid}
+  void AddNode(const Node& parent, const der::Input& policy_oid) {
+    AddNodeWithExpectedPolicySet(parent, policy_oid, {policy_oid});
+  }
+
+  // Adds a node |n| to the current level which is a child of |parent|
+  // such that:
+  //   * n.valid_policy = policy_oid
+  //   * n.expected_policy_set = expected_policy_set
+  void AddNodeWithExpectedPolicySet(
+      const Node& parent,
+      const der::Input& policy_oid,
+      const std::set<der::Input>& expected_policy_set) {
+    Node new_node;
+    new_node.valid_policy = policy_oid;
+    new_node.expected_policy_set = expected_policy_set;
+
+    // Consider the root policy as the first policy other than anyPolicy (or
+    // anyPolicy if it hasn't been restricted yet).
+    new_node.root_policy =
+        (parent.root_policy == AnyPolicy()) ? policy_oid : parent.root_policy;
+
+    current_level_.push_back(std::move(new_node));
+  }
+
+  // Returns the first node having valid_policy == anyPolicy in |level|, or
+  // nullptr if there is none.
+  static const Node* FindAnyPolicyNode(const Level& level) {
+    for (const Node& node : level) {
+      if (node.valid_policy == AnyPolicy())
+        return &node;
+    }
+    return nullptr;
+  }
+
+  // Deletes all nodes |n| in |level| where |n.valid_policy| matches the given
+  // |valid_policy|. This may re-order the nodes in |level|.
+  static void DeleteNodesMatchingValidPolicy(const der::Input& valid_policy,
+                                             Level* level) {
+    // This works by swapping nodes to the end of the vector, and then doing a
+    // single resize to delete them all.
+    auto cur = level->begin();
+    auto end = level->end();
+    while (cur != end) {
+      bool should_delete_node = cur->valid_policy == valid_policy;
+      if (should_delete_node) {
+        end = std::prev(end);
+        std::iter_swap(cur, end);
+      } else {
+        ++cur;
+      }
+    }
+    level->erase(end, level->end());
+  }
+
+ private:
+  // Deletes all nodes in the valid policy tree.
+  void Clear() { current_level_.clear(); }
+
+  // Adds a node to the current level for OID |policy_oid|. The current level
+  // is assumed to be the root level.
+  void AddRootNode(const der::Input& policy_oid) {
+    Node new_node;
+    new_node.root_policy = policy_oid;
+    new_node.valid_policy = policy_oid;
+    new_node.expected_policy_set = {policy_oid};
+    current_level_.push_back(std::move(new_node));
+  }
+
+  Level current_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValidPolicyTree);
+};
+
+// Class that encapsulates the state variables used by certificate path
+// validation.
+class PathVerifier {
+ public:
+  // Same parameters and meaning as VerifyCertificateChain().
+  void Run(const ParsedCertificateList& certs,
+           const CertificateTrust& last_cert_trust,
+           const SignaturePolicy* signature_policy,
+           const der::GeneralizedTime& time,
+           KeyPurpose required_key_purpose,
+           InitialExplicitPolicy initial_explicit_policy,
+           const std::set<der::Input>& user_initial_policy_set,
+           InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+           InitialAnyPolicyInhibit initial_any_policy_inhibit,
+           std::set<der::Input>* user_constrained_policy_set,
+           CertPathErrors* errors);
+
+ private:
+  // Verifies and updates the valid policies. This corresponds with RFC 5280
+  // section 6.1.3 steps d-f.
+  void VerifyPolicies(const ParsedCertificate& cert,
+                      bool is_target_cert,
+                      CertErrors* errors);
+
+  // Applies the policy mappings. This corresponds with RFC 5280 section 6.1.4
+  // steps a-b.
+  void VerifyPolicyMappings(const ParsedCertificate& cert, CertErrors* errors);
+
+  // This function corresponds to RFC 5280 section 6.1.3's "Basic Certificate
+  // Processing" procedure.
+  void BasicCertificateProcessing(const ParsedCertificate& cert,
+                                  bool is_target_cert,
+                                  const SignaturePolicy* signature_policy,
+                                  const der::GeneralizedTime& time,
+                                  KeyPurpose required_key_purpose,
+                                  CertErrors* errors);
+
+  // This function corresponds to RFC 5280 section 6.1.4's "Preparation for
+  // Certificate i+1" procedure. |cert| is expected to be an intermediate.
+  void PrepareForNextCertificate(const ParsedCertificate& cert,
+                                 CertErrors* errors);
+
+  // This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up
+  // Procedure". It does processing for the final certificate (the target cert).
+  void WrapUp(const ParsedCertificate& cert, CertErrors* errors);
+
+  // Enforces trust anchor constraints compatibile with RFC 5937.
+  //
+  // Note that the anchor constraints are encoded via the attached certificate
+  // itself.
+  void ApplyTrustAnchorConstraints(const ParsedCertificate& cert,
+                                   KeyPurpose required_key_purpose,
+                                   CertErrors* errors);
+
+  // Initializes the path validation algorithm given anchor constraints. This
+  // follows the description in RFC 5937
+  void ProcessRootCertificate(const ParsedCertificate& cert,
+                              const CertificateTrust& trust,
+                              KeyPurpose required_key_purpose,
+                              CertErrors* errors);
+
+  ValidPolicyTree valid_policy_tree_;
+
+  // Will contain a NameConstraints for each previous cert in the chain which
+  // had nameConstraints. This corresponds to the permitted_subtrees and
+  // excluded_subtrees state variables from RFC 5280.
+  std::vector<const NameConstraints*> name_constraints_list_;
+
+  // |explicit_policy_| corresponds with the same named variable from RFC 5280
+  // section 6.1.2:
+  //
+  //   explicit_policy:  an integer that indicates if a non-NULL
+  //   valid_policy_tree is required.  The integer indicates the
+  //   number of non-self-issued certificates to be processed before
+  //   this requirement is imposed.  Once set, this variable may be
+  //   decreased, but may not be increased.  That is, if a certificate in the
+  //   path requires a non-NULL valid_policy_tree, a later certificate cannot
+  //   remove this requirement.  If initial-explicit-policy is set, then the
+  //   initial value is 0, otherwise the initial value is n+1.
+  size_t explicit_policy_;
+
+  // |inhibit_any_policy_| corresponds with the same named variable from RFC
+  // 5280 section 6.1.2:
+  //
+  //   inhibit_anyPolicy:  an integer that indicates whether the
+  //   anyPolicy policy identifier is considered a match.  The
+  //   integer indicates the number of non-self-issued certificates
+  //   to be processed before the anyPolicy OID, if asserted in a
+  //   certificate other than an intermediate self-issued
+  //   certificate, is ignored.  Once set, this variable may be
+  //   decreased, but may not be increased.  That is, if a
+  //   certificate in the path inhibits processing of anyPolicy, a
+  //   later certificate cannot permit it.  If initial-any-policy-
+  //   inhibit is set, then the initial value is 0, otherwise the
+  //   initial value is n+1.
+  size_t inhibit_any_policy_;
+
+  // |policy_mapping_| corresponds with the same named variable from RFC 5280
+  // section 6.1.2:
+  //
+  //   policy_mapping:  an integer that indicates if policy mapping
+  //   is permitted.  The integer indicates the number of non-self-
+  //   issued certificates to be processed before policy mapping is
+  //   inhibited.  Once set, this variable may be decreased, but may
+  //   not be increased.  That is, if a certificate in the path
+  //   specifies that policy mapping is not permitted, it cannot be
+  //   overridden by a later certificate.  If initial-policy-
+  //   mapping-inhibit is set, then the initial value is 0,
+  //   otherwise the initial value is n+1.
+  size_t policy_mapping_;
+
+  // |working_spki_| is an amalgamation of 3 separate variables from RFC 5280:
+  //    * working_public_key
+  //    * working_public_key_algorithm
+  //    * working_public_key_parameters
+  //
+  // They are combined for simplicity since the signature verification takes an
+  // SPKI, and the parameter inheritence is not applicable for the supported
+  // key types.
+  //
+  // An approximate explanation of |working_spki| is this description from RFC
+  // 5280 section 6.1.2:
+  //
+  //    working_public_key:  the public key used to verify the
+  //    signature of a certificate.
+  der::Input working_spki_;
+
+  // |working_normalized_issuer_name_| is the normalized value of the
+  // working_issuer_name variable in RFC 5280 section 6.1.2:
+  //
+  //    working_issuer_name:  the issuer distinguished name expected
+  //    in the next certificate in the chain.
+  der::Input working_normalized_issuer_name_;
+
+  // |max_path_length_| corresponds with the same named variable in RFC 5280
+  // section 6.1.2.
+  //
+  //    max_path_length:  this integer is initialized to n, is
+  //    decremented for each non-self-issued certificate in the path,
+  //    and may be reduced to the value in the path length constraint
+  //    field within the basic constraints extension of a CA
+  //    certificate.
+  size_t max_path_length_;
+};
+
+void PathVerifier::VerifyPolicies(const ParsedCertificate& cert,
+                                  bool is_target_cert,
+                                  CertErrors* errors) {
+  // From RFC 5280 section 6.1.3:
+  //
+  //  (d)  If the certificate policies extension is present in the
+  //       certificate and the valid_policy_tree is not NULL, process
+  //       the policy information by performing the following steps in
+  //       order:
+  if (cert.has_policy_oids() && !valid_policy_tree_.IsNull()) {
+    ValidPolicyTree::Level previous_level = valid_policy_tree_.StartLevel();
+
+    // Identify if there was a node with valid_policy == anyPolicy at depth i-1.
+    const ValidPolicyTree::Node* any_policy_node_prev_level =
+        ValidPolicyTree::FindAnyPolicyNode(previous_level);
+
+    //     (1)  For each policy P not equal to anyPolicy in the
+    //          certificate policies extension, let P-OID denote the OID
+    //          for policy P and P-Q denote the qualifier set for policy
+    //          P.  Perform the following steps in order:
+    bool cert_has_any_policy = false;
+    for (const der::Input& p_oid : cert.policy_oids()) {
+      if (p_oid == AnyPolicy()) {
+        cert_has_any_policy = true;
+        continue;
+      }
+
+      //        (i)   For each node of depth i-1 in the valid_policy_tree
+      //              where P-OID is in the expected_policy_set, create a
+      //              child node as follows: set the valid_policy to P-OID,
+      //              set the qualifier_set to P-Q, and set the
+      //              expected_policy_set to {P-OID}.
+      bool found_match = false;
+      for (const ValidPolicyTree::Node& prev_node : previous_level) {
+        if (SetContains(prev_node.expected_policy_set, p_oid)) {
+          valid_policy_tree_.AddNode(prev_node, p_oid);
+          found_match = true;
+        }
+      }
+
+      //        (ii)  If there was no match in step (i) and the
+      //              valid_policy_tree includes a node of depth i-1 with
+      //              the valid_policy anyPolicy, generate a child node with
+      //              the following values: set the valid_policy to P-OID,
+      //              set the qualifier_set to P-Q, and set the
+      //              expected_policy_set to  {P-OID}.
+      if (!found_match && any_policy_node_prev_level)
+        valid_policy_tree_.AddNode(*any_policy_node_prev_level, p_oid);
+    }
+
+    //     (2)  If the certificate policies extension includes the policy
+    //          anyPolicy with the qualifier set AP-Q and either (a)
+    //          inhibit_anyPolicy is greater than 0 or (b) i<n and the
+    //          certificate is self-issued, then:
+    //
+    //          For each node in the valid_policy_tree of depth i-1, for
+    //          each value in the expected_policy_set (including
+    //          anyPolicy) that does not appear in a child node, create a
+    //          child node with the following values: set the valid_policy
+    //          to the value from the expected_policy_set in the parent
+    //          node, set the qualifier_set to AP-Q, and set the
+    //          expected_policy_set to the value in the valid_policy from
+    //          this node.
+    if (cert_has_any_policy && ((inhibit_any_policy_ > 0) ||
+                                (!is_target_cert && IsSelfIssued(cert)))) {
+      // Keep track of the existing policies at depth i.
+      std::set<der::Input> child_node_policies;
+      for (const ValidPolicyTree::Node& node :
+           valid_policy_tree_.current_level())
+        child_node_policies.insert(node.valid_policy);
+
+      for (const ValidPolicyTree::Node& prev_node : previous_level) {
+        for (const der::Input& expected_policy :
+             prev_node.expected_policy_set) {
+          if (!SetContains(child_node_policies, expected_policy)) {
+            child_node_policies.insert(expected_policy);
+            valid_policy_tree_.AddNode(prev_node, expected_policy);
+          }
+        }
+      }
+    }
+
+    //     (3)  If there is a node in the valid_policy_tree of depth i-1
+    //          or less without any child nodes, delete that node.  Repeat
+    //          this step until there are no nodes of depth i-1 or less
+    //          without children.
+    //
+    // Nothing needs to be done for this step, since this implementation only
+    // stores the nodes at depth i, and the entire level has already been
+    // calculated.
+  }
+
+  //  (e)  If the certificate policies extension is not present, set the
+  //       valid_policy_tree to NULL.
+  if (!cert.has_policy_oids())
+    valid_policy_tree_.SetNull();
+
+  //  (f)  Verify that either explicit_policy is greater than 0 or the
+  //       valid_policy_tree is not equal to NULL;
+  if (!((explicit_policy_ > 0) || !valid_policy_tree_.IsNull()))
+    errors->AddError(kNoValidPolicy);
+}
+
+void PathVerifier::VerifyPolicyMappings(const ParsedCertificate& cert,
+                                        CertErrors* errors) {
+  if (!cert.has_policy_mappings())
+    return;
+
+  // From RFC 5280 section 6.1.4:
+  //
+  //  (a)  If a policy mappings extension is present, verify that the
+  //       special value anyPolicy does not appear as an
+  //       issuerDomainPolicy or a subjectDomainPolicy.
+  for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) {
+    if (mapping.issuer_domain_policy == AnyPolicy() ||
+        mapping.subject_domain_policy == AnyPolicy()) {
+      // Because this implementation continues processing certificates after
+      // this error, clear the valid policy tree to ensure the
+      // "user_constrained_policy_set" output upon failure is empty.
+      valid_policy_tree_.SetNull();
+      errors->AddError(kPolicyMappingAnyPolicy);
+    }
+  }
+
+  //  (b)  If a policy mappings extension is present, then for each
+  //       issuerDomainPolicy ID-P in the policy mappings extension:
+  //
+  //     (1)  If the policy_mapping variable is greater than 0, for each
+  //          node in the valid_policy_tree of depth i where ID-P is the
+  //          valid_policy, set expected_policy_set to the set of
+  //          subjectDomainPolicy values that are specified as
+  //          equivalent to ID-P by the policy mappings extension.
+  //
+  //          If no node of depth i in the valid_policy_tree has a
+  //          valid_policy of ID-P but there is a node of depth i with a
+  //          valid_policy of anyPolicy, then generate a child node of
+  //          the node of depth i-1 that has a valid_policy of anyPolicy
+  //          as follows:
+  //
+  //        (i)    set the valid_policy to ID-P;
+  //
+  //        (ii)   set the qualifier_set to the qualifier set of the
+  //               policy anyPolicy in the certificate policies
+  //               extension of certificate i; and
+  //
+  //        (iii)  set the expected_policy_set to the set of
+  //               subjectDomainPolicy values that are specified as
+  //               equivalent to ID-P by the policy mappings extension.
+  //
+  if (policy_mapping_ > 0) {
+    const ValidPolicyTree::Node* any_policy_node =
+        ValidPolicyTree::FindAnyPolicyNode(valid_policy_tree_.current_level());
+
+    // Group mappings by issuer domain policy.
+    std::map<der::Input, std::set<der::Input>> mappings;
+    for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) {
+      mappings[mapping.issuer_domain_policy].insert(
+          mapping.subject_domain_policy);
+    }
+
+    for (const auto& it : mappings) {
+      const der::Input& issuer_domain_policy = it.first;
+      const std::set<der::Input>& subject_domain_policies = it.second;
+      bool found_node = false;
+
+      for (ValidPolicyTree::Node& node : valid_policy_tree_.current_level()) {
+        if (node.valid_policy == issuer_domain_policy) {
+          node.expected_policy_set = subject_domain_policies;
+          found_node = true;
+        }
+      }
+
+      if (!found_node && any_policy_node) {
+        valid_policy_tree_.AddNodeWithExpectedPolicySet(
+            *any_policy_node, issuer_domain_policy, subject_domain_policies);
+      }
+    }
+  }
+
+  //  (b)  If a policy mappings extension is present, then for each
+  //       issuerDomainPolicy ID-P in the policy mappings extension:
+  //
+  //  ...
+  //
+  //     (2)  If the policy_mapping variable is equal to 0:
+  //
+  //        (i)    delete each node of depth i in the valid_policy_tree
+  //               where ID-P is the valid_policy.
+  //
+  //        (ii)   If there is a node in the valid_policy_tree of depth
+  //               i-1 or less without any child nodes, delete that
+  //               node.  Repeat this step until there are no nodes of
+  //               depth i-1 or less without children.
+  if (policy_mapping_ == 0) {
+    for (const ParsedPolicyMapping& mapping : cert.policy_mappings()) {
+      ValidPolicyTree::DeleteNodesMatchingValidPolicy(
+          mapping.issuer_domain_policy, &valid_policy_tree_.current_level());
+    }
+  }
+}
+
+void PathVerifier::BasicCertificateProcessing(
     const ParsedCertificate& cert,
     bool is_target_cert,
     const SignaturePolicy* signature_policy,
     const der::GeneralizedTime& time,
-    const der::Input& working_spki,
-    const der::Input& working_normalized_issuer_name,
-    const std::vector<const NameConstraints*>& name_constraints_list,
+    KeyPurpose required_key_purpose,
     CertErrors* errors) {
   // Check that the signature algorithms in Certificate vs TBSCertificate
   // match. This isn't part of RFC 5280 section 6.1.3, but is mandated by
@@ -235,7 +779,7 @@
   // Verify the digital signature using the previous certificate's key (RFC
   // 5280 section 6.1.3 step a.1).
   if (!VerifySignedData(cert.signature_algorithm(), cert.tbs_certificate_tlv(),
-                        cert.signature_value(), working_spki, signature_policy,
+                        cert.signature_value(), working_spki_, signature_policy,
                         errors)) {
     errors->AddError(kVerifySignedDataFailed);
   }
@@ -249,15 +793,15 @@
 
   // Verify the certificate's issuer name matches the issuing certificate's
   // subject name. (RFC 5280 section 6.1.3 step a.4)
-  if (cert.normalized_issuer() != working_normalized_issuer_name)
+  if (cert.normalized_issuer() != working_normalized_issuer_name_)
     errors->AddError(kSubjectDoesNotMatchIssuer);
 
   // Name constraints (RFC 5280 section 6.1.3 step b & c)
   // If certificate i is self-issued and it is not the final certificate in the
   // path, skip this step for certificate i.
-  if (!name_constraints_list.empty() &&
+  if (!name_constraints_list_.empty() &&
       (!IsSelfIssued(cert) || is_target_cert)) {
-    for (const NameConstraints* nc : name_constraints_list) {
+    for (const NameConstraints* nc : name_constraints_list_) {
       if (!nc->IsPermittedCert(cert.normalized_subject(),
                                cert.subject_alt_names())) {
         errors->AddError(kNotPermittedByNameConstraints);
@@ -265,31 +809,30 @@
     }
   }
 
-  // TODO(eroman): Steps d-f are omitted, as policy constraints are not yet
-  // implemented.
+  // RFC 5280 section 6.1.3 step d - f.
+  VerifyPolicies(cert, is_target_cert, errors);
+
+  // The key purpose is checked not just for the end-entity certificate, but
+  // also interpreted as a constraint when it appears in intermediates. This
+  // goes beyond what RFC 5280 describes, but is the de-facto standard. See
+  // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions
+  VerifyExtendedKeyUsage(cert, required_key_purpose, errors);
 }
 
-// This function corresponds to RFC 5280 section 6.1.4's "Preparation for
-// Certificate i+1" procedure. |cert| is expected to be an intermediate.
-void PrepareForNextCertificate(
-    const ParsedCertificate& cert,
-    size_t* max_path_length_ptr,
-    der::Input* working_spki,
-    der::Input* working_normalized_issuer_name,
-    std::vector<const NameConstraints*>* name_constraints_list,
-    CertErrors* errors) {
-  // TODO(crbug.com/634456): Steps a-b are omitted, as policy mappings are not
-  // yet implemented.
+void PathVerifier::PrepareForNextCertificate(const ParsedCertificate& cert,
+                                             CertErrors* errors) {
+  // RFC 5280 section 6.1.4 step a-b
+  VerifyPolicyMappings(cert, errors);
 
   // From RFC 5280 section 6.1.4 step c:
   //
   //    Assign the certificate subject name to working_normalized_issuer_name.
-  *working_normalized_issuer_name = cert.normalized_subject();
+  working_normalized_issuer_name_ = cert.normalized_subject();
 
   // From RFC 5280 section 6.1.4 step d:
   //
   //    Assign the certificate subjectPublicKey to working_public_key.
-  *working_spki = cert.tbs().spki_tlv;
+  working_spki_ = cert.tbs().spki_tlv;
 
   // Note that steps e and f are omitted as they are handled by
   // the assignment to |working_spki| above. See the definition
@@ -297,10 +840,53 @@
 
   // From RFC 5280 section 6.1.4 step g:
   if (cert.has_name_constraints())
-    name_constraints_list->push_back(&cert.name_constraints());
+    name_constraints_list_.push_back(&cert.name_constraints());
 
-  // TODO(eroman): Steps h-j are omitted as policy
-  // constraints/mappings/inhibitAnyPolicy are not yet implemented.
+  //     (h)  If certificate i is not self-issued:
+  if (!IsSelfIssued(cert)) {
+    //         (1)  If explicit_policy is not 0, decrement explicit_policy by
+    //              1.
+    if (explicit_policy_ > 0)
+      explicit_policy_ -= 1;
+
+    //         (2)  If policy_mapping is not 0, decrement policy_mapping by 1.
+    if (policy_mapping_ > 0)
+      policy_mapping_ -= 1;
+
+    //         (3)  If inhibit_anyPolicy is not 0, decrement inhibit_anyPolicy
+    //              by 1.
+    if (inhibit_any_policy_ > 0)
+      inhibit_any_policy_ -= 1;
+  }
+
+  //      (i)  If a policy constraints extension is included in the
+  //           certificate, modify the explicit_policy and policy_mapping
+  //           state variables as follows:
+  if (cert.has_policy_constraints()) {
+    //         (1)  If requireExplicitPolicy is present and is less than
+    //              explicit_policy, set explicit_policy to the value of
+    //              requireExplicitPolicy.
+    if (cert.policy_constraints().has_require_explicit_policy &&
+        cert.policy_constraints().require_explicit_policy < explicit_policy_) {
+      explicit_policy_ = cert.policy_constraints().require_explicit_policy;
+    }
+
+    //         (2)  If inhibitPolicyMapping is present and is less than
+    //              policy_mapping, set policy_mapping to the value of
+    //              inhibitPolicyMapping.
+    if (cert.policy_constraints().has_inhibit_policy_mapping &&
+        cert.policy_constraints().inhibit_policy_mapping < policy_mapping_) {
+      policy_mapping_ = cert.policy_constraints().inhibit_policy_mapping;
+    }
+  }
+
+  //      (j)  If the inhibitAnyPolicy extension is included in the
+  //           certificate and is less than inhibit_anyPolicy, set
+  //           inhibit_anyPolicy to the value of inhibitAnyPolicy.
+  if (cert.has_inhibit_any_policy() &&
+      cert.inhibit_any_policy() < inhibit_any_policy_) {
+    inhibit_any_policy_ = cert.inhibit_any_policy();
+  }
 
   // From RFC 5280 section 6.1.4 step k:
   //
@@ -327,10 +913,10 @@
   //    max_path_length is greater than zero and decrement
   //    max_path_length by 1.
   if (!IsSelfIssued(cert)) {
-    if (*max_path_length_ptr == 0) {
+    if (max_path_length_ == 0) {
       errors->AddError(kMaxPathLengthViolated);
     } else {
-      --(*max_path_length_ptr);
+      --max_path_length_;
     }
   }
 
@@ -340,8 +926,8 @@
   //    less than max_path_length, set max_path_length to the value
   //    of pathLenConstraint.
   if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len &&
-      cert.basic_constraints().path_len < *max_path_length_ptr) {
-    *max_path_length_ptr = cert.basic_constraints().path_len;
+      cert.basic_constraints().path_len < max_path_length_) {
+    max_path_length_ = cert.basic_constraints().path_len;
   }
 
   // From RFC 5280 section 6.1.4 step n:
@@ -408,13 +994,22 @@
   }
 }
 
-// This function corresponds with RFC 5280 section 6.1.5's "Wrap-Up Procedure".
-// It does processing for the final certificate (the target cert).
-void WrapUp(const ParsedCertificate& cert, CertErrors* errors) {
-  // TODO(crbug.com/634452): Steps a-b are omitted as policy constraints are not
-  // yet implemented.
+void PathVerifier::WrapUp(const ParsedCertificate& cert, CertErrors* errors) {
+  // From RFC 5280 section 6.1.5:
+  //      (a)  If explicit_policy is not 0, decrement explicit_policy by 1.
+  if (explicit_policy_ > 0)
+    explicit_policy_ -= 1;
 
-  // Note step c-e are omitted the verification function does
+  //      (b)  If a policy constraints extension is included in the
+  //           certificate and requireExplicitPolicy is present and has a
+  //           value of 0, set the explicit_policy state variable to 0.
+  if (cert.has_policy_constraints() &&
+      cert.policy_constraints().has_require_explicit_policy &&
+      cert.policy_constraints().require_explicit_policy == 0) {
+    explicit_policy_ = 0;
+  }
+
+  // Note step c-e are omitted as the verification function does
   // not output the working public key.
 
   // From RFC 5280 section 6.1.5 step f:
@@ -428,24 +1023,24 @@
   // directly match the procedures in RFC 5280's section 6.1.
   VerifyNoUnconsumedCriticalExtensions(cert, errors);
 
-  // TODO(eroman): Step g is omitted, as policy constraints are not yet
-  // implemented.
+  // RFC 5280 section 6.1.5 step g is skipped, as the intersection of valid
+  // policies was computed during previous steps.
+  //
+  //    If either (1) the value of explicit_policy variable is greater than
+  //    zero or (2) the valid_policy_tree is not NULL, then path processing
+  //   has succeeded.
+  if (!(explicit_policy_ > 0 || !valid_policy_tree_.IsNull())) {
+    errors->AddError(kNoValidPolicy);
+  }
 
   // The following check is NOT part of RFC 5280 6.1.5's "Wrap-Up Procedure",
   // however is implied by RFC 5280 section 4.2.1.9.
   VerifyTargetCertHasConsistentCaBits(cert, errors);
 }
 
-// Enforces trust anchor constraints compatibile with RFC 5937.
-//
-// Note that the anchor constraints are encoded via the attached certificate
-// itself.
-void ApplyTrustAnchorConstraints(
-    const ParsedCertificate& cert,
-    KeyPurpose required_key_purpose,
-    size_t* max_path_length_ptr,
-    std::vector<const NameConstraints*>* name_constraints_list,
-    CertErrors* errors) {
+void PathVerifier::ApplyTrustAnchorConstraints(const ParsedCertificate& cert,
+                                               KeyPurpose required_key_purpose,
+                                               CertErrors* errors) {
   // This is not part of RFC 5937 nor RFC 5280, but matches the EKU handling
   // done for intermediates (described in Web PKI's Baseline Requirements).
   VerifyExtendedKeyUsage(cert, required_key_purpose, errors);
@@ -454,7 +1049,7 @@
 
   // Initialize name constraints initial-permitted/excluded-subtrees.
   if (cert.has_name_constraints())
-    name_constraints_list->push_back(&cert.name_constraints());
+    name_constraints_list_.push_back(&cert.name_constraints());
 
   // TODO(eroman): Initialize user-initial-policy-set based on anchor
   // constraints.
@@ -477,7 +1072,7 @@
   // NOTE: RFC 5937 does not say to enforce the CA=true part of basic
   // constraints.
   if (cert.has_basic_constraints() && cert.basic_constraints().has_path_len)
-    *max_path_length_ptr = cert.basic_constraints().path_len;
+    max_path_length_ = cert.basic_constraints().path_len;
 
   // From RFC 5937 section 2:
   //
@@ -487,22 +1082,15 @@
   VerifyNoUnconsumedCriticalExtensions(cert, errors);
 }
 
-// Initializes the path validation algorithm given anchor constraints. This
-// follows the description in RFC 5937
-void ProcessRootCertificate(
-    const ParsedCertificate& cert,
-    const CertificateTrust& trust,
-    KeyPurpose required_key_purpose,
-    size_t* max_path_length_ptr,
-    std::vector<const NameConstraints*>* name_constraints_list,
-    der::Input* working_spki,
-    der::Input* working_normalized_issuer_name,
-    CertErrors* errors) {
+void PathVerifier::ProcessRootCertificate(const ParsedCertificate& cert,
+                                          const CertificateTrust& trust,
+                                          KeyPurpose required_key_purpose,
+                                          CertErrors* errors) {
   // Use the certificate's SPKI and subject when verifying the next certificate.
   // Note this is initialized even in the case of untrusted roots (they already
   // emit an error for the distrust).
-  *working_spki = cert.tbs().spki_tlv;
-  *working_normalized_issuer_name = cert.normalized_subject();
+  working_spki_ = cert.tbs().spki_tlv;
+  working_normalized_issuer_name_ = cert.normalized_subject();
 
   switch (trust.type) {
     case CertificateTrustType::UNSPECIFIED:
@@ -517,24 +1105,26 @@
     case CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS:
       // If the trust anchor has constraints, enforce them.
       if (trust.type == CertificateTrustType::TRUSTED_ANCHOR_WITH_CONSTRAINTS) {
-        ApplyTrustAnchorConstraints(cert, required_key_purpose,
-                                    max_path_length_ptr, name_constraints_list,
-                                    errors);
+        ApplyTrustAnchorConstraints(cert, required_key_purpose, errors);
       }
       break;
   }
 }
 
-}  // namespace
-
-// This implementation is structured to mimic the description of certificate
-// path verification given by RFC 5280 section 6.1.
-void VerifyCertificateChain(const ParsedCertificateList& certs,
-                            const CertificateTrust& last_cert_trust,
-                            const SignaturePolicy* signature_policy,
-                            const der::GeneralizedTime& time,
-                            KeyPurpose required_key_purpose,
-                            CertPathErrors* errors) {
+void PathVerifier::Run(
+    const ParsedCertificateList& certs,
+    const CertificateTrust& last_cert_trust,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time,
+    KeyPurpose required_key_purpose,
+    InitialExplicitPolicy initial_explicit_policy,
+    const std::set<der::Input>& user_initial_policy_set,
+    InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+    InitialAnyPolicyInhibit initial_any_policy_inhibit,
+    std::set<der::Input>* user_constrained_policy_set,
+    CertPathErrors* errors) {
+  // This implementation is structured to mimic the description of certificate
+  // path verification given by RFC 5280 section 6.1.
   DCHECK(signature_policy);
   DCHECK(errors);
 
@@ -551,50 +1141,48 @@
     return;
   }
 
-  // Will contain a NameConstraints for each previous cert in the chain which
-  // had nameConstraints. This corresponds to the permitted_subtrees and
-  // excluded_subtrees state variables from RFC 5280.
-  std::vector<const NameConstraints*> name_constraints_list;
+  // RFC 5280's "n" variable is the length of the path, which does not count
+  // the trust anchor. (Although in practice it doesn't really change behaviors
+  // if n is used in place of n+1).
+  const size_t n = certs.size() - 1;
 
-  // |working_spki| is an amalgamation of 3 separate variables from RFC 5280:
-  //    * working_public_key
-  //    * working_public_key_algorithm
-  //    * working_public_key_parameters
-  //
-  // They are combined for simplicity since the signature verification takes an
-  // SPKI, and the parameter inheritence is not applicable for the supported
-  // key types.
-  //
-  // An approximate explanation of |working_spki| is this description from RFC
-  // 5280 section 6.1.2:
-  //
-  //    working_public_key:  the public key used to verify the
-  //    signature of a certificate.
-  der::Input working_spki;
+  valid_policy_tree_.Init(user_initial_policy_set);
 
-  // |working_normalized_issuer_name| is the normalized value of the
-  // working_issuer_name variable in RFC 5280 section 6.1.2:
+  // RFC 5280 section section 6.1.2:
   //
-  //    working_issuer_name:  the issuer distinguished name expected
-  //    in the next certificate in the chain.
-  der::Input working_normalized_issuer_name;
+  // If initial-explicit-policy is set, then the initial value
+  // [of explicit_policy] is 0, otherwise the initial value is n+1.
+  explicit_policy_ =
+      initial_explicit_policy == InitialExplicitPolicy::kTrue ? 0 : n + 1;
 
-  // |max_path_length| corresponds with the same named variable in RFC 5280
-  // section 6.1.2:
+  // RFC 5280 section section 6.1.2:
   //
-  //    max_path_length:  this integer is initialized to n, is
-  //    decremented for each non-self-issued certificate in the path,
-  //    and may be reduced to the value in the path length constraint
-  //    field within the basic constraints extension of a CA
-  //    certificate.
-  size_t max_path_length = certs.size();
+  // If initial-any-policy-inhibit is set, then the initial value
+  // [of inhibit_anyPolicy] is 0, otherwise the initial value is n+1.
+  inhibit_any_policy_ =
+      initial_any_policy_inhibit == InitialAnyPolicyInhibit::kTrue ? 0 : n + 1;
+
+  // RFC 5280 section section 6.1.2:
+  //
+  // If initial-policy-mapping-inhibit is set, then the initial value
+  // [of policy_mapping] is 0, otherwise the initial value is n+1.
+  policy_mapping_ =
+      initial_policy_mapping_inhibit == InitialPolicyMappingInhibit::kTrue
+          ? 0
+          : n + 1;
+
+  // RFC 5280 section section 6.1.2:
+  //
+  // max_path_length:  this integer is initialized to n, ...
+  max_path_length_ = n;
 
   // Iterate over all the certificates in the reverse direction: starting from
   // the root certificate and progressing towards the target certificate.
   //
-  //   * i=0               :  Root certificate (i.e. trust anchor)
-  //   * i=1               :  Certificated signed by the root certificate
-  //   * i=certs.size()-1  :  Target certificate.
+  //   * i=0  :  Root certificate (i.e. trust anchor)
+  //   * i=1  :  Certificate issued by root
+  //   * i=x  :  Certificate i=x is issued by certificate i=x-1
+  //   * i=n  :  Target certificate.
   for (size_t i = 0; i < certs.size(); ++i) {
     const size_t index_into_certs = certs.size() - i - 1;
 
@@ -612,8 +1200,6 @@
 
     if (is_root_cert) {
       ProcessRootCertificate(cert, last_cert_trust, required_key_purpose,
-                             &max_path_length, &name_constraints_list,
-                             &working_spki, &working_normalized_issuer_name,
                              cert_errors);
 
       // Don't do any other checks for root certificates.
@@ -626,28 +1212,45 @@
     //     - Then run "Wrap up"
     //     - Otherwise run "Prepare for Next cert"
     BasicCertificateProcessing(cert, is_target_cert, signature_policy, time,
-                               working_spki, working_normalized_issuer_name,
-                               name_constraints_list, cert_errors);
-
-    // The key purpose is checked not just for the end-entity certificate, but
-    // also interpreted as a constraint when it appears in intermediates. This
-    // goes beyond what RFC 5280 describes, but is the de-facto standard. See
-    // https://wiki.mozilla.org/CA:CertificatePolicyV2.1#Frequently_Asked_Questions
-    VerifyExtendedKeyUsage(cert, required_key_purpose, cert_errors);
-
+                               required_key_purpose, cert_errors);
     if (!is_target_cert) {
-      PrepareForNextCertificate(cert, &max_path_length, &working_spki,
-                                &working_normalized_issuer_name,
-                                &name_constraints_list, cert_errors);
+      PrepareForNextCertificate(cert, cert_errors);
     } else {
       WrapUp(cert, cert_errors);
     }
   }
 
+  if (user_constrained_policy_set) {
+    // valid_policy_tree_ already contains the intersection of valid policies
+    // with user_initial_policy_set.
+    valid_policy_tree_.GetValidRootPolicySet(user_constrained_policy_set);
+  }
+
   // TODO(eroman): RFC 5280 forbids duplicate certificates per section 6.1:
   //
   //    A certificate MUST NOT appear more than once in a prospective
   //    certification path.
 }
 
+}  // namespace
+
+void VerifyCertificateChain(
+    const ParsedCertificateList& certs,
+    const CertificateTrust& last_cert_trust,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time,
+    KeyPurpose required_key_purpose,
+    InitialExplicitPolicy initial_explicit_policy,
+    const std::set<der::Input>& user_initial_policy_set,
+    InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+    InitialAnyPolicyInhibit initial_any_policy_inhibit,
+    std::set<der::Input>* user_constrained_policy_set,
+    CertPathErrors* errors) {
+  PathVerifier verifier;
+  verifier.Run(certs, last_cert_trust, signature_policy, time,
+               required_key_purpose, initial_explicit_policy,
+               user_initial_policy_set, initial_policy_mapping_inhibit,
+               initial_any_policy_inhibit, user_constrained_policy_set, errors);
+}
+
 }  // namespace net
diff --git a/net/cert/internal/verify_certificate_chain.h b/net/cert/internal/verify_certificate_chain.h
index 8d1f044..a8b2917 100644
--- a/net/cert/internal/verify_certificate_chain.h
+++ b/net/cert/internal/verify_certificate_chain.h
@@ -5,7 +5,7 @@
 #ifndef NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_
 #define NET_CERT_INTERNAL_VERIFY_CERTIFICATE_CHAIN_H_
 
-#include <vector>
+#include <set>
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
@@ -30,72 +30,160 @@
   CLIENT_AUTH,
 };
 
+enum class InitialExplicitPolicy {
+  kFalse,
+  kTrue,
+};
+
+enum class InitialPolicyMappingInhibit {
+  kFalse,
+  kTrue,
+};
+
+enum class InitialAnyPolicyInhibit {
+  kFalse,
+  kTrue,
+};
+
 // VerifyCertificateChain() verifies an ordered certificate path in accordance
-// with RFC 5280 (with some modifications [1]).
+// with RFC 5280's "Certification Path Validation" algorithm (section 6).
 //
-// [1] Deviations from RFC 5280:
+// -----------------------------------------
+// Deviations from RFC 5280
+// -----------------------------------------
 //
-//   * If Extended Key Usage appears on intermediates it is treated as a
-//     restriction on subordinate certificates.
+//   * If Extended Key Usage appears on intermediates, it is treated as
+//     a restriction on subordinate certificates.
 //
-// The caller is responsible for additionally checking:
+// -----------------------------------------
+// Additional responsibilities of the caller
+// -----------------------------------------
+//
+// After successful path verification, the caller is responsible for
+// subsequently checking:
 //
 //  * The end-entity's KeyUsage before using its SPKI.
-//  * The end-entity's name/subjectAltName (note that name constraints from
-//    intermediates will have already been applied, so just need to check
-//    the end-entity for a match).
-//  * Policies
-//
-// WARNING: This implementation is in progress, and is currently incomplete.
-// Consult an OWNER before using it.
-//
-// TODO(eroman): Take a CertPath instead of ParsedCertificateList +
-//               TrustAnchor.
+//  * The end-entity's name/subjectAltName. Name constraints from intermediates
+//    will have already been applied, so it is sufficient to check the
+//    end-entity for a match.
 //
 // ---------
 // Inputs
 // ---------
 //
-//   cert_chain:
-//     A non-empty chain of N DER-encoded certificates, listed in the
-//     "forward" direction. The first certificate is the target certificate to
-//     verify, and the last certificate has trustedness given by
-//     |last_cert_trust|.
+//   certs:
+//     A non-empty chain of DER-encoded certificates, listed in the
+//     "forward" direction. The first certificate is the target
+//     certificate to verify, and the last certificate has trustedness
+//     given by |last_cert_trust| (generally a trust anchor).
 //
-//      * cert_chain[0] is the target certificate to verify.
-//      * cert_chain[i+1] holds the certificate that issued cert_chain[i].
-//      * cert_chain[N-1] the root certificate
+//      * certs[0] is the target certificate to verify.
+//      * certs[i+1] holds the certificate that issued cert_chain[i].
+//      * certs[N-1] the root certificate
+//
+//     Note that THIS IS NOT identical in meaning to the same named
+//     "certs" input defined in RFC 5280 section 6.1.1.a. The differences
+//     are:
+//
+//      * The order of certificates is reversed
+//      * In RFC 5280 "certs" DOES NOT include the trust anchor
 //
 //   last_cert_trust:
-//     Trustedness of certs.back(). The trustedness of certs.back() MUST BE
-//     decided by the caller -- this function takes it purely as an input.
-//     Moreover, the CertificateTrust can be used to specify trust anchor
-//     constraints [1]
+//     Trustedness of |certs.back()|. The trustedness of |certs.back()|
+//     MUST BE decided by the caller -- this function takes it purely as
+//     an input. Moreover, the CertificateTrust can be used to specify
+//     trust anchor constraints.
+//
+//     This combined with |certs.back()| (the root certificate) fills a
+//     similar role to "trust anchor information" defined in RFC 5280
+//     section 6.1.1.d.
 //
 //   signature_policy:
 //     The policy to use when verifying signatures (what hash algorithms are
 //     allowed, what length keys, what named curves, etc).
 //
 //   time:
-//     The UTC time to use for expiration checks.
+//     The UTC time to use for expiration checks. This is equivalent to
+//     the input from RFC 5280 section 6.1.1:
 //
-//   key_purpose:
+//       (b)  the current date/time.
+//
+//   required_key_purpose:
 //     The key purpose that the target certificate needs to be valid for.
 //
+//   user_initial_policy_set:
+//     This is equivalent to the same named input in RFC 5280 section
+//     6.1.1:
+//
+//       (c)  user-initial-policy-set: A set of certificate policy
+//            identifiers naming the policies that are acceptable to the
+//            certificate user. The user-initial-policy-set contains the
+//            special value any-policy if the user is not concerned about
+//            certificate policy.
+//
+//   initial_policy_mapping_inhibit:
+//     This is equivalent to the same named input in RFC 5280 section
+//     6.1.1:
+//
+//       (e)  initial-policy-mapping-inhibit, which indicates if policy
+//            mapping is allowed in the certification path.
+//
+//   initial_explicit_policy:
+//     This is equivalent to the same named input in RFC 5280 section
+//     6.1.1:
+//
+//       (f)  initial-explicit-policy, which indicates if the path must be
+//            valid for at least one of the certificate policies in the
+//            user-initial-policy-set.
+//
+//   initial_any_policy_inhibit:
+//     This is equivalent to the same named input in RFC 5280 section
+//     6.1.1:
+//
+//       (g)  initial-any-policy-inhibit, which indicates whether the
+//            anyPolicy OID should be processed if it is included in a
+//            certificate.
+//
 // ---------
 // Outputs
 // ---------
+//
+//   user_constrained_policy_set:
+//     Can be null. If non-null, |user_constrained_policy_set| will be filled
+//     with the matching policies (intersected with user_initial_policy_set).
+//     This is equivalent to the same named output in X.509 section 10.2.
+//     Note that it is OK for this to point to input user_initial_policy_set.
+//
 //   errors:
 //     Must be non-null. The set of errors/warnings encountered while
 //     validating the path are appended to this structure. If verification
 //     failed, then there is guaranteed to be at least 1 high severity error
 //     written to |errors|.
 //
-// [1] Conceptually VerifyCertificateChain() sets RFC 5937's
-// "enforceTrustAnchorConstraints" to true. And one specifies whether to
-// interpret a root certificate as having trust anchor constraints through the
-// |last_cert_trust| parameter. The constraints are just a subset of the
-// extensions present in the certificate:
+// -------------------------
+// Trust Anchor constraints
+// -------------------------
+//
+// Conceptually, VerifyCertificateChain() sets RFC 5937's
+// "enforceTrustAnchorConstraints" to true.
+//
+// One specifies trust anchor constraints using the |last_cert_trust|
+// parameter in conjunction with extensions appearing in |certs.back()|.
+//
+// The trust anchor |certs.back()| is always passed as a certificate to
+// this function, however the manner in which that certificate is
+// interpreted depends on |last_cert_trust|:
+//
+// TRUSTED_ANCHOR:
+//
+// No properties from the root certificate, other than its Subject and
+// SPKI, are checked during verification. This is the usual
+// interpretation for a "trust anchor".
+//
+// TRUSTED_ANCHOR_WITH_CONSTRAINTS:
+//
+// Only a subset of extensions and properties from the certificate are checked,
+// as described by RFC 5937.
 //
 //  * Signature:             No
 //  * Validity (expiration): No
@@ -104,17 +192,24 @@
 //  * Basic constraints:     Yes, but only the pathlen (CA=false is accepted)
 //  * Name constraints:      Yes
 //  * Certificate policies:  Not currently, TODO(crbug.com/634453)
+//  * Policy Mappings:       No
 //  * inhibitAnyPolicy:      Not currently, TODO(crbug.com/634453)
 //  * PolicyConstraints:     Not currently, TODO(crbug.com/634452)
 //
 // The presence of any other unrecognized extension marked as critical fails
 // validation.
-NET_EXPORT void VerifyCertificateChain(const ParsedCertificateList& certs,
-                                       const CertificateTrust& last_cert_trust,
-                                       const SignaturePolicy* signature_policy,
-                                       const der::GeneralizedTime& time,
-                                       KeyPurpose required_key_purpose,
-                                       CertPathErrors* errors);
+NET_EXPORT void VerifyCertificateChain(
+    const ParsedCertificateList& certs,
+    const CertificateTrust& last_cert_trust,
+    const SignaturePolicy* signature_policy,
+    const der::GeneralizedTime& time,
+    KeyPurpose required_key_purpose,
+    InitialExplicitPolicy initial_explicit_policy,
+    const std::set<der::Input>& user_initial_policy_set,
+    InitialPolicyMappingInhibit initial_policy_mapping_inhibit,
+    InitialAnyPolicyInhibit initial_any_policy_inhibit,
+    std::set<der::Input>* user_constrained_policy_set,
+    CertPathErrors* errors);
 
 // TODO(crbug.com/634443): Move exported errors to a central location?
 extern CertErrorId kValidityFailedNotAfter;
diff --git a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
index 8138dae9..f86e1e9e 100644
--- a/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_pkits_unittest.cc
@@ -67,12 +67,19 @@
 
     SimpleSignaturePolicy signature_policy(1024);
 
+    std::set<der::Input> user_constrained_policy_set;
+
     CertPathErrors path_errors;
-    VerifyCertificateChain(input_chain, CertificateTrust::ForTrustAnchor(),
-                           &signature_policy, info.time, KeyPurpose::ANY_EKU,
-                           &path_errors);
+    VerifyCertificateChain(
+        input_chain, CertificateTrust::ForTrustAnchor(), &signature_policy,
+        info.time, KeyPurpose::ANY_EKU, info.initial_explicit_policy,
+        info.initial_policy_set, info.initial_policy_mapping_inhibit,
+        info.initial_inhibit_any_policy, &user_constrained_policy_set,
+        &path_errors);
     bool did_succeed = !path_errors.ContainsHighSeverityErrors();
 
+    EXPECT_EQ(info.user_constrained_policy_set, user_constrained_policy_set);
+
     //  TODO(crbug.com/634443): Test errors on failure?
     if (info.should_validate != did_succeed) {
       ASSERT_EQ(info.should_validate, did_succeed)
@@ -222,6 +229,21 @@
                               PkitsTest07KeyUsage,
                               VerifyCertificateChainPkitsTestDelegate);
 INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+                              PkitsTest08CertificatePolicies,
+                              VerifyCertificateChainPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+                              PkitsTest09RequireExplicitPolicy,
+                              VerifyCertificateChainPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+                              PkitsTest10PolicyMappings,
+                              VerifyCertificateChainPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+                              PkitsTest11InhibitPolicyMapping,
+                              VerifyCertificateChainPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
+                              PkitsTest12InhibitAnyPolicy,
+                              VerifyCertificateChainPkitsTestDelegate);
+INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
                               PkitsTest13NameConstraints,
                               VerifyCertificateChainPkitsTestDelegate);
 INSTANTIATE_TYPED_TEST_CASE_P(VerifyCertificateChain,
@@ -232,8 +254,4 @@
 // PkitsTest05VerifyingPathswithSelfIssuedCertificates,
 // PkitsTest14DistributionPoints, PkitsTest15DeltaCRLs
 
-// TODO(mattm): Certificate Policies support: PkitsTest08CertificatePolicies,
-// PkitsTest09RequireExplicitPolicy PkitsTest10PolicyMappings,
-// PkitsTest11InhibitPolicyMapping, PkitsTest12InhibitAnyPolicy
-
 }  // namespace net
diff --git a/net/cert/internal/verify_certificate_chain_unittest.cc b/net/cert/internal/verify_certificate_chain_unittest.cc
index 13c689f..82851d0 100644
--- a/net/cert/internal/verify_certificate_chain_unittest.cc
+++ b/net/cert/internal/verify_certificate_chain_unittest.cc
@@ -19,8 +19,13 @@
     SimpleSignaturePolicy signature_policy(1024);
 
     CertPathErrors errors;
-    VerifyCertificateChain(test.chain, test.last_cert_trust, &signature_policy,
-                           test.time, test.key_purpose, &errors);
+    // TODO(eroman): Check user_constrained_policy_set.
+    VerifyCertificateChain(
+        test.chain, test.last_cert_trust, &signature_policy, test.time,
+        test.key_purpose, test.initial_explicit_policy,
+        test.user_initial_policy_set, test.initial_policy_mapping_inhibit,
+        test.initial_any_policy_inhibit,
+        nullptr /*user_constrained_policy_set*/, &errors);
     EXPECT_EQ(test.expected_errors, errors.ToDebugString(test.chain))
         << "Test file: " << test_file_path;
   }
diff --git a/net/third_party/nist-pkits/generate_tests.py b/net/third_party/nist-pkits/generate_tests.py
index 04afc6f8..8083d62a 100644
--- a/net/third_party/nist-pkits/generate_tests.py
+++ b/net/third_party/nist-pkits/generate_tests.py
@@ -688,6 +688,17 @@
              user_constrained_policy_set=[]),
   ],
 
+  '4.10.7': [ # Invalid Mapping From anyPolicy Test7 
+    # Procedure: Validate Invalid Mapping From anyPolicy Test7 EE using the
+    # default settings or open and verify Signed Test Message 6.2.2.100 using
+    # the default settings.
+    #
+    # Expected Result: The path should not validate successfully since the
+    # intermediate certificate includes a policy mapping extension in which
+    # anyPolicy appears as an issuerDomainPolicy. 
+    TestInfo(False, user_constrained_policy_set=[]),
+  ],
+
   '4.10.8': [ # Invalid Mapping To anyPolicy Test8
     # Procedure: Validate Invalid Mapping To anyPolicy Test8 EE using the
     # default settings or open and verify Signed Test Message 6.2.2.101 using
@@ -696,8 +707,6 @@
     # Expected Result: The path should not validate successfully since the
     # intermediate certificate includes a policy mapping extension in which
     # anyPolicy appears as an subjectDomainPolicy.
-    #
-    # TODO(eroman): What should user_constrained_policy_set be?
     TestInfo(False, user_constrained_policy_set=[]),
   ],
 
diff --git a/net/third_party/nist-pkits/pkits_testcases-inl.h b/net/third_party/nist-pkits/pkits_testcases-inl.h
index d4b709d..8ddf7c6 100644
--- a/net/third_party/nist-pkits/pkits_testcases-inl.h
+++ b/net/third_party/nist-pkits/pkits_testcases-inl.h
@@ -2113,6 +2113,7 @@
                               "MappingFromanyPolicyCACRL"};
   PkitsTestInfo info;
   info.should_validate = false;
+  info.SetUserConstrainedPolicySet("");
 
   this->RunTest(certs, crls, info);
 }
diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc
index 2f9c9315..02e54f9 100644
--- a/remoting/client/plugin/pepper_input_handler.cc
+++ b/remoting/client/plugin/pepper_input_handler.cc
@@ -97,7 +97,8 @@
   } else if (dom_code == "OSRight") {
     dom_code = "MetaRight";
   }
-  key_event.set_usb_keycode(ui::KeycodeConverter::CodeToUsbKeycode(dom_code));
+  key_event.set_usb_keycode(
+      ui::KeycodeConverter::CodeStringToUsbKeycode(dom_code));
   key_event.set_pressed(pp_key_event.GetType() == PP_INPUTEVENT_TYPE_KEYDOWN);
   key_event.set_lock_states(MakeLockStates(pp_key_event));
   return key_event;
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index efe5829..7ca6cfa 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -326,8 +326,10 @@
 Bug(none) compositing/overflow/nested-scrolling.html [ Failure ]
 Bug(none) compositing/overflow/opt-in-if-composited.html [ Failure ]
 Bug(none) compositing/overflow/overflow-compositing-descendant.html [ Failure ]
+Bug(none) compositing/overflow/overflow-scroll-background-fractional-offset.html [ Failure ]
 Bug(none) compositing/overflow/overflow-scroll-background-opaque-to-transparent.html [ Failure ]
 Bug(none) compositing/overflow/overflow-scroll-background-transparent-to-opaque.html [ Failure ]
+Bug(none) compositing/overflow/overflow-scroll-content-fractional-offset.html [ Failure ]
 Bug(none) compositing/overflow/overflow-scroll-with-opaque-background-will-change.html [ Failure ]
 Bug(none) compositing/overflow/overflow-scroll-with-opaque-background.html [ Failure ]
 Bug(none) compositing/overflow/overflow-scroll-with-pointer-events-toggle.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 9045e0d5..8cfa388 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2996,3 +2996,6 @@
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Failure Timeout Crash ]
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-worker-to-main.html [ Pass Failure Timeout Crash ]
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/request-animation-frame.html [ Pass Failure Timeout Crash ]
+
+crbug.com/728895 [ Win7 Debug ] fast/table/backgr_border-table-column-group-collapsed-border.html [ Failure ]
+crbug.com/728895 [ Win7 Debug ] virtual/mojo-loading/fast/table/backgr_border-table-column-group-collapsed-border.html [ Failure ]
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset-expected.html
new file mode 100644
index 0000000..64d5f30b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset-expected.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<style>
+.layout-container {
+  width: 210px;
+  position: relative;
+}
+.position-container {
+  position: relative;
+  width: 202px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#overflow {
+  background: #0f0;
+  width: 50%;
+  height: 100px;
+  overflow: scroll;
+  position: absolute;
+}
+
+.spacer {
+  height: 2000px;
+}
+</style>
+
+<body>
+  <div class="layout-container">
+  <div class="position-container">
+    <div id="overflow">
+      <div class="spacer">
+      </div>
+    </div>
+  </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset.html
new file mode 100644
index 0000000..233fb97
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-background-fractional-offset.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<style>
+.layout-container {
+  width: 210px;
+  position: relative;
+}
+.position-container {
+  position: relative;
+  width: 203px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#overflow {
+  width: 50%;
+  height: 100px;
+  overflow: scroll;
+  position: absolute;
+  background: #0f0;
+  will-change: transform;
+}
+
+.spacer {
+  height: 2000px;
+}
+</style>
+
+<body>
+  <div class="layout-container">
+  <div class="position-container">
+    <div id="overflow">
+      <div class="spacer">
+      </div>
+    </div>
+  </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset-expected.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset-expected.html
new file mode 100644
index 0000000..0634bea
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset-expected.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<style>
+.layout-container {
+  width: 210px;
+  position: relative;
+}
+.position-container {
+  position: relative;
+  width: 202px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#overflow {
+  width: 50%;
+  height: 100px;
+  overflow: scroll;
+  position: absolute;
+}
+
+.spacer {
+  background: #0f0;
+  height: 2000px;
+  width: 100%;
+}
+</style>
+
+<body>
+  <div class="layout-container">
+  <div class="position-container">
+    <div id="overflow">
+      <div class="spacer">
+      </div>
+    </div>
+  </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset.html b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset.html
new file mode 100644
index 0000000..c2d1a865
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/overflow/overflow-scroll-content-fractional-offset.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<style>
+.layout-container {
+  width: 210px;
+  position: relative;
+}
+.position-container {
+  position: relative;
+  width: 203px;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+#overflow {
+  width: 50%;
+  height: 100px;
+  overflow: scroll;
+  position: absolute;
+  will-change: transform;
+}
+
+.spacer {
+  background: #0f0;
+  height: 2000px;
+  width: 100%;
+}
+</style>
+
+<body>
+  <div class="layout-container">
+  <div class="position-container">
+    <div id="overflow">
+      <div class="spacer">
+      </div>
+    </div>
+  </div>
+  </div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/editing/composition-marker-basic.html b/third_party/WebKit/LayoutTests/editing/composition-marker-basic.html
index ec202974..16ee187 100644
--- a/third_party/WebKit/LayoutTests/editing/composition-marker-basic.html
+++ b/third_party/WebKit/LayoutTests/editing/composition-marker-basic.html
@@ -36,7 +36,7 @@
 };
 
 function highlightRangeSimple(elem, start, end) {
-    highlightRange(elem, start, end, 'orange', false, 'lightBlue');
+    highlightRange(elem, start, end, 'orange', 'thin', 'lightBlue');
 };
 
 function highlightAcrossNodes(startNode, start, endNode, end) {
@@ -44,13 +44,13 @@
     range.setStart(startNode, start);
     range.setEnd(endNode, end);
     if (typeof internals !== 'undefined')
-        internals.addCompositionMarker(range, 'orange', false, 'lightBlue');
+        internals.addCompositionMarker(range, 'orange', 'thin', 'lightBlue');
 };
 
 onload = runAfterLayoutAndPaint(function() {
     highlightRangeSimple(markAll, 0, 6);
-    highlightRange(markAllThick, 0, 6, 'orange', true, 'lightBlue');
-    highlightRange(markAllDifferentColors, 0, 6, 'purple', true, 'lightYellow');
+    highlightRange(markAllThick, 0, 6, 'orange', 'thick', 'lightBlue');
+    highlightRange(markAllDifferentColors, 0, 6, 'purple', 'thick', 'lightYellow');
     highlightRangeSimple(markBeginning, 0, 3);
     highlightRangeSimple(markAllExceptFirstAndLast, 1, 5);
     highlightRangeSimple(markEnd, 3, 6);
@@ -58,7 +58,7 @@
     highlightRangeSimple(markNothingEnd, 6, 6);
 
     highlightRangeSimple(markRtlAll, 0, 6);
-    highlightRange(markRtlAllThick, 0, 6, 'orange', true, 'lightBlue');
+    highlightRange(markRtlAllThick, 0, 6, 'orange', 'thick', 'lightBlue');
     highlightRangeSimple(markRtlBeginning, 0, 3);
     highlightRangeSimple(markRtlAllExceptFirstAndLast, 1, 5);
     highlightRangeSimple(markRtlEnd, 3, 6);
diff --git a/third_party/WebKit/LayoutTests/editing/composition-marker-split.html b/third_party/WebKit/LayoutTests/editing/composition-marker-split.html
index 195a74d..f3cb4ce 100644
--- a/third_party/WebKit/LayoutTests/editing/composition-marker-split.html
+++ b/third_party/WebKit/LayoutTests/editing/composition-marker-split.html
@@ -19,7 +19,7 @@
     range.setStart(textNode, 0);
     range.setEnd(textNode, 4);
     if (typeof internals !== 'undefined')
-        internals.addCompositionMarker(range, 'orange', false, 'lightBlue');
+        internals.addCompositionMarker(range, 'orange', 'thin', 'lightBlue');
 }
 
 onload = runAfterLayoutAndPaint(function() {
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 40c11b0e..2effa99f 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -4137,18 +4137,6 @@
      {}
     ]
    ],
-   "assumptions/ahem.html": [
-    [
-     "/assumptions/ahem.html",
-     [
-      [
-       "/assumptions/ahem-ref.html",
-       "=="
-      ]
-     ],
-     {}
-    ]
-   ],
    "assumptions/canvas-background.html": [
     [
      "/assumptions/canvas-background.html",
@@ -63731,11 +63719,6 @@
      {}
     ]
    ],
-   "assumptions/ahem-ref.html": [
-    [
-     {}
-    ]
-   ],
    "assumptions/canvas-background-ref.html": [
     [
      {}
@@ -63776,6 +63759,16 @@
      {}
     ]
    ],
+   "battery-status/battery-iframe.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "battery-status/battery-insecure-context-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "battery-status/support-iframe.html": [
     [
      {}
@@ -80291,6 +80284,11 @@
      {}
     ]
    ],
+   "custom-elements/reactions/DOMTokenList-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "custom-elements/reactions/HTMLElement-expected.txt": [
     [
      {}
@@ -80731,6 +80729,11 @@
      {}
     ]
    ],
+   "dom/nodes/Element-classlist-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "dom/nodes/Element-closest-expected.txt": [
     [
      {}
@@ -82381,11 +82384,6 @@
      {}
     ]
    ],
-   "fullscreen/api/document-exit-fullscreen-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "fullscreen/api/document-exit-fullscreen-timing-manual-expected.txt": [
     [
      {}
@@ -82411,11 +82409,6 @@
      {}
     ]
    ],
-   "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "fullscreen/api/element-request-fullscreen-and-move-manual-expected.txt": [
     [
      {}
@@ -82436,16 +82429,6 @@
      {}
     ]
    ],
-   "fullscreen/api/element-request-fullscreen-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fullscreen/api/element-request-fullscreen-not-allowed-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "fullscreen/api/element-request-fullscreen-timing-manual-expected.txt": [
     [
      {}
@@ -82471,31 +82454,6 @@
      {}
     ]
    ],
-   "fullscreen/model/move-to-iframe-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fullscreen/model/remove-first-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fullscreen/model/remove-last-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fullscreen/model/remove-parent-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "fullscreen/model/remove-single-manual-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "fullscreen/trusted-click.js": [
     [
      {}
@@ -91981,11 +91939,6 @@
      {}
     ]
    ],
-   "html/semantics/interactive-elements/the-menu-element/menuitem-label-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "html/semantics/interactive-elements/the-summary-element/.gitkeep": [
     [
      {}
@@ -144064,12 +144017,6 @@
      {}
     ]
    ],
-   "payment-request/payment-request-abort-method.https.html": [
-    [
-     "/payment-request/payment-request-abort-method.https.html",
-     {}
-    ]
-   ],
    "payment-request/payment-request-constructor.https.html": [
     [
      "/payment-request/payment-request-constructor.https.html",
@@ -162714,7 +162661,7 @@
    "support"
   ],
   "./update-built-tests.sh": [
-   "99b5beb84b30521fa4c4a8a061acc309ee3d0d4a",
+   "75ea35a5ce9d8e3e32e8d0c336dc12e04691d16a",
    "support"
   ],
   "./wptrun": [
@@ -170773,14 +170720,6 @@
    "b9ba0287c92e5dbda1dc207ab45e9c90e8618878",
    "reftest"
   ],
-  "assumptions/ahem-ref.html": [
-   "f38cdd07d07558540e19c2b2ec063dbc54f8be7f",
-   "support"
-  ],
-  "assumptions/ahem.html": [
-   "e097b6e6eb9ecf107cea94b3984661cc62c7ac67",
-   "reftest"
-  ],
   "assumptions/canvas-background-ref.html": [
    "0868a5443b1aacb8fd95327bc7c71d071158b0f1",
    "support"
@@ -170857,10 +170796,18 @@
    "0fb90d807a27ce9e78dab040926effc1be7f71be",
    "manual"
   ],
+  "battery-status/battery-iframe.https-expected.txt": [
+   "eb6453b6d1c328ffc20afdbb96fe5d7602a7c1d1",
+   "support"
+  ],
   "battery-status/battery-iframe.https.html": [
    "b4df9429c1ff9ace253fb40296b20c06f8eb5eb3",
    "testharness"
   ],
+  "battery-status/battery-insecure-context-expected.txt": [
+   "6be1447d61155d2656c958a00674ea311031b8eb",
+   "support"
+  ],
   "battery-status/battery-insecure-context.html": [
    "39639373d161846186cbcb7eb33466493bcc77ad",
    "testharness"
@@ -207217,6 +207164,10 @@
    "ad0b3fd9ec6ac895c2abd6685e23bc92b60f0733",
    "testharness"
   ],
+  "custom-elements/reactions/DOMTokenList-expected.txt": [
+   "f4b61b6ed54590d0e65611c03fe9061a2fedbe8d",
+   "support"
+  ],
   "custom-elements/reactions/DOMTokenList.html": [
    "7482fa56e7f4d95cfe8b8f337a9b5e63a83a6e9d",
    "testharness"
@@ -207238,7 +207189,7 @@
    "testharness"
   ],
   "custom-elements/reactions/HTMLElement-expected.txt": [
-   "fd027b233d354d933eb260def242be36ea6bccf8",
+   "f30c19c462c4b322553f38401106b2f70442e1c7",
    "support"
   ],
   "custom-elements/reactions/HTMLElement.html": [
@@ -207586,7 +207537,7 @@
    "testharness"
   ],
   "dom/interfaces-expected.txt": [
-   "133f60942eae89418f507d7cea7cee10d3f0e4b0",
+   "ee2b93473877f87d12dd9649452df2ed89706fab",
    "support"
   ],
   "dom/interfaces.html": [
@@ -208181,6 +208132,10 @@
    "e3fe31ea198922fe64fbf985ae99d1cd4512567a",
    "testharness"
   ],
+  "dom/nodes/Element-classlist-expected.txt": [
+   "3e610f97449595d17e58504e9dc2f9733562aa90",
+   "support"
+  ],
   "dom/nodes/Element-classlist.html": [
    "c197df35960b77a7794eed10a1a927867a6658f4",
    "testharness"
@@ -211657,10 +211612,6 @@
    "b4010cb68f5fa7f97e8d405e67977335e6a00795",
    "testharness"
   ],
-  "fullscreen/api/document-exit-fullscreen-manual-expected.txt": [
-   "c167856f71136c06d7733118f4def0c248989394",
-   "support"
-  ],
   "fullscreen/api/document-exit-fullscreen-manual.html": [
    "398a52fc8728e07771249c017baf0c1867c4ea44",
    "manual"
@@ -211749,10 +211700,6 @@
    "f8c6c1a63b5738a442bcf01c09535d4bb48512a7",
    "testharness"
   ],
-  "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual-expected.txt": [
-   "a473d95d2e72c45121680fc47ced9dcba2d73145",
-   "support"
-  ],
   "fullscreen/api/element-request-fullscreen-and-exit-iframe-manual.html": [
    "870575cb59c5a7f76097e19da8b3854120d6cb86",
    "manual"
@@ -211789,10 +211736,6 @@
    "86c1ac20aa86e860cfa8f05a9873f3a3cddbdcd9",
    "manual"
   ],
-  "fullscreen/api/element-request-fullscreen-manual-expected.txt": [
-   "b14caf034cd09dc2d84c76042c6ce66c3b85d8e2",
-   "support"
-  ],
   "fullscreen/api/element-request-fullscreen-manual.html": [
    "ed7683b3c4a7134b640e07a7329a21361b122402",
    "manual"
@@ -211801,10 +211744,6 @@
    "c346255bb659b952d8d27b2ab136e7815c1161d9",
    "manual"
   ],
-  "fullscreen/api/element-request-fullscreen-not-allowed-expected.txt": [
-   "c0be9280569576bb9e14a1e339bb90e335892c2b",
-   "support"
-  ],
   "fullscreen/api/element-request-fullscreen-not-allowed.html": [
    "8991e8df530fa7c24a9e084f2ab17fa9c70fb120",
    "testharness"
@@ -211862,17 +211801,13 @@
    "testharness"
   ],
   "fullscreen/interfaces-expected.txt": [
-   "d22cb0ab5f83fd919fcce3e334ca6916405c9945",
+   "ad9dbeb1ee339c858138e3bab0827eca418de781",
    "support"
   ],
   "fullscreen/interfaces.html": [
    "f6f0dbc8a505896a0e7ec7aca2746bbd5c1eb7d9",
    "testharness"
   ],
-  "fullscreen/model/move-to-iframe-manual-expected.txt": [
-   "e7019c27330910de32ea2a7f0283377e6dd1cb75",
-   "support"
-  ],
   "fullscreen/model/move-to-iframe-manual.html": [
    "818cb1b5db729db4959591dc75d4bb1ae3c7542d",
    "manual"
@@ -211881,34 +211816,18 @@
    "b1142930c6c972057213bd477cf116fcc9e7fc2a",
    "manual"
   ],
-  "fullscreen/model/remove-first-manual-expected.txt": [
-   "ef976589b9898457661d8304518a5013776b8681",
-   "support"
-  ],
   "fullscreen/model/remove-first-manual.html": [
    "3de98ae96822370fa80c1b8d61df254910a63ff9",
    "manual"
   ],
-  "fullscreen/model/remove-last-manual-expected.txt": [
-   "6813bede8236c163823407e7abbba719bed2c177",
-   "support"
-  ],
   "fullscreen/model/remove-last-manual.html": [
    "8caa21a892edeaba9996a7f2bf1c670385e0a91b",
    "manual"
   ],
-  "fullscreen/model/remove-parent-manual-expected.txt": [
-   "0e4526d0b0bd833feed4ddedd2c35ae7d6a904f8",
-   "support"
-  ],
   "fullscreen/model/remove-parent-manual.html": [
    "e5791db04ab5e2b75a00c922457fcc8ba87c7ce7",
    "manual"
   ],
-  "fullscreen/model/remove-single-manual-expected.txt": [
-   "9d0112ef4bf35d3a6a80e2dcb836b4c57ca850e2",
-   "support"
-  ],
   "fullscreen/model/remove-single-manual.html": [
    "c7fc8323d503adb6d7f0c390a8add90c5c9e8082",
    "manual"
@@ -216490,7 +216409,7 @@
    "testharness"
   ],
   "html/dom/reflection-misc-expected.txt": [
-   "a2a204d95b1c8dd8691e6572d9cdf6b64739a73f",
+   "f2046b22833fa1c167a8e898ce4c6f814937d0f2",
    "support"
   ],
   "html/dom/reflection-misc.html": [
@@ -224213,10 +224132,6 @@
    "a79ad27e8f1e2eee47c89fa4530f7babfbb07dd5",
    "support"
   ],
-  "html/semantics/interactive-elements/the-menu-element/menuitem-label-expected.txt": [
-   "237def2c38478a46dbaf16029c5c2b2d5ff04993",
-   "support"
-  ],
   "html/semantics/interactive-elements/the-menu-element/menuitem-label.html": [
    "d11f6d0ef667da33d7981860b47e6d02f8c0ad24",
    "testharness"
@@ -224230,7 +224145,7 @@
    "testharness"
   ],
   "html/semantics/interfaces-expected.txt": [
-   "5bde359d32efb77ff7ed13a3bc646eade3a92d8d",
+   "66b9d2904c0b48ff310813f23947c8f27d45b1ec",
    "support"
   ],
   "html/semantics/interfaces.html": [
@@ -224666,7 +224581,7 @@
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-cycle.js": [
-   "e9cad195e5e718080c21f7cf15a58a775a1226de",
+   "462fe462bf92e1df232228cc1ce338ff522febbd",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-inc-a.js": [
@@ -224686,11 +224601,11 @@
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports-self.js": [
-   "a18743fbd553b68e0ceb657a5d65e3424e6f6a52",
+   "26b832413187999e45c0520e171f5fc61a911b20",
    "support"
   ],
   "html/semantics/scripting-1/the-script-element/module/imports.html": [
-   "15b0b32d86bc6411b29c5d978db71053c00a1d65",
+   "997cee37dcd202498196e63e0f66035979121b7f",
    "testharness"
   ],
   "html/semantics/scripting-1/the-script-element/module/instantiation-error-1.html": [
@@ -236797,12 +236712,8 @@
    "29af302db74de64e2bd1352ad92092a309d28c92",
    "testharness"
   ],
-  "payment-request/payment-request-abort-method.https.html": [
-   "c9ee5af2ccd5ad364090807c8427f1d4624d3747",
-   "testharness"
-  ],
   "payment-request/payment-request-constructor.https.html": [
-   "44d2656f2990c51063254326521a02218a7fc500",
+   "12cb2d46800b03554830fb145f2d8dca37043f79",
    "testharness"
   ],
   "payment-request/payment-request-id.https.html": [
@@ -236822,7 +236733,7 @@
    "support"
   ],
   "payment-request/payment-request-show-method.https.html": [
-   "518136ad885f95172e578f6e2c165a559c51896b",
+   "026e28265a88be54a56e2dadc0fb485303864dfc",
    "testharness"
   ],
   "performance-timeline/case-sensitivity.any.js": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html
deleted file mode 100644
index 2272bdab..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem-ref.html
+++ /dev/null
@@ -1,300 +0,0 @@
-
-<!doctype html>
-<title>Ahem checker</title>
-<style>
-@font-face {
-  font-family: Ahem;
-  src: url("../css/fonts/ahem/ahem.ttf");
-}
-* {
-  padding: 0;
-  margin: 0;
-  border: none;
-}
-
-table {
-  font: 15px/1 Ahem;
-  border-collapse: separate;
-  border-spacing: 1px;
-  table-layout: fixed;
-}
-
-td {
-  width: 34px;
-}
-</style>
-<table>
-    <tr>
-        <td>&#x0020;x <!-- U+0020: SPACE -->
-        <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
-        <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
-        <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
-        <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
-        <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
-        <td>&#x0026;x <!-- U+0026: AMPERSAND -->
-        <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
-        <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
-        <td>&#x002A;x <!-- U+002A: ASTERISK -->
-        <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
-        <td>&#x002C;x <!-- U+002C: COMMA -->
-        <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
-        <td>&#x002E;x <!-- U+002E: FULL STOP -->
-        <td>&#x002F;x <!-- U+002F: SOLIDUS -->
-        <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
-        <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
-    <tr>
-        <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
-        <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
-        <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
-        <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
-        <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
-        <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
-        <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
-        <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
-        <td>&#x003A;x <!-- U+003A: COLON -->
-        <td>&#x003B;x <!-- U+003B: SEMICOLON -->
-        <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
-        <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
-        <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
-        <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
-        <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
-        <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
-        <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
-    <tr>
-        <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
-        <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
-        <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
-        <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
-        <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
-        <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
-        <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
-        <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
-        <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
-        <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
-        <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
-        <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
-        <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
-        <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
-        <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
-        <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
-        <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
-    <tr>
-        <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
-        <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
-        <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
-        <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
-        <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
-        <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
-        <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
-        <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
-        <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
-        <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
-        <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
-        <td>&#x005F;x <!-- U+005F: LOW LINE -->
-        <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
-        <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
-        <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
-        <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
-        <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
-    <tr>
-        <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
-        <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
-        <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
-        <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
-        <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
-        <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
-        <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
-        <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
-        <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
-        <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
-        <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
-        <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
-        <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
-        <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
-        <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
-        <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
-        <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
-    <tr>
-        <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
-        <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
-        <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
-        <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
-        <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
-        <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
-        <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
-        <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
-        <td>&#x007E;x <!-- U+007E: TILDE -->
-        <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
-        <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
-        <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
-        <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
-        <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
-        <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
-        <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
-        <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
-    <tr>
-        <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
-        <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
-        <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
-        <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-        <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
-        <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
-        <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
-        <td>&#x00AF;x <!-- U+00AF: MACRON -->
-        <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
-        <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
-        <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
-        <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
-        <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
-        <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
-        <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
-        <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
-        <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
-    <tr>
-        <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
-        <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
-        <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-        <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
-        <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
-        <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
-        <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
-        <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
-        <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
-        <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
-        <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
-        <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
-        <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
-        <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
-        <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
-        <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
-        <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
-    <tr>
-        <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
-        <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
-        <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
-        <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
-        <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
-        <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
-        <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
-        <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
-        <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
-        <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
-        <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
-        <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
-        <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
-        <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
-        <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
-        <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
-        <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
-    <tr>
-        <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
-        <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
-        <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
-        <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
-        <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
-        <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
-        <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
-        <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
-        <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
-        <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
-        <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
-        <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
-        <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
-        <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
-        <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
-        <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
-        <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
-    <tr>
-        <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
-        <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
-        <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
-        <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
-        <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
-        <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
-        <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
-        <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
-        <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
-        <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
-        <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
-        <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
-        <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
-        <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
-        <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
-        <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
-        <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
-    <tr>
-        <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
-        <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
-        <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
-        <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
-        <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
-        <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
-        <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
-        <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
-        <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
-        <td>&#x02C7;x <!-- U+02C7: CARON -->
-        <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
-        <td>&#x02D8;x <!-- U+02D8: BREVE -->
-        <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
-        <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
-        <td>&#x02DB;x <!-- U+02DB: OGONEK -->
-        <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
-        <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
-    <tr>
-        <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
-        <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
-        <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
-        <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
-        <td>&#x2002;x <!-- U+2002: EN SPACE -->
-        <td>&#x2003;x <!-- U+2003: EM SPACE -->
-        <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
-        <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
-        <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
-        <td>&#x2009;x <!-- U+2009: THIN SPACE -->
-        <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
-        <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
-        <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
-        <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
-        <td>&#x2010;x <!-- U+2010: HYPHEN -->
-        <td>&#x2013;x <!-- U+2013: EN DASH -->
-        <td>&#x2014;x <!-- U+2014: EM DASH -->
-    <tr>
-        <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
-        <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
-        <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
-        <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
-        <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
-        <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
-        <td>&#x2020;x <!-- U+2020: DAGGER -->
-        <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
-        <td>&#x2022;x <!-- U+2022: BULLET -->
-        <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
-        <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
-        <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
-        <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
-        <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
-        <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
-        <td>&#x2126;x <!-- U+2126: OHM SIGN -->
-        <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
-    <tr>
-        <td>&#x2206;x <!-- U+2206: INCREMENT -->
-        <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
-        <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
-        <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
-        <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
-        <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
-        <td>&#x221E;x <!-- U+221E: INFINITY -->
-        <td>&#x222B;x <!-- U+222B: INTEGRAL -->
-        <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
-        <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
-        <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
-        <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
-        <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
-        <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
-        <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
-        <td>&#xF000;x <!-- U+F000 -->
-        <td>&#xF001;x <!-- U+F001 -->
-    <tr>
-        <td>&#xF002;x <!-- U+F002 -->
-        <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
-</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html b/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html
deleted file mode 100644
index dee1b75c..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/assumptions/ahem.html
+++ /dev/null
@@ -1,297 +0,0 @@
-
-<!doctype html>
-<title>Ahem checker</title>
-<link rel="match" href="ahem-ref.html">
-<style>
-* {
-  padding: 0;
-  margin: 0;
-  border: none;
-}
-
-table {
-  font: 15px/1 Ahem;
-  border-collapse: separate;
-  border-spacing: 1px;
-  table-layout: fixed;
-}
-
-td {
-  width: 34px;
-}
-</style>
-<table>
-    <tr>
-        <td>&#x0020;x <!-- U+0020: SPACE -->
-        <td>&#x0021;x <!-- U+0021: EXCLAMATION MARK -->
-        <td>&#x0022;x <!-- U+0022: QUOTATION MARK -->
-        <td>&#x0023;x <!-- U+0023: NUMBER SIGN -->
-        <td>&#x0024;x <!-- U+0024: DOLLAR SIGN -->
-        <td>&#x0025;x <!-- U+0025: PERCENT SIGN -->
-        <td>&#x0026;x <!-- U+0026: AMPERSAND -->
-        <td>&#x0028;x <!-- U+0028: LEFT PARENTHESIS -->
-        <td>&#x0029;x <!-- U+0029: RIGHT PARENTHESIS -->
-        <td>&#x002A;x <!-- U+002A: ASTERISK -->
-        <td>&#x002B;x <!-- U+002B: PLUS SIGN -->
-        <td>&#x002C;x <!-- U+002C: COMMA -->
-        <td>&#x002D;x <!-- U+002D: HYPHEN-MINUS -->
-        <td>&#x002E;x <!-- U+002E: FULL STOP -->
-        <td>&#x002F;x <!-- U+002F: SOLIDUS -->
-        <td>&#x0030;x <!-- U+0030: DIGIT ZERO -->
-        <td>&#x0031;x <!-- U+0031: DIGIT ONE -->
-    <tr>
-        <td>&#x0032;x <!-- U+0032: DIGIT TWO -->
-        <td>&#x0033;x <!-- U+0033: DIGIT THREE -->
-        <td>&#x0034;x <!-- U+0034: DIGIT FOUR -->
-        <td>&#x0035;x <!-- U+0035: DIGIT FIVE -->
-        <td>&#x0036;x <!-- U+0036: DIGIT SIX -->
-        <td>&#x0037;x <!-- U+0037: DIGIT SEVEN -->
-        <td>&#x0038;x <!-- U+0038: DIGIT EIGHT -->
-        <td>&#x0039;x <!-- U+0039: DIGIT NINE -->
-        <td>&#x003A;x <!-- U+003A: COLON -->
-        <td>&#x003B;x <!-- U+003B: SEMICOLON -->
-        <td>&#x003C;x <!-- U+003C: LESS-THAN SIGN -->
-        <td>&#x003D;x <!-- U+003D: EQUALS SIGN -->
-        <td>&#x003E;x <!-- U+003E: GREATER-THAN SIGN -->
-        <td>&#x003F;x <!-- U+003F: QUESTION MARK -->
-        <td>&#x0040;x <!-- U+0040: COMMERCIAL AT -->
-        <td>&#x0041;x <!-- U+0041: LATIN CAPITAL LETTER A -->
-        <td>&#x0042;x <!-- U+0042: LATIN CAPITAL LETTER B -->
-    <tr>
-        <td>&#x0043;x <!-- U+0043: LATIN CAPITAL LETTER C -->
-        <td>&#x0044;x <!-- U+0044: LATIN CAPITAL LETTER D -->
-        <td>&#x0045;x <!-- U+0045: LATIN CAPITAL LETTER E -->
-        <td>&#x0046;x <!-- U+0046: LATIN CAPITAL LETTER F -->
-        <td>&#x0047;x <!-- U+0047: LATIN CAPITAL LETTER G -->
-        <td>&#x0048;x <!-- U+0048: LATIN CAPITAL LETTER H -->
-        <td>&#x0049;x <!-- U+0049: LATIN CAPITAL LETTER I -->
-        <td>&#x004A;x <!-- U+004A: LATIN CAPITAL LETTER J -->
-        <td>&#x004B;x <!-- U+004B: LATIN CAPITAL LETTER K -->
-        <td>&#x004C;x <!-- U+004C: LATIN CAPITAL LETTER L -->
-        <td>&#x004D;x <!-- U+004D: LATIN CAPITAL LETTER M -->
-        <td>&#x004E;x <!-- U+004E: LATIN CAPITAL LETTER N -->
-        <td>&#x004F;x <!-- U+004F: LATIN CAPITAL LETTER O -->
-        <td>&#x0050;x <!-- U+0050: LATIN CAPITAL LETTER P -->
-        <td>&#x0051;x <!-- U+0051: LATIN CAPITAL LETTER Q -->
-        <td>&#x0052;x <!-- U+0052: LATIN CAPITAL LETTER R -->
-        <td>&#x0053;x <!-- U+0053: LATIN CAPITAL LETTER S -->
-    <tr>
-        <td>&#x0054;x <!-- U+0054: LATIN CAPITAL LETTER T -->
-        <td>&#x0055;x <!-- U+0055: LATIN CAPITAL LETTER U -->
-        <td>&#x0056;x <!-- U+0056: LATIN CAPITAL LETTER V -->
-        <td>&#x0057;x <!-- U+0057: LATIN CAPITAL LETTER W -->
-        <td>&#x0058;x <!-- U+0058: LATIN CAPITAL LETTER X -->
-        <td>&#x0059;x <!-- U+0059: LATIN CAPITAL LETTER Y -->
-        <td>&#x005A;x <!-- U+005A: LATIN CAPITAL LETTER Z -->
-        <td>&#x005B;x <!-- U+005B: LEFT SQUARE BRACKET -->
-        <td>&#x005C;x <!-- U+005C: REVERSE SOLIDUS -->
-        <td>&#x005D;x <!-- U+005D: RIGHT SQUARE BRACKET -->
-        <td>&#x005E;x <!-- U+005E: CIRCUMFLEX ACCENT -->
-        <td>&#x005F;x <!-- U+005F: LOW LINE -->
-        <td>&#x0060;x <!-- U+0060: GRAVE ACCENT -->
-        <td>&#x0061;x <!-- U+0061: LATIN SMALL LETTER A -->
-        <td>&#x0062;x <!-- U+0062: LATIN SMALL LETTER B -->
-        <td>&#x0063;x <!-- U+0063: LATIN SMALL LETTER C -->
-        <td>&#x0064;x <!-- U+0064: LATIN SMALL LETTER D -->
-    <tr>
-        <td>&#x0065;x <!-- U+0065: LATIN SMALL LETTER E -->
-        <td>&#x0066;x <!-- U+0066: LATIN SMALL LETTER F -->
-        <td>&#x0067;x <!-- U+0067: LATIN SMALL LETTER G -->
-        <td>&#x0068;x <!-- U+0068: LATIN SMALL LETTER H -->
-        <td>&#x0069;x <!-- U+0069: LATIN SMALL LETTER I -->
-        <td>&#x006A;x <!-- U+006A: LATIN SMALL LETTER J -->
-        <td>&#x006B;x <!-- U+006B: LATIN SMALL LETTER K -->
-        <td>&#x006C;x <!-- U+006C: LATIN SMALL LETTER L -->
-        <td>&#x006D;x <!-- U+006D: LATIN SMALL LETTER M -->
-        <td>&#x006E;x <!-- U+006E: LATIN SMALL LETTER N -->
-        <td>&#x006F;x <!-- U+006F: LATIN SMALL LETTER O -->
-        <td>&#x0070;x <!-- U+0070: LATIN SMALL LETTER P -->
-        <td>&#x0071;x <!-- U+0071: LATIN SMALL LETTER Q -->
-        <td>&#x0072;x <!-- U+0072: LATIN SMALL LETTER R -->
-        <td>&#x0073;x <!-- U+0073: LATIN SMALL LETTER S -->
-        <td>&#x0074;x <!-- U+0074: LATIN SMALL LETTER T -->
-        <td>&#x0075;x <!-- U+0075: LATIN SMALL LETTER U -->
-    <tr>
-        <td>&#x0076;x <!-- U+0076: LATIN SMALL LETTER V -->
-        <td>&#x0077;x <!-- U+0077: LATIN SMALL LETTER W -->
-        <td>&#x0078;x <!-- U+0078: LATIN SMALL LETTER X -->
-        <td>&#x0079;x <!-- U+0079: LATIN SMALL LETTER Y -->
-        <td>&#x007A;x <!-- U+007A: LATIN SMALL LETTER Z -->
-        <td>&#x007B;x <!-- U+007B: LEFT CURLY BRACKET -->
-        <td>&#x007C;x <!-- U+007C: VERTICAL LINE -->
-        <td>&#x007D;x <!-- U+007D: RIGHT CURLY BRACKET -->
-        <td>&#x007E;x <!-- U+007E: TILDE -->
-        <td>&#x00A0;x <!-- U+00A0: NO-BREAK SPACE -->
-        <td>&#x00A1;x <!-- U+00A1: INVERTED EXCLAMATION MARK -->
-        <td>&#x00A2;x <!-- U+00A2: CENT SIGN -->
-        <td>&#x00A3;x <!-- U+00A3: POUND SIGN -->
-        <td>&#x00A4;x <!-- U+00A4: CURRENCY SIGN -->
-        <td>&#x00A5;x <!-- U+00A5: YEN SIGN -->
-        <td>&#x00A6;x <!-- U+00A6: BROKEN BAR -->
-        <td>&#x00A7;x <!-- U+00A7: SECTION SIGN -->
-    <tr>
-        <td>&#x00A8;x <!-- U+00A8: DIAERESIS -->
-        <td>&#x00A9;x <!-- U+00A9: COPYRIGHT SIGN -->
-        <td>&#x00AA;x <!-- U+00AA: FEMININE ORDINAL INDICATOR -->
-        <td>&#x00AB;x <!-- U+00AB: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-        <td>&#x00AC;x <!-- U+00AC: NOT SIGN -->
-        <td>&#x00AD;x <!-- U+00AD: SOFT HYPHEN -->
-        <td>&#x00AE;x <!-- U+00AE: REGISTERED SIGN -->
-        <td>&#x00AF;x <!-- U+00AF: MACRON -->
-        <td>&#x00B0;x <!-- U+00B0: DEGREE SIGN -->
-        <td>&#x00B1;x <!-- U+00B1: PLUS-MINUS SIGN -->
-        <td>&#x00B2;x <!-- U+00B2: SUPERSCRIPT TWO -->
-        <td>&#x00B3;x <!-- U+00B3: SUPERSCRIPT THREE -->
-        <td>&#x00B4;x <!-- U+00B4: ACUTE ACCENT -->
-        <td>&#x00B5;x <!-- U+00B5: MICRO SIGN -->
-        <td>&#x00B6;x <!-- U+00B6: PILCROW SIGN -->
-        <td>&#x00B7;x <!-- U+00B7: MIDDLE DOT -->
-        <td>&#x00B8;x <!-- U+00B8: CEDILLA -->
-    <tr>
-        <td>&#x00B9;x <!-- U+00B9: SUPERSCRIPT ONE -->
-        <td>&#x00BA;x <!-- U+00BA: MASCULINE ORDINAL INDICATOR -->
-        <td>&#x00BB;x <!-- U+00BB: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-        <td>&#x00BC;x <!-- U+00BC: VULGAR FRACTION ONE QUARTER -->
-        <td>&#x00BD;x <!-- U+00BD: VULGAR FRACTION ONE HALF -->
-        <td>&#x00BE;x <!-- U+00BE: VULGAR FRACTION THREE QUARTERS -->
-        <td>&#x00BF;x <!-- U+00BF: INVERTED QUESTION MARK -->
-        <td>&#x00C0;x <!-- U+00C0: LATIN CAPITAL LETTER A WITH GRAVE -->
-        <td>&#x00C1;x <!-- U+00C1: LATIN CAPITAL LETTER A WITH ACUTE -->
-        <td>&#x00C2;x <!-- U+00C2: LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
-        <td>&#x00C3;x <!-- U+00C3: LATIN CAPITAL LETTER A WITH TILDE -->
-        <td>&#x00C4;x <!-- U+00C4: LATIN CAPITAL LETTER A WITH DIAERESIS -->
-        <td>&#x00C5;x <!-- U+00C5: LATIN CAPITAL LETTER A WITH RING ABOVE -->
-        <td>&#x00C6;x <!-- U+00C6: LATIN CAPITAL LETTER AE -->
-        <td>&#x00C7;x <!-- U+00C7: LATIN CAPITAL LETTER C WITH CEDILLA -->
-        <td>&#x00C8;x <!-- U+00C8: LATIN CAPITAL LETTER E WITH GRAVE -->
-        <td>&#x00C9;x <!-- U+00C9: LATIN CAPITAL LETTER E WITH ACUTE -->
-    <tr>
-        <td>&#x00CA;x <!-- U+00CA: LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
-        <td>&#x00CB;x <!-- U+00CB: LATIN CAPITAL LETTER E WITH DIAERESIS -->
-        <td>&#x00CC;x <!-- U+00CC: LATIN CAPITAL LETTER I WITH GRAVE -->
-        <td>&#x00CD;x <!-- U+00CD: LATIN CAPITAL LETTER I WITH ACUTE -->
-        <td>&#x00CE;x <!-- U+00CE: LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
-        <td>&#x00CF;x <!-- U+00CF: LATIN CAPITAL LETTER I WITH DIAERESIS -->
-        <td>&#x00D0;x <!-- U+00D0: LATIN CAPITAL LETTER ETH -->
-        <td>&#x00D1;x <!-- U+00D1: LATIN CAPITAL LETTER N WITH TILDE -->
-        <td>&#x00D2;x <!-- U+00D2: LATIN CAPITAL LETTER O WITH GRAVE -->
-        <td>&#x00D3;x <!-- U+00D3: LATIN CAPITAL LETTER O WITH ACUTE -->
-        <td>&#x00D4;x <!-- U+00D4: LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
-        <td>&#x00D5;x <!-- U+00D5: LATIN CAPITAL LETTER O WITH TILDE -->
-        <td>&#x00D6;x <!-- U+00D6: LATIN CAPITAL LETTER O WITH DIAERESIS -->
-        <td>&#x00D7;x <!-- U+00D7: MULTIPLICATION SIGN -->
-        <td>&#x00D8;x <!-- U+00D8: LATIN CAPITAL LETTER O WITH STROKE -->
-        <td>&#x00D9;x <!-- U+00D9: LATIN CAPITAL LETTER U WITH GRAVE -->
-        <td>&#x00DA;x <!-- U+00DA: LATIN CAPITAL LETTER U WITH ACUTE -->
-    <tr>
-        <td>&#x00DB;x <!-- U+00DB: LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
-        <td>&#x00DC;x <!-- U+00DC: LATIN CAPITAL LETTER U WITH DIAERESIS -->
-        <td>&#x00DD;x <!-- U+00DD: LATIN CAPITAL LETTER Y WITH ACUTE -->
-        <td>&#x00DE;x <!-- U+00DE: LATIN CAPITAL LETTER THORN -->
-        <td>&#x00DF;x <!-- U+00DF: LATIN SMALL LETTER SHARP S -->
-        <td>&#x00E0;x <!-- U+00E0: LATIN SMALL LETTER A WITH GRAVE -->
-        <td>&#x00E1;x <!-- U+00E1: LATIN SMALL LETTER A WITH ACUTE -->
-        <td>&#x00E2;x <!-- U+00E2: LATIN SMALL LETTER A WITH CIRCUMFLEX -->
-        <td>&#x00E3;x <!-- U+00E3: LATIN SMALL LETTER A WITH TILDE -->
-        <td>&#x00E4;x <!-- U+00E4: LATIN SMALL LETTER A WITH DIAERESIS -->
-        <td>&#x00E5;x <!-- U+00E5: LATIN SMALL LETTER A WITH RING ABOVE -->
-        <td>&#x00E6;x <!-- U+00E6: LATIN SMALL LETTER AE -->
-        <td>&#x00E7;x <!-- U+00E7: LATIN SMALL LETTER C WITH CEDILLA -->
-        <td>&#x00E8;x <!-- U+00E8: LATIN SMALL LETTER E WITH GRAVE -->
-        <td>&#x00E9;x <!-- U+00E9: LATIN SMALL LETTER E WITH ACUTE -->
-        <td>&#x00EA;x <!-- U+00EA: LATIN SMALL LETTER E WITH CIRCUMFLEX -->
-        <td>&#x00EB;x <!-- U+00EB: LATIN SMALL LETTER E WITH DIAERESIS -->
-    <tr>
-        <td>&#x00EC;x <!-- U+00EC: LATIN SMALL LETTER I WITH GRAVE -->
-        <td>&#x00ED;x <!-- U+00ED: LATIN SMALL LETTER I WITH ACUTE -->
-        <td>&#x00EE;x <!-- U+00EE: LATIN SMALL LETTER I WITH CIRCUMFLEX -->
-        <td>&#x00EF;x <!-- U+00EF: LATIN SMALL LETTER I WITH DIAERESIS -->
-        <td>&#x00F0;x <!-- U+00F0: LATIN SMALL LETTER ETH -->
-        <td>&#x00F1;x <!-- U+00F1: LATIN SMALL LETTER N WITH TILDE -->
-        <td>&#x00F2;x <!-- U+00F2: LATIN SMALL LETTER O WITH GRAVE -->
-        <td>&#x00F3;x <!-- U+00F3: LATIN SMALL LETTER O WITH ACUTE -->
-        <td>&#x00F4;x <!-- U+00F4: LATIN SMALL LETTER O WITH CIRCUMFLEX -->
-        <td>&#x00F5;x <!-- U+00F5: LATIN SMALL LETTER O WITH TILDE -->
-        <td>&#x00F6;x <!-- U+00F6: LATIN SMALL LETTER O WITH DIAERESIS -->
-        <td>&#x00F7;x <!-- U+00F7: DIVISION SIGN -->
-        <td>&#x00F8;x <!-- U+00F8: LATIN SMALL LETTER O WITH STROKE -->
-        <td>&#x00F9;x <!-- U+00F9: LATIN SMALL LETTER U WITH GRAVE -->
-        <td>&#x00FA;x <!-- U+00FA: LATIN SMALL LETTER U WITH ACUTE -->
-        <td>&#x00FB;x <!-- U+00FB: LATIN SMALL LETTER U WITH CIRCUMFLEX -->
-        <td>&#x00FC;x <!-- U+00FC: LATIN SMALL LETTER U WITH DIAERESIS -->
-    <tr>
-        <td>&#x00FD;x <!-- U+00FD: LATIN SMALL LETTER Y WITH ACUTE -->
-        <td>&#x00FE;x <!-- U+00FE: LATIN SMALL LETTER THORN -->
-        <td>&#x00FF;x <!-- U+00FF: LATIN SMALL LETTER Y WITH DIAERESIS -->
-        <td>&#x0131;x <!-- U+0131: LATIN SMALL LETTER DOTLESS I -->
-        <td>&#x0152;x <!-- U+0152: LATIN CAPITAL LIGATURE OE -->
-        <td>&#x0153;x <!-- U+0153: LATIN SMALL LIGATURE OE -->
-        <td>&#x0178;x <!-- U+0178: LATIN CAPITAL LETTER Y WITH DIAERESIS -->
-        <td>&#x0192;x <!-- U+0192: LATIN SMALL LETTER F WITH HOOK -->
-        <td>&#x02C6;x <!-- U+02C6: MODIFIER LETTER CIRCUMFLEX ACCENT -->
-        <td>&#x02C7;x <!-- U+02C7: CARON -->
-        <td>&#x02C9;x <!-- U+02C9: MODIFIER LETTER MACRON -->
-        <td>&#x02D8;x <!-- U+02D8: BREVE -->
-        <td>&#x02D9;x <!-- U+02D9: DOT ABOVE -->
-        <td>&#x02DA;x <!-- U+02DA: RING ABOVE -->
-        <td>&#x02DB;x <!-- U+02DB: OGONEK -->
-        <td>&#x02DC;x <!-- U+02DC: SMALL TILDE -->
-        <td>&#x02DD;x <!-- U+02DD: DOUBLE ACUTE ACCENT -->
-    <tr>
-        <td>&#x0394;x <!-- U+0394: GREEK CAPITAL LETTER DELTA -->
-        <td>&#x03A9;x <!-- U+03A9: GREEK CAPITAL LETTER OMEGA -->
-        <td>&#x03BC;x <!-- U+03BC: GREEK SMALL LETTER MU -->
-        <td>&#x03C0;x <!-- U+03C0: GREEK SMALL LETTER PI -->
-        <td>&#x2002;x <!-- U+2002: EN SPACE -->
-        <td>&#x2003;x <!-- U+2003: EM SPACE -->
-        <td>&#x2004;x <!-- U+2004: THREE-PER-EM SPACE -->
-        <td>&#x2005;x <!-- U+2005: FOUR-PER-EM SPACE -->
-        <td>&#x2006;x <!-- U+2006: SIX-PER-EM SPACE -->
-        <td>&#x2009;x <!-- U+2009: THIN SPACE -->
-        <td>&#x200A;x <!-- U+200A: HAIR SPACE -->
-        <td>&#x200B;x <!-- U+200B: ZERO WIDTH SPACE -->
-        <td>&#x200C;x <!-- U+200C: ZERO WIDTH NON-JOINER -->
-        <td>&#x200D;x <!-- U+200D: ZERO WIDTH JOINER -->
-        <td>&#x2010;x <!-- U+2010: HYPHEN -->
-        <td>&#x2013;x <!-- U+2013: EN DASH -->
-        <td>&#x2014;x <!-- U+2014: EM DASH -->
-    <tr>
-        <td>&#x2018;x <!-- U+2018: LEFT SINGLE QUOTATION MARK -->
-        <td>&#x2019;x <!-- U+2019: RIGHT SINGLE QUOTATION MARK -->
-        <td>&#x201A;x <!-- U+201A: SINGLE LOW-9 QUOTATION MARK -->
-        <td>&#x201C;x <!-- U+201C: LEFT DOUBLE QUOTATION MARK -->
-        <td>&#x201D;x <!-- U+201D: RIGHT DOUBLE QUOTATION MARK -->
-        <td>&#x201E;x <!-- U+201E: DOUBLE LOW-9 QUOTATION MARK -->
-        <td>&#x2020;x <!-- U+2020: DAGGER -->
-        <td>&#x2021;x <!-- U+2021: DOUBLE DAGGER -->
-        <td>&#x2022;x <!-- U+2022: BULLET -->
-        <td>&#x2026;x <!-- U+2026: HORIZONTAL ELLIPSIS -->
-        <td>&#x2030;x <!-- U+2030: PER MILLE SIGN -->
-        <td>&#x2039;x <!-- U+2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK -->
-        <td>&#x203A;x <!-- U+203A: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK -->
-        <td>&#x2044;x <!-- U+2044: FRACTION SLASH -->
-        <td>&#x2122;x <!-- U+2122: TRADE MARK SIGN -->
-        <td>&#x2126;x <!-- U+2126: OHM SIGN -->
-        <td>&#x2202;x <!-- U+2202: PARTIAL DIFFERENTIAL -->
-    <tr>
-        <td>&#x2206;x <!-- U+2206: INCREMENT -->
-        <td>&#x220F;x <!-- U+220F: N-ARY PRODUCT -->
-        <td>&#x2211;x <!-- U+2211: N-ARY SUMMATION -->
-        <td>&#x2212;x <!-- U+2212: MINUS SIGN -->
-        <td>&#x2219;x <!-- U+2219: BULLET OPERATOR -->
-        <td>&#x221A;x <!-- U+221A: SQUARE ROOT -->
-        <td>&#x221E;x <!-- U+221E: INFINITY -->
-        <td>&#x222B;x <!-- U+222B: INTEGRAL -->
-        <td>&#x2248;x <!-- U+2248: ALMOST EQUAL TO -->
-        <td>&#x2260;x <!-- U+2260: NOT EQUAL TO -->
-        <td>&#x2264;x <!-- U+2264: LESS-THAN OR EQUAL TO -->
-        <td>&#x2265;x <!-- U+2265: GREATER-THAN OR EQUAL TO -->
-        <td>&#x22F2;x <!-- U+22F2: ELEMENT OF WITH LONG HORIZONTAL STROKE -->
-        <td>&#x25CA;x <!-- U+25CA: LOZENGE -->
-        <td>&#x3000;x <!-- U+3000: IDEOGRAPHIC SPACE -->
-        <td>&#xF000;x <!-- U+F000 -->
-        <td>&#xF001;x <!-- U+F001 -->
-    <tr>
-        <td>&#xF002;x <!-- U+F002 -->
-        <td>&#xFEFF;x <!-- U+FEFF: ZERO WIDTH NO-BREAK SPACE -->
-</table>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt
deleted file mode 100644
index 4fe4e85c..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Throws if the promise [[state]] is not "interactive" 
-FAIL Calling abort must not change the [[state]] until after "interactive" assert_true: Unexpected promise rejection: Request failed expected true got false
-FAIL calling .abort() causes acceptPromise to reject and closes the request. assert_true: Unexpected promise rejection: Request failed expected true got false
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
deleted file mode 100644
index f596800..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-abort-method.https.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE html>
-<!-- Copyright © 2017 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
-<meta charset="utf-8">
-<title>Test for PaymentRequest.abort() method</title>
-<link rel="help" href="https://w3c.github.io/browser-payment-api/#abort-method">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script>
-"use strict";
-setup(() => {}, {
-  // Ignore unhandled rejections resulting from .show()'s acceptPromise
-  // not being explicitly handled.
-  allow_uncaught_exception: true,
-});
-const basicCard = Object.freeze({ supportedMethods: ["basic-card"] });
-const defaultMethods = Object.freeze([basicCard]);
-const defaultDetails = Object.freeze({
-  total: {
-    label: "Total",
-    amount: {
-      currency: "USD",
-      value: "1.00",
-    },
-  },
-});
-
-promise_test(async t => {
-  // request is in "created" state
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  await promise_rejects(t, "InvalidStateError", request.abort());
-}, `Throws if the promise [[state]] is not "interactive"`);
-
-promise_test(async t => {
-  // request is in "created" state.
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  await promise_rejects(t, "InvalidStateError", request.abort());
-  // Call it again, for good measure.
-  await promise_rejects(t, "InvalidStateError", request.abort());
-  // The request's state is "created", so let's show it
-  // which changes the state to "interactive.".
-  request.show();
-  // Let's set request the state to "closed" by calling .abort()
-  try {
-    await request.abort();
-  } catch (err) {
-    assert_true(false, "Unexpected promise rejection: " + err.message);
-  }
-  // The request is now "closed", so...
-  await promise_rejects(t, "InvalidStateError", request.abort());
-}, `Calling abort must not change the [[state]] until after "interactive"`);
-
-promise_test(async t => {
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = request.show();
-  try {
-    await request.abort();
-  } catch (err) {
-    assert_true(false, "Unexpected promise rejection: " + err.message);
-  }
-  await promise_rejects(t, "AbortError", acceptPromise);
-  // As request is now "closed", trying to show it will fail
-  await promise_rejects(t, "InvalidStateError", request.show());
-}, "calling .abort() causes acceptPromise to reject and closes the request.");
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
index 971622e8..35fb974 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-constructor.https.html
@@ -41,7 +41,7 @@
 
 test(() => {
   const newDetails = Object.assign({}, defaultDetails, {
-    id: "".padStart(1024, "a"),
+    id: "".padStart(100000000, "\n test 123 \t \n "),
   });
   const request = new PaymentRequest(defaultMethods, newDetails);
   assert_equals(
@@ -305,17 +305,6 @@
   }, `If details.total.amount.value is not a valid decimal monetary value (in this case "${amount}"), then throw a TypeError`);
 }
 
-for (const prop in ["displayItems", "shippingOptions", "modifiers"]) {
-  test(() => {
-    try {
-      const details = Object.assign({}, defaultDetails, { [prop]: [] });
-      new PaymentRequest(defaultMethods, details);
-    } catch (err) {
-      assert_true(false, `${prop} can be zero length`);
-    }
-  }, `PaymentDetailsBase.${prop} can be 0 length`);
-}
-
 test(() => {
   assert_throws(
     {
@@ -386,9 +375,7 @@
       [
         {
           supportedMethods: ["basic-card"],
-          data: {
-            supportedTypes: ["debit"],
-          },
+          data: ["some-data"],
         },
       ],
       {
@@ -423,49 +410,6 @@
   assert_false(itThrows, "shouldn't throw when given a negative value");
 }, "Negative values are allowed for displayItems.amount.value, irrespective of total amount");
 
-test(() => {
-  let itThrows = false;
-  const largeMoney = "1".repeat(510);
-
-  try {
-    new PaymentRequest(
-      [
-        {
-          supportedMethods: ["basic-card"],
-        },
-      ],
-      {
-        total: {
-          label: "",
-          amount: {
-            currency: "USD",
-            value: `${largeMoney}.${largeMoney}`,
-          },
-        },
-        displayItems: [
-          {
-            label: "",
-            amount: {
-              currency: "USD",
-              value: `-${largeMoney}`,
-            },
-          },
-          {
-            label: "",
-            amount: {
-              currency: "AUD",
-              value: `-${largeMoney}.${largeMoney}`,
-            },
-          },
-        ],
-      }
-    );
-  } catch (err) {
-    itThrows = true;
-  }
-  assert_false(itThrows, "shouldn't throw when given absurd monetary values");
-}, "it handles high precision currency values without throwing");
-
 // Process shipping options:
 const defaultAmount = Object.freeze({
   currency: "USD",
@@ -507,11 +451,7 @@
   const shippingOptions = [defaultShippingOption];
   const details = Object.assign({}, defaultDetails, { shippingOptions });
   const request = new PaymentRequest(defaultMethods, details);
-  assert_equals(
-    request.shippingOption,
-    null,
-    "request.shippingOption must be null"
-  );
+  assert_equals(request.shippingOption, null, "request.shippingOption must be null");
 }, "If there is no selected shipping option, then PaymentRequest.shippingOption remains null");
 
 test(() => {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
new file mode 100644
index 0000000..c7173f3f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. Test bug: need to pass exception to assert_throws()
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
index 1bdbba4..d170ea0 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-show-method.https.html
@@ -7,34 +7,34 @@
 <script src="/resources/testharnessreport.js"></script>
 <script>
 'use strict';
-const basicCard = Object.freeze({ supportedMethods: ["basic-card"] });
-const defaultMethods = Object.freeze([basicCard]);
-const defaultDetails = Object.freeze({
-  total: {
-    label: "Total",
-    amount: {
-      currency: "USD",
-      value: "1.00",
+
+promise_test(t => {
+  const request1 = new PaymentRequest([{
+    supportedMethods: ['basic-card'],
+  }], {
+    total: {
+      label: 'request1',
+      amount: {
+        currency: 'USD',
+        value: '1.00',
+      },
     },
-  },
-});
-
-promise_test(async t => {
-  const request = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise = request.show(); // Sets state to "interactive"
-  await promise_rejects(t, "InvalidStateError", request.show());
-  await request.abort();
-  await promise_rejects(t, "AbortError", acceptPromise);
-}, `Throws if the promise [[state]] is not "created"`);
-
-promise_test(async t => {
-  const request1 = new PaymentRequest(defaultMethods, defaultDetails);
-  const request2 = new PaymentRequest(defaultMethods, defaultDetails);
-  const acceptPromise1 = request1.show();
-  const acceptPromise2 = request2.show();
-  await promise_rejects(t, "AbortError", acceptPromise2);
-  await request1.abort();
-  await promise_rejects(t, "AbortError", acceptPromise1);
-}, `If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException.`);
-
+  });
+  const request2 = new PaymentRequest([{
+    supportedMethods: ['basic-card'],
+  }], {
+    total: {
+      label: 'request2',
+      amount: {
+        currency: 'USD',
+        value: '1.00',
+      },
+    },
+  });
+  const result = promise_rejects(t, null, request1.show());
+  promise_rejects(t, 'AbortError', request2.show())
+    .then(t.step_func(() => request1.abort()));
+  return result;
+}, 'If the user agent\'s "payment request is showing" boolean is true, ' +
+   'then return a promise rejected with an "AbortError" DOMException.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh b/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
index 90da2624..970a930 100755
--- a/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
+++ b/third_party/WebKit/LayoutTests/external/wpt/update-built-tests.sh
@@ -2,6 +2,5 @@
 set -ex
 
 2dcontext/tools/build.sh
-assumptions/tools/build.sh
 html/tools/build.sh
 offscreen-canvas/tools/build.sh
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
index 46fd8ae..d3e9354 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/cache-storage/cache-storage-test.js
@@ -5,127 +5,99 @@
 var initialize_CacheStorageTest = function() {
 InspectorTest.preloadPanel("resources");
 
-InspectorTest.dumpCacheTree = function()
+InspectorTest.dumpCacheTree = async function()
 {
     UI.panels.resources._sidebar.cacheStorageListTreeElement.expand();
     InspectorTest.addResult("Dumping CacheStorage tree:");
     var cachesTreeElement = UI.panels.resources._sidebar.cacheStorageListTreeElement;
-    var promise = new Promise(function(resolve, reject) {
-        InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, "_updateCacheNames").then(crawlCacheTree).catch(reject);
-
-        function crawlCacheTree()
-        {
-            if (!cachesTreeElement.childCount()) {
-                InspectorTest.addResult("    (empty)");
-                return resolve();
-            }
-
-            queryView(0);
-
-            function queryView(i)
-            {
-                var cacheTreeElement = cachesTreeElement.childAt(i);
-                InspectorTest.addResult("    cache: " + cacheTreeElement.title);
-                var view = cacheTreeElement._view;
-                InspectorTest.addSniffer(Resources.ServiceWorkerCacheView.prototype, "_updateDataCallback", addDataResult, false);
-                if (!view)
-                    cacheTreeElement.onselect(false);
-                else
-                    view._updateData(true);
-                view = cacheTreeElement._view;
-
-                function addDataResult()
-                {
-                    if (view._entries.length == 0) {
-                        InspectorTest.addResult("        (cache empty)");
-                        nextOrResolve();
-                        return;
-                    }
-                    var dataGrid = view._dataGrid;
-                    for (var node of dataGrid.rootNode().children) {
-                        var entries = [];
-                        for (var j = 0; j < node.element().children.length; j++) {
-                            var td = node.element().children[j];
-                            if (td.textContent)
-                                entries.push(td.textContent);
-                        }
-                        InspectorTest.addResult("        " + entries.join(", "));
-                    }
-                    nextOrResolve();
-                }
-
-                function nextOrResolve()
-                {
-                    var next = i + 1;
-                    if (next < cachesTreeElement.childCount())
-                        queryView(next);
-                    else
-                        resolve();
-                }
-            }
-        }
-    });
+    var promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, "_updateCacheNames");
     UI.panels.resources._sidebar.cacheStorageListTreeElement._refreshCaches();
-    return promise;
+
+    await promise;
+
+    if (!cachesTreeElement.childCount()) {
+        InspectorTest.addResult("    (empty)");
+        return;
+    }
+
+    for (var i = 0; i < cachesTreeElement.childCount(); ++i) {
+        var cacheTreeElement = cachesTreeElement.childAt(i);
+        InspectorTest.addResult("    cache: " + cacheTreeElement.title);
+        var view = cacheTreeElement._view;
+        promise = InspectorTest.addSnifferPromise(Resources.ServiceWorkerCacheView.prototype, "_updateDataCallback");
+        if (!view)
+            cacheTreeElement.onselect(false);
+        else
+            view._updateData(true);
+        view = cacheTreeElement._view;
+
+        await promise;
+
+        if (view._entries.length == 0) {
+            InspectorTest.addResult("        (cache empty)");
+            continue;
+        }
+        var dataGrid = view._dataGrid;
+        for (var node of dataGrid.rootNode().children) {
+            var entries = Array.from(node.element().children, td => td.textContent).filter(text => text);
+            InspectorTest.addResult("        " + entries.join(", "));
+        }
+    }
 }
 
 // If optionalEntry is not specified, then the whole cache is deleted.
-InspectorTest.deleteCacheFromInspector = function(cacheName, optionalEntry)
+InspectorTest.deleteCacheFromInspector = async function(cacheName, optionalEntry)
 {
     UI.panels.resources._sidebar.cacheStorageListTreeElement.expand();
-    if (optionalEntry) {
+    if (optionalEntry)
         InspectorTest.addResult("Deleting CacheStorage entry " + optionalEntry + " in cache " + cacheName);
-    } else {
+    else
         InspectorTest.addResult("Deleting CacheStorage cache " + cacheName);
-    }
     var cachesTreeElement = UI.panels.resources._sidebar.cacheStorageListTreeElement;
-    var promise = new Promise(function(resolve, reject) {
-        InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, "_updateCacheNames")
-            .then(function() {
-                if (!cachesTreeElement.childCount()) {
-                    reject("Error: Could not find CacheStorage cache " + cacheName);
-                    return;
-                }
-                for (var i = 0; i < cachesTreeElement.childCount(); i++) {
-                    var cacheTreeElement = cachesTreeElement.childAt(i);
-                    var title = cacheTreeElement.title;
-                    var elementCacheName = title.substring(0, title.lastIndexOf(" - "));
-                    if (elementCacheName != cacheName)
-                        continue;
-                    if (!optionalEntry) {
-                        // Here we're deleting the whole cache.
-                        InspectorTest.addSniffer(SDK.ServiceWorkerCacheModel.prototype, "_cacheRemoved", resolve)
-                        cacheTreeElement._clearCache();
-                        return;
-                    }
-
-                    // Here we're deleting only the entry.  We verify that it is present in the table.
-                    var view = cacheTreeElement._view;
-                    InspectorTest.addSniffer(Resources.ServiceWorkerCacheView.prototype, "_updateDataCallback", deleteEntryOrReject, false);
-                    if (!view)
-                        cacheTreeElement.onselect(false);
-                    else
-                        view._updateData(true);
-                    view = cacheTreeElement._view;
-
-                    function deleteEntryOrReject()
-                    {
-                        for (var entry of view._entries) {
-                            if (entry.request == optionalEntry) {
-                                view._model.deleteCacheEntry(view._cache, entry.request, resolve);
-                                return;
-                            }
-                        }
-                        reject("Error: Could not find cache entry to delete: " + optionalEntry);
-                        return;
-                    }
-                    return;
-                }
-                reject("Error: Could not find CacheStorage cache " + cacheName);
-            }).catch(reject);
-    });
+    var promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, "_updateCacheNames");
     UI.panels.resources._sidebar.cacheStorageListTreeElement._refreshCaches();
-    return promise;
+
+    await promise;
+
+    if (!cachesTreeElement.childCount()) {
+        throw "Error: Could not find CacheStorage cache " + cacheName;
+        return;
+    }
+
+    for (var i = 0; i < cachesTreeElement.childCount(); i++) {
+        var cacheTreeElement = cachesTreeElement.childAt(i);
+        var title = cacheTreeElement.title;
+        var elementCacheName = title.substring(0, title.lastIndexOf(" - "));
+        if (elementCacheName != cacheName)
+            continue;
+        if (!optionalEntry) {
+            // Here we're deleting the whole cache.
+            promise = InspectorTest.addSnifferPromise(SDK.ServiceWorkerCacheModel.prototype, "_cacheRemoved");
+            cacheTreeElement._clearCache();
+            await promise;
+            return;
+        }
+
+        promise = InspectorTest.addSnifferPromise(Resources.ServiceWorkerCacheView.prototype, "_updateDataCallback");
+        // Here we're deleting only the entry.  We verify that it is present in the table.
+        var view = cacheTreeElement._view;
+        if (!view)
+            cacheTreeElement.onselect(false);
+        else
+            view._updateData(true);
+        view = cacheTreeElement._view;
+
+        await promise;
+
+        var entry = view._entries.find(entry => entry.request === optionalEntry);
+        if (!entry) {
+            throw "Error: Could not find cache entry to delete: " + optionalEntry;
+            return;
+        }
+        await view._model.deleteCacheEntry(view._cache, entry.request);
+        return;
+    }
+    throw "Error: Could not find CacheStorage cache " + cacheName;
 }
 
 InspectorTest.waitForCacheRefresh = function(callback)
diff --git a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index d7e70afa..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index d7e70afa..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index e97e7f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Request failed
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index e97e7f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Request failed
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index e97e7f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Request failed
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index d7e70afa..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt b/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt
deleted file mode 100644
index e97e7f6..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/external/wpt/payment-request/payment-request-show-method.https-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-Harness Error. harness_status.status = 1 , harness_status.message = Request failed
-FAIL Throws if the promise [[state]] is not "created" promise_test: Unhandled rejection with value: object "UnknownError: Request failed"
-FAIL If the user agent's "payment request is showing" boolean is true, then return a promise rejected with an "AbortError" DOMException. assert_throws: function "function () { throw e }" threw object "UnknownError: Request failed" that is not a DOMException AbortError: property "code" is equal to 0, expected 20
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
index 864d96a3e..9cba88ca 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.cpp
@@ -49,14 +49,14 @@
     const v8::Local<v8::Value>& constructor) {
   v8::Local<v8::Map> map =
       EnsureCustomElementRegistryMap(script_state, registry);
-  v8::Local<v8::Value> name_value =
+  v8::Local<v8::Value> id_value =
       map->Get(script_state->GetContext(), constructor).ToLocalChecked();
-  if (!name_value->IsString())
+  if (!id_value->IsUint32())
     return nullptr;
-  AtomicString name = ToCoreAtomicString(name_value.As<v8::String>());
+  uint32_t id = id_value.As<v8::Uint32>()->Value();
 
   // This downcast is safe because only
-  // ScriptCustomElementDefinitions have a name associated with a V8
+  // ScriptCustomElementDefinitions have an ID associated with a V8
   // constructor in the map; see
   // ScriptCustomElementDefinition::create. This relies on three
   // things:
@@ -65,10 +65,8 @@
   //    Audit the use of private properties in general and how the
   //    map is handled--it should never be leaked to script.
   //
-  // 2. CustomElementRegistry does not overwrite definitions with a
-  //    given name--see the CHECK in CustomElementRegistry::define
-  //    --and adds ScriptCustomElementDefinitions to the map without
-  //    fail.
+  // 2. CustomElementRegistry adds ScriptCustomElementDefinitions
+  //    assigned an ID to the lis tof definitions without fail.
   //
   // 3. The relationship between the CustomElementRegistry and its
   //    map is never mixed up; this is guaranteed by the bindings
@@ -79,7 +77,7 @@
   // currently only one implementation of CustomElementDefinition in
   // product code and that is ScriptCustomElementDefinition. But
   // that may change in the future.
-  CustomElementDefinition* definition = registry->DefinitionForName(name);
+  CustomElementDefinition* definition = registry->DefinitionForId(id);
   CHECK(definition);
   return static_cast<ScriptCustomElementDefinition*>(definition);
 }
@@ -88,6 +86,7 @@
     ScriptState* script_state,
     CustomElementRegistry* registry,
     const CustomElementDescriptor& descriptor,
+    CustomElementDefinition::Id id,
     const v8::Local<v8::Object>& constructor,
     const v8::Local<v8::Function>& connected_callback,
     const v8::Local<v8::Function>& disconnected_callback,
@@ -99,13 +98,12 @@
       disconnected_callback, adopted_callback, attribute_changed_callback,
       std::move(observed_attributes));
 
-  // Add a constructor -> name mapping to the registry.
-  v8::Local<v8::Value> name_value =
-      V8String(script_state->GetIsolate(), descriptor.GetName());
+  // Add a constructor -> ID mapping to the registry.
+  v8::Local<v8::Value> id_value =
+      v8::Integer::New(script_state->GetIsolate(), id);
   v8::Local<v8::Map> map =
       EnsureCustomElementRegistryMap(script_state, registry);
-  map->Set(script_state->GetContext(), constructor, name_value)
-      .ToLocalChecked();
+  map->Set(script_state->GetContext(), constructor, id_value).ToLocalChecked();
 
   return definition;
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
index 439a73a0..ad87c58 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinition.h
@@ -32,6 +32,7 @@
       ScriptState*,
       CustomElementRegistry*,
       const CustomElementDescriptor&,
+      CustomElementDefinition::Id,
       const v8::Local<v8::Object>& constructor,
       const v8::Local<v8::Function>& connected_callback,
       const v8::Local<v8::Function>& disconnected_callback,
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
index 1d8c6d4..27cb8fa 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.cpp
@@ -56,23 +56,27 @@
 }
 
 bool ScriptCustomElementDefinitionBuilder::ValueForName(
+    v8::Isolate* isolate,
+    v8::Local<v8::Context>& context,
+    const v8::TryCatch& try_catch,
     const v8::Local<v8::Object>& object,
     const StringView& name,
     v8::Local<v8::Value>& value) const {
-  v8::Isolate* isolate = script_state_->GetIsolate();
-  v8::Local<v8::Context> context = script_state_->GetContext();
   v8::Local<v8::String> name_string = V8AtomicString(isolate, name);
-  v8::TryCatch try_catch(isolate);
   if (!object->Get(context, name_string).ToLocal(&value)) {
     exception_state_.RethrowV8Exception(try_catch.Exception());
     return false;
   }
-  return true;
+  return script_state_->ContextIsValid();
 }
 
 bool ScriptCustomElementDefinitionBuilder::CheckPrototype() {
+  v8::Isolate* isolate = script_state_->GetIsolate();
+  v8::Local<v8::Context> context = script_state_->GetContext();
+  v8::TryCatch try_catch(isolate);
   v8::Local<v8::Value> prototype_value;
-  if (!ValueForName(constructor_, "prototype", prototype_value))
+  if (!ValueForName(isolate, context, try_catch, constructor_, "prototype",
+                    prototype_value))
     return false;
   if (!prototype_value->IsObject()) {
     exception_state_.ThrowTypeError("constructor prototype is not an object");
@@ -85,12 +89,15 @@
 }
 
 bool ScriptCustomElementDefinitionBuilder::CallableForName(
+    v8::Isolate* isolate,
+    v8::Local<v8::Context>& context,
+    const v8::TryCatch& try_catch,
     const StringView& name,
     v8::Local<v8::Function>& callback) const {
   v8::Local<v8::Value> value;
-  if (!ValueForName(prototype_, name, value))
+  if (!ValueForName(isolate, context, try_catch, prototype_, name, value))
     return false;
-  // "undefined" means "omitted", so return true.
+  // "undefined" means "omitted", which is valid.
   if (value->IsUndefined())
     return true;
   if (!value->IsFunction()) {
@@ -102,16 +109,19 @@
   return true;
 }
 
-bool ScriptCustomElementDefinitionBuilder::RetrieveObservedAttributes() {
+bool ScriptCustomElementDefinitionBuilder::RetrieveObservedAttributes(
+    v8::Isolate* isolate,
+    v8::Local<v8::Context>& context,
+    const v8::TryCatch& try_catch) {
   v8::Local<v8::Value> observed_attributes_value;
-  if (!ValueForName(constructor_, "observedAttributes",
-                    observed_attributes_value))
+  if (!ValueForName(isolate, context, try_catch, constructor_,
+                    "observedAttributes", observed_attributes_value))
     return false;
   if (observed_attributes_value->IsUndefined())
     return true;
   Vector<String> list = NativeValueTraits<IDLSequence<IDLString>>::NativeValue(
-      script_state_->GetIsolate(), observed_attributes_value, exception_state_);
-  if (exception_state_.HadException())
+      isolate, observed_attributes_value, exception_state_);
+  if (exception_state_.HadException() || !script_state_->ContextIsValid())
     return false;
   if (list.IsEmpty())
     return true;
@@ -124,19 +134,27 @@
 bool ScriptCustomElementDefinitionBuilder::RememberOriginalProperties() {
   // Spec requires to use values of these properties at the point
   // CustomElementDefinition is built, even if JS changes them afterwards.
-  return CallableForName("connectedCallback", connected_callback_) &&
-         CallableForName("disconnectedCallback", disconnected_callback_) &&
-         CallableForName("adoptedCallback", adopted_callback_) &&
-         CallableForName("attributeChangedCallback",
+  v8::Isolate* isolate = script_state_->GetIsolate();
+  v8::Local<v8::Context> context = script_state_->GetContext();
+  v8::TryCatch try_catch(isolate);
+  return CallableForName(isolate, context, try_catch, "connectedCallback",
+                         connected_callback_) &&
+         CallableForName(isolate, context, try_catch, "disconnectedCallback",
+                         disconnected_callback_) &&
+         CallableForName(isolate, context, try_catch, "adoptedCallback",
+                         adopted_callback_) &&
+         CallableForName(isolate, context, try_catch,
+                         "attributeChangedCallback",
                          attribute_changed_callback_) &&
          (attribute_changed_callback_.IsEmpty() ||
-          RetrieveObservedAttributes());
+          RetrieveObservedAttributes(isolate, context, try_catch));
 }
 
 CustomElementDefinition* ScriptCustomElementDefinitionBuilder::Build(
-    const CustomElementDescriptor& descriptor) {
+    const CustomElementDescriptor& descriptor,
+    CustomElementDefinition::Id id) {
   return ScriptCustomElementDefinition::Create(
-      script_state_.Get(), registry_, descriptor, constructor_,
+      script_state_.Get(), registry_, descriptor, id, constructor_,
       connected_callback_, disconnected_callback_, adopted_callback_,
       attribute_changed_callback_, std::move(observed_attributes_));
 }
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
index c65a67e..ee9c7af 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptCustomElementDefinitionBuilder.h
@@ -41,7 +41,8 @@
   bool CheckConstructorNotRegistered() override;
   bool CheckPrototype() override;
   bool RememberOriginalProperties() override;
-  CustomElementDefinition* Build(const CustomElementDescriptor&) override;
+  CustomElementDefinition* Build(const CustomElementDescriptor&,
+                                 CustomElementDefinition::Id) override;
 
  private:
   static ScriptCustomElementDefinitionBuilder* stack_;
@@ -58,11 +59,20 @@
   HashSet<AtomicString> observed_attributes_;
   ExceptionState& exception_state_;
 
-  bool ValueForName(const v8::Local<v8::Object>&,
+  bool ValueForName(v8::Isolate*,
+                    v8::Local<v8::Context>&,
+                    const v8::TryCatch&,
+                    const v8::Local<v8::Object>&,
                     const StringView&,
                     v8::Local<v8::Value>&) const;
-  bool CallableForName(const StringView&, v8::Local<v8::Function>&) const;
-  bool RetrieveObservedAttributes();
+  bool CallableForName(v8::Isolate*,
+                       v8::Local<v8::Context>&,
+                       const v8::TryCatch&,
+                       const StringView&,
+                       v8::Local<v8::Function>&) const;
+  bool RetrieveObservedAttributes(v8::Isolate*,
+                                  v8::Local<v8::Context>&,
+                                  const v8::TryCatch&);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn b/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
index 961fabe..82d9b97d 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
+++ b/third_party/WebKit/Source/bindings/modules/v8/BUILD.gn
@@ -15,7 +15,6 @@
     ":bindings_modules_v8_generated_init_partial",
     ":generate_bindings_modules_v8_interfaces",
     ":generate_bindings_modules_v8_partial_interfaces",
-    ":generate_bindings_modules_v8_partial_interfaces_for_testing",
   ]
 }
 
@@ -36,14 +35,8 @@
 }
 
 idl_compiler("generate_bindings_modules_v8_partial_interfaces") {
-  sources = core_idl_with_modules_dependency_files
-  output_dir = bindings_modules_v8_output_dir
-  output_name_suffix = "Partial"
-  target_component = "modules"
-}
-
-idl_compiler("generate_bindings_modules_v8_partial_interfaces_for_testing") {
-  sources = webcore_testing_idl_with_modules_dependency_files
+  sources = core_idl_with_modules_dependency_files +
+            webcore_testing_idl_with_modules_dependency_files
   output_dir = bindings_modules_v8_output_dir
   output_name_suffix = "Partial"
   target_component = "modules"
@@ -75,17 +68,3 @@
     "//third_party/WebKit/Source/bindings/modules:interfaces_info",
   ]
 }
-
-blink_modules_sources("bindings_modules_impl") {
-  # ":generate_bindings_modules_v8_partial_interfaces_for_testing" is not
-  # included here.
-  sources =
-      get_target_outputs(":generate_bindings_modules_v8_interfaces") +
-      get_target_outputs(":bindings_modules_impl_generated") +
-      get_target_outputs(":generate_bindings_modules_v8_partial_interfaces") +
-      get_target_outputs(":bindings_modules_v8_generated_init_partial")
-
-  deps = [
-    ":bindings_modules_generated",
-  ]
-}
diff --git a/third_party/WebKit/Source/bindings/modules/v8/generated.gni b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
index bf4e8da5..fda0235 100644
--- a/third_party/WebKit/Source/bindings/modules/v8/generated.gni
+++ b/third_party/WebKit/Source/bindings/modules/v8/generated.gni
@@ -82,3 +82,19 @@
   "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.cpp",
   "$bindings_modules_v8_output_dir/RemotePlaybackAvailabilityCallback.h",
 ]
+
+bindings_modules_generated_interface_files =
+    process_file_template(
+        modules_definition_idl_files,
+        [
+          "$bindings_modules_v8_output_dir/V8{{source_name_part}}.cpp",
+          "$bindings_modules_v8_output_dir/V8{{source_name_part}}.h",
+        ])
+
+bindings_modules_generated_partial_interface_files =
+    process_file_template(
+        core_idl_with_modules_dependency_files,
+        [
+          "$bindings_modules_v8_output_dir/V8{{source_name_part}}Partial.cpp",
+          "$bindings_modules_v8_output_dir/V8{{source_name_part}}Partial.h",
+        ])
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
index 15b6061..5251ae4 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinition.h
@@ -29,6 +29,10 @@
   WTF_MAKE_NONCOPYABLE(CustomElementDefinition);
 
  public:
+  // Each definition has an ID that is unique within the
+  // CustomElementRegistry that created it.
+  using Id = uint32_t;
+
   CustomElementDefinition(const CustomElementDescriptor&);
   CustomElementDefinition(const CustomElementDescriptor&,
                           const HashSet<AtomicString>&);
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinitionBuilder.h b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinitionBuilder.h
index 202d984..0988b3fb 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementDefinitionBuilder.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementDefinitionBuilder.h
@@ -6,12 +6,12 @@
 #define CustomElementDefinitionBuilder_h
 
 #include "core/CoreExport.h"
+#include "core/dom/custom/CustomElementDefinition.h"
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Noncopyable.h"
 
 namespace blink {
 
-class CustomElementDefinition;
 class CustomElementDescriptor;
 class CustomElementRegistry;
 
@@ -46,7 +46,8 @@
   virtual bool RememberOriginalProperties() = 0;
 
   // Produce the definition. This must produce a definition.
-  virtual CustomElementDefinition* Build(const CustomElementDescriptor&) = 0;
+  virtual CustomElementDefinition* Build(const CustomElementDescriptor&,
+                                         CustomElementDefinition::Id) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.cpp
index 18bf29f..f05d309 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.cpp
@@ -26,6 +26,8 @@
 #include "platform/instrumentation/tracing/TraceEvent.h"
 #include "platform/wtf/Allocator.h"
 
+#include <limits>
+
 namespace blink {
 
 // Returns true if |name| is invalid.
@@ -93,7 +95,7 @@
 
 DEFINE_TRACE_WRAPPERS(CustomElementRegistry) {
   visitor->TraceWrappers(&CustomElementReactionStack::Current());
-  for (auto definition : definitions_.Values())
+  for (auto definition : definitions_)
     visitor->TraceWrappers(definition);
 }
 
@@ -185,12 +187,16 @@
   }
 
   CustomElementDescriptor descriptor(name, local_name);
-  CustomElementDefinition* definition = builder.Build(descriptor);
+  if (UNLIKELY(definitions_.size() >=
+               std::numeric_limits<CustomElementDefinition::Id>::max()))
+    return nullptr;
+  CustomElementDefinition::Id id = definitions_.size() + 1;
+  CustomElementDefinition* definition = builder.Build(descriptor, id);
   CHECK(!exception_state.HadException());
   CHECK(definition->Descriptor() == descriptor);
-  DefinitionMap::AddResult result = definitions_.insert(
-      descriptor.GetName(),
+  definitions_.emplace_back(
       TraceWrapperMember<CustomElementDefinition>(this, definition));
+  NameIdMap::AddResult result = name_id_map_.insert(descriptor.GetName(), id);
   CHECK(result.is_new_entry);
 
   HeapVector<Member<Element>> candidates;
@@ -237,7 +243,7 @@
 }
 
 bool CustomElementRegistry::NameIsDefined(const AtomicString& name) const {
-  return definitions_.Contains(name);
+  return name_id_map_.Contains(name);
 }
 
 void CustomElementRegistry::Entangle(V0CustomElementRegistrationContext* v0) {
@@ -255,7 +261,12 @@
 
 CustomElementDefinition* CustomElementRegistry::DefinitionForName(
     const AtomicString& name) const {
-  return definitions_.at(name);
+  return DefinitionForId(name_id_map_.at(name));
+}
+
+CustomElementDefinition* CustomElementRegistry::DefinitionForId(
+    CustomElementDefinition::Id id) const {
+  return id ? definitions_[id - 1].Get() : nullptr;
 }
 
 void CustomElementRegistry::AddCandidate(Element* candidate) {
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.h b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.h
index fba6ad6..ca7a67d61 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistry.h
@@ -18,7 +18,6 @@
 
 namespace blink {
 
-class CustomElementDefinition;
 class CustomElementDefinitionBuilder;
 class CustomElementDescriptor;
 class Element;
@@ -55,6 +54,7 @@
   ScriptValue get(const AtomicString& name);
   bool NameIsDefined(const AtomicString& name) const;
   CustomElementDefinition* DefinitionForName(const AtomicString& name) const;
+  CustomElementDefinition* DefinitionForId(CustomElementDefinition::Id) const;
 
   // TODO(dominicc): Switch most callers of definitionForName to
   // definitionFor when implementing type extensions.
@@ -85,9 +85,12 @@
   class ElementDefinitionIsRunning;
   bool element_definition_is_running_;
 
-  using DefinitionMap =
-      HeapHashMap<AtomicString, TraceWrapperMember<CustomElementDefinition>>;
-  DefinitionMap definitions_;
+  using DefinitionList =
+      HeapVector<TraceWrapperMember<CustomElementDefinition>>;
+  DefinitionList definitions_;
+
+  using NameIdMap = HashMap<AtomicString, size_t>;
+  NameIdMap name_id_map_;
 
   Member<const LocalDOMWindow> owner_;
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp
index 79da0fc9..083ed72d9 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementRegistryTest.cpp
@@ -265,8 +265,8 @@
  public:
   LogUpgradeBuilder() {}
 
-  CustomElementDefinition* Build(
-      const CustomElementDescriptor& descriptor) override {
+  CustomElementDefinition* Build(const CustomElementDescriptor& descriptor,
+                                 CustomElementDefinition::Id) override {
     return new LogUpgradeDefinition(descriptor);
   }
 };
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.cpp
index 4a14473..09cdd77 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.cpp
@@ -7,7 +7,8 @@
 namespace blink {
 
 CustomElementDefinition* TestCustomElementDefinitionBuilder::Build(
-    const CustomElementDescriptor& descriptor) {
+    const CustomElementDescriptor& descriptor,
+    CustomElementDefinition::Id) {
   return new TestCustomElementDefinition(descriptor);
 }
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.h b/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.h
index 7d5c9bb..cd5ff42 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementTestHelpers.h
@@ -35,7 +35,8 @@
   bool CheckConstructorNotRegistered() override { return true; }
   bool CheckPrototype() override { return true; }
   bool RememberOriginalProperties() override { return true; }
-  CustomElementDefinition* Build(const CustomElementDescriptor&) override;
+  CustomElementDefinition* Build(const CustomElementDescriptor&,
+                                 CustomElementDefinition::Id) override;
 };
 
 class TestCustomElementDefinition : public CustomElementDefinition {
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 0dd8a65..180773f 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -107,13 +107,13 @@
 // removed.
 static Position AnchorPosition(const VisibleSelection& selection) {
   Position anchor =
-      selection.IsBaseFirst() ? selection.Start() : selection.end();
+      selection.IsBaseFirst() ? selection.Start() : selection.End();
   return anchor.ParentAnchoredEquivalent();
 }
 
 static Position FocusPosition(const VisibleSelection& selection) {
   Position focus =
-      selection.IsBaseFirst() ? selection.end() : selection.Start();
+      selection.IsBaseFirst() ? selection.End() : selection.Start();
   return focus.ParentAnchoredEquivalent();
 }
 
diff --git a/third_party/WebKit/Source/core/editing/EditingStyle.cpp b/third_party/WebKit/Source/core/editing/EditingStyle.cpp
index b9a0451..c0661d8 100644
--- a/third_party/WebKit/Source/core/editing/EditingStyle.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingStyle.cpp
@@ -816,7 +816,7 @@
         }
       }
     }
-    if (&node == selection.end().AnchorNode())
+    if (&node == selection.End().AnchorNode())
       break;
   }
 
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp
index fa0e682..39b82fa 100644
--- a/third_party/WebKit/Source/core/editing/Editor.cpp
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1592,7 +1592,7 @@
   // TODO(yosin) We should make |findRangeOfString()| to return
   // |EphemeralRange| rather than|Range| object.
   Range* result_range = FindRangeOfString(
-      target, EphemeralRange(selection.Start(), selection.end()),
+      target, EphemeralRange(selection.Start(), selection.End()),
       static_cast<FindOptions>(options | kFindAPICall));
 
   if (!result_range)
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 2c1d365..755cd84 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -454,7 +454,7 @@
   const PositionInFlatTree& focused_position =
       PositionInFlatTree::FirstPositionInNode(focused_element);
   if (ComputeVisibleSelectionInFlatTree().Start() <= focused_position &&
-      ComputeVisibleSelectionInFlatTree().end() >= focused_position)
+      ComputeVisibleSelectionInFlatTree().End() >= focused_position)
     return true;
 
   bool has_editable_style = HasEditableStyle(*current);
@@ -955,7 +955,7 @@
 static IntRect AbsoluteSelectionBoundsOf(
     const VisibleSelectionInFlatTree& selection) {
   return ComputeTextRect(
-      EphemeralRangeInFlatTree(selection.Start(), selection.end()));
+      EphemeralRangeInFlatTree(selection.Start(), selection.End()));
 }
 
 // TODO(editing-dev): This should be done in FlatTree world.
diff --git a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
index d2f1961..83c0b38 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp
@@ -173,10 +173,10 @@
   Selection().Modify(FrameSelection::kAlterationExtend, kDirectionForward,
                      kWordGranularity);
   EXPECT_EQ(Position(two, 0), VisibleSelectionInDOMTree().Start());
-  EXPECT_EQ(Position(two, 3), VisibleSelectionInDOMTree().end());
+  EXPECT_EQ(Position(two, 3), VisibleSelectionInDOMTree().End());
   EXPECT_EQ(PositionInFlatTree(two, 0),
             GetVisibleSelectionInFlatTree().Start());
-  EXPECT_EQ(PositionInFlatTree(two, 3), GetVisibleSelectionInFlatTree().end());
+  EXPECT_EQ(PositionInFlatTree(two, 3), GetVisibleSelectionInFlatTree().End());
 }
 
 TEST_F(FrameSelectionTest, ModifyWithUserTriggered) {
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index 6cc9533..33eb315 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -465,7 +465,9 @@
       continue;
 
     GetDocument().Markers().AddCompositionMarker(
-        ephemeral_line_range, underline.GetColor(), underline.Thick(),
+        ephemeral_line_range, underline.GetColor(),
+        underline.Thick() ? CompositionMarker::Thickness::kThick
+                          : CompositionMarker::Thickness::kThin,
         underline.BackgroundColor());
   }
 }
@@ -689,7 +691,8 @@
 
   if (underlines.IsEmpty()) {
     GetDocument().Markers().AddCompositionMarker(
-        EphemeralRange(composition_range_), Color::kBlack, false,
+        EphemeralRange(composition_range_), Color::kBlack,
+        CompositionMarker::Thickness::kThin,
         LayoutTheme::GetTheme().PlatformDefaultCompositionBackgroundColor());
     return;
   }
@@ -899,7 +902,7 @@
                    .Start() == GetFrame()
                                    .Selection()
                                    .ComputeVisibleSelectionInDOMTreeDeprecated()
-                                   .end() &&
+                                   .End() &&
            before <= static_cast<int>(selection_offsets.Start()));
   // TODO(chongz): Find a way to distinguish Forward and Backward.
   Node* target = GetDocument().FocusedElement();
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
index 3d6ac8c..1deae42 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -202,7 +202,7 @@
   EXPECT_EQ(2, GetFrame()
                    .Selection()
                    .ComputeVisibleSelectionInDOMTreeDeprecated()
-                   .end()
+                   .End()
                    .ComputeOffsetInContainerNode());
 
   Controller().SetComposition(String("a"), underlines, 1, 1);
@@ -416,7 +416,7 @@
   EXPECT_EQ(0, GetFrame()
                    .Selection()
                    .ComputeVisibleSelectionInDOMTreeDeprecated()
-                   .end()
+                   .End()
                    .ComputeOffsetInContainerNode());
 }
 
diff --git a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
index 82cebfdf..3beb027 100644
--- a/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/LayoutSelection.cpp
@@ -83,7 +83,7 @@
     const VisibleSelectionInFlatTree& original_selection,
     bool should_show_blok_cursor) {
   const PositionInFlatTree& start = original_selection.Start();
-  const PositionInFlatTree& end = original_selection.end();
+  const PositionInFlatTree& end = original_selection.End();
   SelectionType selection_type = original_selection.GetSelectionType();
   const TextAffinity affinity = original_selection.Affinity();
 
@@ -344,7 +344,7 @@
       MostForwardCaretPosition(start_pos);
   if (IsVisuallyEquivalentCandidate(most_forward_start))
     start_pos = most_forward_start;
-  PositionInFlatTree end_pos = selection.end();
+  PositionInFlatTree end_pos = selection.End();
   const PositionInFlatTree most_backward = MostBackwardCaretPosition(end_pos);
   if (IsVisuallyEquivalentCandidate(most_backward))
     end_pos = most_backward;
diff --git a/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp b/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp
index 6d2ba19..2ed10f7 100644
--- a/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionAdjuster.cpp
@@ -159,24 +159,24 @@
   DCHECK(selection->Base().IsNotNull());
   DCHECK(selection->Extent().IsNotNull());
   DCHECK(selection->Start().IsNotNull());
-  DCHECK(selection->end().IsNotNull());
+  DCHECK(selection->End().IsNotNull());
 
   // TODO(hajimehoshi): Checking treeScope is wrong when a node is
   // distributed, but we leave it as it is for backward compatibility.
   if (selection->Start().AnchorNode()->GetTreeScope() ==
-      selection->end().AnchorNode()->GetTreeScope())
+      selection->End().AnchorNode()->GetTreeScope())
     return;
 
   if (selection->IsBaseFirst()) {
     const Position& new_end = AdjustPositionForEnd(
-        selection->end(), selection->Start().ComputeContainerNode());
+        selection->End(), selection->Start().ComputeContainerNode());
     selection->extent_ = new_end;
     selection->end_ = new_end;
     return;
   }
 
   const Position& new_start = AdjustPositionForStart(
-      selection->Start(), selection->end().ComputeContainerNode());
+      selection->Start(), selection->End().ComputeContainerNode());
   selection->extent_ = new_start;
   selection->start_ = new_start;
 }
@@ -188,7 +188,7 @@
     VisibleSelectionInFlatTree* selection) {
   Node* const shadow_host_start =
       EnclosingShadowHostForStart(selection->Start());
-  Node* const shadow_host_end = EnclosingShadowHostForEnd(selection->end());
+  Node* const shadow_host_end = EnclosingShadowHostForEnd(selection->End());
   if (shadow_host_start == shadow_host_end)
     return;
 
@@ -196,7 +196,7 @@
     Node* const shadow_host =
         shadow_host_start ? shadow_host_start : shadow_host_end;
     const PositionInFlatTree& new_end =
-        AdjustPositionInFlatTreeForEnd(selection->end(), shadow_host);
+        AdjustPositionInFlatTreeForEnd(selection->End(), shadow_host);
     selection->extent_ = new_end;
     selection->end_ = new_end;
     return;
diff --git a/third_party/WebKit/Source/core/editing/SelectionController.cpp b/third_party/WebKit/Source/core/editing/SelectionController.cpp
index 85273a90..3a8f03e 100644
--- a/third_party/WebKit/Source/core/editing/SelectionController.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionController.cpp
@@ -150,8 +150,8 @@
     return position;
   if (selection_in_user_select_all.Start().CompareTo(selection_start) < 0)
     return selection_in_user_select_all.Start();
-  if (selection_end.CompareTo(selection_in_user_select_all.end()) < 0)
-    return selection_in_user_select_all.end();
+  if (selection_end.CompareTo(selection_in_user_select_all.End()) < 0)
+    return selection_in_user_select_all.End();
   return position;
 }
 
@@ -210,7 +210,7 @@
     // Note: "fast/events/shift-click-user-select-none.html" makes
     // |pos.isNull()| true.
     const PositionInFlatTree& pos = AdjustPositionRespectUserSelectAll(
-        inner_node, selection.Start(), selection.end(),
+        inner_node, selection.Start(), selection.End(),
         visible_pos.DeepEquivalent());
     SelectionInFlatTree::Builder builder;
     builder.SetGranularity(this->Selection().Granularity());
@@ -221,7 +221,7 @@
     } else {
       // Shift+Click deselects when selection was created right-to-left
       const PositionInFlatTree& start = selection.Start();
-      const PositionInFlatTree& end = selection.end();
+      const PositionInFlatTree& end = selection.End();
       if (pos < start) {
         // |distance_to_start < distance_to_end|.
         builder.SetBaseAndExtent(end, pos);
@@ -496,7 +496,7 @@
   if (select_input_event_type == SelectInputEventType::kTouch) {
     // If node doesn't have text except space, tab or line break, do not
     // select that 'empty' area.
-    EphemeralRangeInFlatTree range(new_selection.Start(), new_selection.end());
+    EphemeralRangeInFlatTree range(new_selection.Start(), new_selection.End());
     const String& str = PlainText(
         range,
         TextIteratorBehavior::Builder()
diff --git a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
index 52cb1bfe..f386227 100644
--- a/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionControllerTest.cpp
@@ -69,7 +69,7 @@
   EXPECT_EQ(Position(top, 1), VisibleSelectionInDOMTree().Base());
   EXPECT_EQ(Position::BeforeNode(host), VisibleSelectionInDOMTree().Extent());
   EXPECT_EQ(Position(top, 1), VisibleSelectionInDOMTree().Start());
-  EXPECT_EQ(Position(top, 3), VisibleSelectionInDOMTree().end());
+  EXPECT_EQ(Position(top, 3), VisibleSelectionInDOMTree().End());
 
   EXPECT_EQ(PositionInFlatTree(top, 1), GetVisibleSelectionInFlatTree().Base());
   EXPECT_EQ(PositionInFlatTree(bottom, 3),
@@ -77,7 +77,7 @@
   EXPECT_EQ(PositionInFlatTree(top, 1),
             GetVisibleSelectionInFlatTree().Start());
   EXPECT_EQ(PositionInFlatTree(bottom, 3),
-            GetVisibleSelectionInFlatTree().end());
+            GetVisibleSelectionInFlatTree().End());
 
   // bottom to top
   SetNonDirectionalSelectionIfNeeded(
@@ -90,7 +90,7 @@
   EXPECT_EQ(Position::BeforeNode(bottom->parentNode()),
             VisibleSelectionInDOMTree().Extent());
   EXPECT_EQ(Position(bottom, 0), VisibleSelectionInDOMTree().Start());
-  EXPECT_EQ(Position(bottom, 3), VisibleSelectionInDOMTree().end());
+  EXPECT_EQ(Position(bottom, 3), VisibleSelectionInDOMTree().End());
 
   EXPECT_EQ(PositionInFlatTree(bottom, 3),
             GetVisibleSelectionInFlatTree().Base());
@@ -99,7 +99,7 @@
   EXPECT_EQ(PositionInFlatTree(top, 1),
             GetVisibleSelectionInFlatTree().Start());
   EXPECT_EQ(PositionInFlatTree(bottom, 3),
-            GetVisibleSelectionInFlatTree().end());
+            GetVisibleSelectionInFlatTree().End());
 }
 
 TEST_F(SelectionControllerTest, setCaretAtHitTestResult) {
diff --git a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
index 2791202..1f08e08 100644
--- a/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionModifier.cpp
@@ -138,8 +138,8 @@
   const bool base_is_start = IsBaseStart(visible_selection, direction);
   return SelectionInDOMTree::Builder(visible_selection.AsSelection())
       .Collapse(base_is_start ? visible_selection.Start()
-                              : visible_selection.end())
-      .Extend(base_is_start ? visible_selection.end()
+                              : visible_selection.End())
+      .Extend(base_is_start ? visible_selection.End()
                             : visible_selection.Start())
       .Build();
 }
@@ -289,7 +289,7 @@
             CreateVisiblePosition(selection_.Extent(), selection_.Affinity()));
       }
       if (DirectionOfSelection() == TextDirection::kLtr)
-        return CreateVisiblePosition(selection_.end(), selection_.Affinity());
+        return CreateVisiblePosition(selection_.End(), selection_.Affinity());
       return CreateVisiblePosition(selection_.Start(), selection_.Affinity());
     case kWordGranularity: {
       const bool skips_space_when_moving_right =
@@ -322,7 +322,7 @@
   switch (granularity) {
     case kCharacterGranularity:
       if (selection_.IsRange())
-        pos = CreateVisiblePosition(selection_.end(), selection_.Affinity());
+        pos = CreateVisiblePosition(selection_.End(), selection_.Affinity());
       else
         pos = NextPositionOf(
             CreateVisiblePosition(selection_.Extent(), selection_.Affinity()),
@@ -474,7 +474,7 @@
       }
       if (DirectionOfSelection() == TextDirection::kLtr)
         return CreateVisiblePosition(selection_.Start(), selection_.Affinity());
-      return CreateVisiblePosition(selection_.end(), selection_.Affinity());
+      return CreateVisiblePosition(selection_.End(), selection_.Affinity());
     case kWordGranularity: {
       const bool skips_space_when_moving_right =
           GetFrame() &&
@@ -727,7 +727,7 @@
     case FrameSelection::kAlterationMove:
       pos = CreateVisiblePosition(direction == FrameSelection::kDirectionUp
                                       ? selection_.Start()
-                                      : selection_.end(),
+                                      : selection_.End(),
                                   selection_.Affinity());
       x_pos = LineDirectionPointForBlockDirectionNavigation(
           direction == FrameSelection::kDirectionUp ? START : END);
@@ -837,7 +837,7 @@
       pos = selection_.Start();
       break;
     case END:
-      pos = selection_.end();
+      pos = selection_.End();
       break;
     case BASE:
       pos = selection_.Base();
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index e3f650e..0d2f103 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -140,7 +140,7 @@
   if (selection.IsNone())
     return EphemeralRange();
   Position start = selection.Start().ParentAnchoredEquivalent();
-  Position end = selection.end().ParentAnchoredEquivalent();
+  Position end = selection.End().ParentAnchoredEquivalent();
   return EphemeralRange(start, end);
 }
 
@@ -686,7 +686,7 @@
   const VisibleSelectionTemplate<Strategy> selection_wrapper2(selection2);
 
   return selection_wrapper1.Start() == selection_wrapper2.Start() &&
-         selection_wrapper1.end() == selection_wrapper2.end() &&
+         selection_wrapper1.End() == selection_wrapper2.End() &&
          selection_wrapper1.Base() == selection_wrapper2.Base() &&
          selection_wrapper1.Extent() == selection_wrapper2.Extent();
 }
@@ -715,12 +715,12 @@
             << Start()
                    .AnchorNode()
                    ->ToMarkedTreeString(Start().AnchorNode(), "S",
-                                        end().AnchorNode(), "E")
+                                        End().AnchorNode(), "E")
                    .Utf8()
                    .data()
             << "start: " << Start().ToAnchorTypeAndOffsetString().Utf8().data()
             << "\n"
-            << "end: " << end().ToAnchorTypeAndOffsetString().Utf8().data();
+            << "end: " << End().ToAnchorTypeAndOffsetString().Utf8().data();
 }
 
 #endif
@@ -735,7 +735,7 @@
   }
   *ostream << "VisibleSelection(base: " << selection.Base()
            << " extent:" << selection.Extent()
-           << " start: " << selection.Start() << " end: " << selection.end()
+           << " start: " << selection.Start() << " end: " << selection.End()
            << ' ' << selection.Affinity() << ' '
            << (selection.IsDirectional() ? "Directional" : "NonDirectional")
            << ')';
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h
index 37d60f7e..11a85d0 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.h
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -69,7 +69,7 @@
   PositionTemplate<Strategy> Base() const { return base_; }
   PositionTemplate<Strategy> Extent() const { return extent_; }
   PositionTemplate<Strategy> Start() const { return start_; }
-  PositionTemplate<Strategy> end() const { return end_; }
+  PositionTemplate<Strategy> End() const { return end_; }
 
   VisiblePositionTemplate<Strategy> VisibleStart() const {
     return CreateVisiblePosition(
@@ -101,10 +101,10 @@
   bool IsCaret() const { return GetSelectionType() == kCaretSelection; }
   bool IsRange() const { return GetSelectionType() == kRangeSelection; }
   bool IsNonOrphanedRange() const {
-    return IsRange() && !Start().IsOrphan() && !end().IsOrphan();
+    return IsRange() && !Start().IsOrphan() && !End().IsOrphan();
   }
   bool IsNonOrphanedCaretOrRange() const {
-    return !IsNone() && !Start().IsOrphan() && !end().IsOrphan();
+    return !IsNone() && !Start().IsOrphan() && !End().IsOrphan();
   }
 
   // True if base() <= extent().
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp b/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
index 4b46eb5..3006f6dc 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelectionTest.cpp
@@ -53,7 +53,7 @@
   // to DOM tree position.
   EXPECT_EQ(selection.Start(),
             ToPositionInDOMTree(selection_in_flat_tree.Start()));
-  EXPECT_EQ(selection.end(), ToPositionInDOMTree(selection_in_flat_tree.end()));
+  EXPECT_EQ(selection.End(), ToPositionInDOMTree(selection_in_flat_tree.End()));
   EXPECT_EQ(selection.Base(),
             ToPositionInDOMTree(selection_in_flat_tree.Base()));
   EXPECT_EQ(selection.Extent(),
@@ -91,7 +91,7 @@
   selection.AppendTrailingWhitespace();
 
   EXPECT_EQ(Position::BeforeNode(input), selection.Start());
-  EXPECT_EQ(Position::AfterNode(input), selection.end());
+  EXPECT_EQ(Position::AfterNode(input), selection.End());
 }
 
 TEST_F(VisibleSelectionTest, expandUsingGranularity) {
@@ -127,12 +127,12 @@
   EXPECT_EQ(Position(one, 1), selection.Base());
   EXPECT_EQ(Position(one, 1), selection.Extent());
   EXPECT_EQ(Position(one, 0), selection.Start());
-  EXPECT_EQ(Position(two, 2), selection.end());
+  EXPECT_EQ(Position(two, 2), selection.End());
 
   EXPECT_EQ(PositionInFlatTree(one, 1), selection_in_flat_tree.Base());
   EXPECT_EQ(PositionInFlatTree(one, 1), selection_in_flat_tree.Extent());
   EXPECT_EQ(PositionInFlatTree(one, 0), selection_in_flat_tree.Start());
-  EXPECT_EQ(PositionInFlatTree(five, 5), selection_in_flat_tree.end());
+  EXPECT_EQ(PositionInFlatTree(five, 5), selection_in_flat_tree.End());
 
   // From a position at distributed node
   selection = CreateVisibleSelection(
@@ -148,12 +148,12 @@
   EXPECT_EQ(Position(two, 1), selection.Base());
   EXPECT_EQ(Position(two, 1), selection.Extent());
   EXPECT_EQ(Position(one, 0), selection.Start());
-  EXPECT_EQ(Position(two, 2), selection.end());
+  EXPECT_EQ(Position(two, 2), selection.End());
 
   EXPECT_EQ(PositionInFlatTree(two, 1), selection_in_flat_tree.Base());
   EXPECT_EQ(PositionInFlatTree(two, 1), selection_in_flat_tree.Extent());
   EXPECT_EQ(PositionInFlatTree(three, 0), selection_in_flat_tree.Start());
-  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.end());
+  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.End());
 
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
@@ -169,12 +169,12 @@
   EXPECT_EQ(Position(three, 1), selection.Base());
   EXPECT_EQ(Position(three, 1), selection.Extent());
   EXPECT_EQ(Position(three, 0), selection.Start());
-  EXPECT_EQ(Position(four, 4), selection.end());
+  EXPECT_EQ(Position(four, 4), selection.End());
 
   EXPECT_EQ(PositionInFlatTree(three, 1), selection_in_flat_tree.Base());
   EXPECT_EQ(PositionInFlatTree(three, 1), selection_in_flat_tree.Extent());
   EXPECT_EQ(PositionInFlatTree(three, 0), selection_in_flat_tree.Start());
-  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.end());
+  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.End());
 
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
@@ -190,12 +190,12 @@
   EXPECT_EQ(Position(four, 1), selection.Base());
   EXPECT_EQ(Position(four, 1), selection.Extent());
   EXPECT_EQ(Position(three, 0), selection.Start());
-  EXPECT_EQ(Position(four, 4), selection.end());
+  EXPECT_EQ(Position(four, 4), selection.End());
 
   EXPECT_EQ(PositionInFlatTree(four, 1), selection_in_flat_tree.Base());
   EXPECT_EQ(PositionInFlatTree(four, 1), selection_in_flat_tree.Extent());
   EXPECT_EQ(PositionInFlatTree(three, 0), selection_in_flat_tree.Start());
-  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.end());
+  EXPECT_EQ(PositionInFlatTree(four, 4), selection_in_flat_tree.End());
 
   // From a position at node in shadow tree
   selection = CreateVisibleSelection(
@@ -211,12 +211,12 @@
   EXPECT_EQ(Position(five, 1), selection.Base());
   EXPECT_EQ(Position(five, 1), selection.Extent());
   EXPECT_EQ(Position(five, 0), selection.Start());
-  EXPECT_EQ(Position(five, 5), selection.end());
+  EXPECT_EQ(Position(five, 5), selection.End());
 
   EXPECT_EQ(PositionInFlatTree(five, 1), selection_in_flat_tree.Base());
   EXPECT_EQ(PositionInFlatTree(five, 1), selection_in_flat_tree.Extent());
   EXPECT_EQ(PositionInFlatTree(one, 0), selection_in_flat_tree.Start());
-  EXPECT_EQ(PositionInFlatTree(five, 5), selection_in_flat_tree.end());
+  EXPECT_EQ(PositionInFlatTree(five, 5), selection_in_flat_tree.End());
 }
 
 TEST_F(VisibleSelectionTest, Initialisation) {
@@ -303,11 +303,11 @@
 
   EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor),
             selection.Start());
-  EXPECT_EQ(Position(one->firstChild(), 0), selection.end());
+  EXPECT_EQ(Position(one->firstChild(), 0), selection.End());
   EXPECT_EQ(PositionInFlatTree(one->firstChild(), 0),
             selection_in_flat_tree.Start());
   EXPECT_EQ(PositionInFlatTree(six->firstChild(), 2),
-            selection_in_flat_tree.end());
+            selection_in_flat_tree.End());
 }
 
 TEST_F(VisibleSelectionTest, ShadowV0DistributedNodes) {
@@ -337,11 +337,11 @@
           .Build());
 
   EXPECT_EQ(Position(one->firstChild(), 0), selection.Start());
-  EXPECT_EQ(Position(two->firstChild(), 2), selection.end());
+  EXPECT_EQ(Position(two->firstChild(), 2), selection.End());
   EXPECT_EQ(PositionInFlatTree(five->firstChild(), 0),
             selection_in_flat_tree.Start());
   EXPECT_EQ(PositionInFlatTree(five->firstChild(), 2),
-            selection_in_flat_tree.end());
+            selection_in_flat_tree.End());
 }
 
 TEST_F(VisibleSelectionTest, ShadowNested) {
@@ -384,11 +384,11 @@
 
   EXPECT_EQ(Position(host, PositionAnchorType::kBeforeAnchor),
             selection.Start());
-  EXPECT_EQ(Position(one->firstChild(), 0), selection.end());
+  EXPECT_EQ(Position(one->firstChild(), 0), selection.End());
   EXPECT_EQ(PositionInFlatTree(eight->firstChild(), 2),
             selection_in_flat_tree.Start());
   EXPECT_EQ(PositionInFlatTree(eight->firstChild(), 2),
-            selection_in_flat_tree.end());
+            selection_in_flat_tree.End());
 }
 
 TEST_F(VisibleSelectionTest, WordGranularity) {
diff --git a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
index d707fdeb..b2cda7c3 100644
--- a/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ApplyStyleCommand.cpp
@@ -118,7 +118,7 @@
       input_type_(input_type),
       property_level_(property_level),
       start_(MostForwardCaretPosition(EndingSelection().Start())),
-      end_(MostBackwardCaretPosition(EndingSelection().end())),
+      end_(MostBackwardCaretPosition(EndingSelection().End())),
       use_ending_selection_(true),
       styled_inline_element_(nullptr),
       remove_only_(false),
@@ -145,7 +145,7 @@
       input_type_(InputEvent::InputType::kNone),
       property_level_(kPropertyDefault),
       start_(MostForwardCaretPosition(EndingSelection().Start())),
-      end_(MostBackwardCaretPosition(EndingSelection().end())),
+      end_(MostBackwardCaretPosition(EndingSelection().End())),
       use_ending_selection_(true),
       styled_inline_element_(element),
       remove_only_(remove_only),
@@ -161,7 +161,7 @@
       input_type_(input_type),
       property_level_(kPropertyDefault),
       start_(MostForwardCaretPosition(EndingSelection().Start())),
-      end_(MostBackwardCaretPosition(EndingSelection().end())),
+      end_(MostBackwardCaretPosition(EndingSelection().End())),
       use_ending_selection_(true),
       styled_inline_element_(nullptr),
       remove_only_(true),
@@ -193,7 +193,7 @@
 
 Position ApplyStyleCommand::EndPosition() {
   if (use_ending_selection_)
-    return EndingSelection().end();
+    return EndingSelection().End();
 
   return end_;
 }
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index dbda1d3..0f2b088 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -549,7 +549,7 @@
 
 Position CompositeEditCommand::ReplaceSelectedTextInNode(const String& text) {
   Position start = EndingSelection().Start();
-  Position end = EndingSelection().end();
+  Position end = EndingSelection().End();
   if (start.ComputeContainerNode() != end.ComputeContainerNode() ||
       !start.ComputeContainerNode()->IsTextNode() ||
       IsTabHTMLSpanElementTextNode(start.ComputeContainerNode()))
@@ -780,7 +780,7 @@
 
   RebalanceWhitespaceAt(selection.Start());
   if (selection.IsRange())
-    RebalanceWhitespaceAt(selection.end());
+    RebalanceWhitespaceAt(selection.End());
 }
 
 void CompositeEditCommand::DeleteInsignificantText(Text* text_node,
diff --git a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
index 7cb0b53..29da949 100644
--- a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
@@ -121,7 +121,7 @@
   HTMLElement* end_special_container = nullptr;
 
   start = selection_to_delete_.Start();
-  end = selection_to_delete_.end();
+  end = selection_to_delete_.End();
 
   // For HRs, we'll get a position at (HR,1) when hitting delete from the
   // beginning of the previous line, or (HR,0) when forward deleting, but in
@@ -394,11 +394,12 @@
   // of start(). We'll use this later in computeTypingStyleAfterDelete if we end
   // up outside of a Mail blockquote
   if (EnclosingNodeOfType(selection_to_delete_.Start(),
-                          IsMailHTMLBlockquoteElement))
+                          IsMailHTMLBlockquoteElement)) {
     delete_into_blockquote_style_ =
-        EditingStyle::Create(selection_to_delete_.end());
-  else
-    delete_into_blockquote_style_ = nullptr;
+        EditingStyle::Create(selection_to_delete_.End());
+    return;
+  }
+  delete_into_blockquote_style_ = nullptr;
 }
 
 bool DeleteSelectionCommand::HandleSpecialCaseBRDelete(
@@ -1073,7 +1074,7 @@
   GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
 
   Position downstream_end =
-      MostForwardCaretPosition(selection_to_delete_.end());
+      MostForwardCaretPosition(selection_to_delete_.End());
   bool root_will_stay_open_without_placeholder =
       downstream_end.ComputeContainerNode() ==
           RootEditableElement(*downstream_end.ComputeContainerNode()) ||
@@ -1094,7 +1095,7 @@
     // open empty cells, but that's handled elsewhere).
     if (Element* table =
             TableElementJustAfter(selection_to_delete_.VisibleStart())) {
-      if (selection_to_delete_.end().AnchorNode()->IsDescendantOf(table))
+      if (selection_to_delete_.End().AnchorNode()->IsDescendantOf(table))
         need_placeholder_ = false;
     }
   }
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index 76b11ff..029e5f7 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -430,7 +430,7 @@
         selection.ComputeVisibleSelectionInDOMTreeDeprecated().Start(),
         tag_name);
     Element* end_element = EnclosingElementWithTag(
-        selection.ComputeVisibleSelectionInDOMTreeDeprecated().end(), tag_name);
+        selection.ComputeVisibleSelectionInDOMTreeDeprecated().End(), tag_name);
 
     if (start_element && end_element && start_element == end_element) {
       // If the selected list has the different type of list as child, return
@@ -492,7 +492,7 @@
 
   Position end;
   if (selection.IsRange()) {
-    end = MostBackwardCaretPosition(selection.end());
+    end = MostBackwardCaretPosition(selection.End());
 
     DCHECK(end.GetDocument());
     const EphemeralRange caret_range(position.ParentAnchoredEquivalent(),
diff --git a/third_party/WebKit/Source/core/editing/commands/IndentOutdentCommand.cpp b/third_party/WebKit/Source/core/editing/commands/IndentOutdentCommand.cpp
index fda9d7aa..28f1a25 100644
--- a/third_party/WebKit/Source/core/editing/commands/IndentOutdentCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/IndentOutdentCommand.cpp
@@ -352,7 +352,7 @@
     return;
   }
 
-  Position original_selection_end = EndingSelection().end();
+  Position original_selection_end = EndingSelection().End();
   Position end_after_selection =
       EndOfParagraph(NextPositionOf(end_of_last_paragraph)).DeepEquivalent();
 
@@ -386,7 +386,7 @@
     GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
     if (end_of_next_paragraph.IsNotNull() &&
         !end_of_next_paragraph.IsConnected()) {
-      end_of_current_paragraph = CreateVisiblePosition(EndingSelection().end());
+      end_of_current_paragraph = CreateVisiblePosition(EndingSelection().End());
       end_of_next_paragraph =
           EndOfParagraph(NextPositionOf(end_of_current_paragraph))
               .ToPositionWithAffinity();
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
index b15347a..0fea908 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
@@ -137,7 +137,7 @@
   DCHECK(element);
 
   const EphemeralRange selection_range(EndingSelection().Start(),
-                                       EndingSelection().end());
+                                       EndingSelection().End());
   const String old_text = PlainText(selection_range);
   const String& new_text = text_;
 
@@ -163,7 +163,7 @@
                                    EndingSelection().IsDirectional());
 
   SetEndingSelectionWithoutValidation(selection_for_insertion.Start(),
-                                      selection_for_insertion.end());
+                                      selection_for_insertion.End());
 
   InsertTextCommand::DoApply(editing_state);
 }
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertLineBreakCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertLineBreakCommand.cpp
index ded13655..20beb807 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertLineBreakCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertLineBreakCommand.cpp
@@ -225,7 +225,7 @@
     // line break that we inserted, or just before it if it's at the end of a
     // block.
     SetEndingSelection(SelectionInDOMTree::Builder()
-                           .Collapse(EndingSelection().end())
+                           .Collapse(EndingSelection().End())
                            .Build());
   }
 
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertListCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertListCommand.cpp
index ed27e335..801ba8f 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertListCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertListCommand.cpp
@@ -205,7 +205,7 @@
                          kCanSkipOverEditingBoundary)
             .DeepEquivalent() != start_of_last_paragraph) {
       force_list_creation =
-          !SelectionHasListOfType(selection.Start(), selection.end(), list_tag);
+          !SelectionHasListOfType(selection.Start(), selection.End(), list_tag);
 
       VisiblePosition start_of_current_paragraph = visible_start_of_selection;
       while (InSameTreeAndOrdered(start_of_current_paragraph.DeepEquivalent(),
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
index e803959..0d7f811 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertTextCommand.cpp
@@ -106,7 +106,7 @@
   if (select_inserted_text)
     return true;
   SetEndingSelection(SelectionInDOMTree::Builder()
-                         .Collapse(EndingSelection().end())
+                         .Collapse(EndingSelection().End())
                          .SetIsDirectional(EndingSelection().IsDirectional())
                          .Build());
   return true;
@@ -135,7 +135,7 @@
   if (select_inserted_text || EndingSelection().IsNone())
     return true;
   SetEndingSelection(SelectionInDOMTree::Builder()
-                         .Collapse(EndingSelection().end())
+                         .Collapse(EndingSelection().End())
                          .SetIsDirectional(EndingSelection().IsDirectional())
                          .Build());
   return true;
@@ -287,8 +287,8 @@
     SelectionInDOMTree::Builder builder;
     builder.SetAffinity(EndingSelection().Affinity());
     builder.SetIsDirectional(EndingSelection().IsDirectional());
-    if (EndingSelection().end().IsNotNull())
-      builder.Collapse(EndingSelection().end());
+    if (EndingSelection().End().IsNotNull())
+      builder.Collapse(EndingSelection().End());
     SetEndingSelection(builder.Build());
   }
 }
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
index 07af93b..b93ff4e 100644
--- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
@@ -1028,8 +1028,8 @@
                ->GetLayoutObject()
                ->Style()
                ->UserModify() == EUserModify::kReadWritePlaintextOnly) &&
-      (selection.end().AnchorNode()->GetLayoutObject() &&
-       selection.end().AnchorNode()->GetLayoutObject()->Style()->UserModify() ==
+      (selection.End().AnchorNode()->GetLayoutObject() &&
+       selection.End().AnchorNode()->GetLayoutObject()->Style()->UserModify() ==
            EUserModify::kReadWritePlaintextOnly))
     match_style_ = false;
 
@@ -1964,7 +1964,7 @@
   GetDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
 
   Node* node_after_insertion_pos =
-      MostForwardCaretPosition(EndingSelection().end()).AnchorNode();
+      MostForwardCaretPosition(EndingSelection().End()).AnchorNode();
   Text* text_node = ToText(fragment.FirstChild());
   // Our fragment creation code handles tabs, spaces, and newlines, so we don't
   // have to worry about those here.
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 6ff753b3..97c667a 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -795,16 +795,16 @@
       selection_to_delete = selection_modifier.Selection();
 
       if (granularity == kCharacterGranularity &&
-          selection_to_delete.end().ComputeContainerNode() ==
+          selection_to_delete.End().ComputeContainerNode() ==
               selection_to_delete.Start().ComputeContainerNode() &&
-          selection_to_delete.end().ComputeOffsetInContainerNode() -
+          selection_to_delete.End().ComputeOffsetInContainerNode() -
                   selection_to_delete.Start().ComputeOffsetInContainerNode() >
               1) {
         // If there are multiple Unicode code points to be deleted, adjust the
         // range to match platform conventions.
         selection_to_delete.SetWithoutValidation(
-            selection_to_delete.end(),
-            PreviousPositionOf(selection_to_delete.end(),
+            selection_to_delete.End(),
+            PreviousPositionOf(selection_to_delete.End(),
                                PositionMoveType::kBackwardDeletion));
       }
 
@@ -816,7 +816,7 @@
         // have been in the original document. We can't let the VisibleSelection
         // class's validation kick in or it'll adjust for us based on the
         // current state of the document and we'll get the wrong result.
-        selection_after_undo.SetWithoutValidation(StartingSelection().end(),
+        selection_after_undo.SetWithoutValidation(StartingSelection().End(),
                                                   selection_to_delete.Extent());
       }
       break;
@@ -884,7 +884,7 @@
                                   kDirectionForward, kCharacterGranularity);
 
       Position downstream_end =
-          MostForwardCaretPosition(EndingSelection().end());
+          MostForwardCaretPosition(EndingSelection().End());
       VisiblePosition visible_end = EndingSelection().VisibleEnd();
       Node* enclosing_table_cell =
           EnclosingNodeOfType(visible_end.DeepEquivalent(), &IsTableCell);
@@ -905,7 +905,7 @@
         SetEndingSelection(
             SelectionInDOMTree::Builder()
                 .SetBaseAndExtentDeprecated(
-                    EndingSelection().end(),
+                    EndingSelection().End(),
                     Position::AfterNode(downstream_end.ComputeContainerNode()))
                 .SetIsDirectional(EndingSelection().IsDirectional())
                 .Build());
@@ -930,20 +930,20 @@
         // have been in the original document. We can't let the VisibleSelection
         // class's validation kick in or it'll adjust for us based on the
         // current state of the document and we'll get the wrong result.
-        Position extent = StartingSelection().end();
+        Position extent = StartingSelection().End();
         if (extent.ComputeContainerNode() !=
-            selection_to_delete.end().ComputeContainerNode()) {
+            selection_to_delete.End().ComputeContainerNode()) {
           extent = selection_to_delete.Extent();
         } else {
           int extra_characters;
           if (selection_to_delete.Start().ComputeContainerNode() ==
-              selection_to_delete.end().ComputeContainerNode())
+              selection_to_delete.End().ComputeContainerNode())
             extra_characters =
-                selection_to_delete.end().ComputeOffsetInContainerNode() -
+                selection_to_delete.End().ComputeOffsetInContainerNode() -
                 selection_to_delete.Start().ComputeOffsetInContainerNode();
           else
             extra_characters =
-                selection_to_delete.end().ComputeOffsetInContainerNode();
+                selection_to_delete.End().ComputeOffsetInContainerNode();
           extent = Position(
               extent.ComputeContainerNode(),
               extent.ComputeOffsetInContainerNode() + extra_characters);
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
index f237ddca..d4f9296 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.cpp
@@ -34,15 +34,7 @@
 
 TextIteratorTextState::TextIteratorTextState(
     const TextIteratorBehavior& behavior)
-    : text_length_(0),
-      single_character_buffer_(0),
-      position_node_(nullptr),
-      position_start_offset_(0),
-      position_end_offset_(0),
-      has_emitted_(false),
-      last_character_(0),
-      behavior_(behavior),
-      text_start_offset_(0) {}
+    : behavior_(behavior) {}
 
 UChar TextIteratorTextState::CharacterAt(unsigned index) const {
   SECURITY_DCHECK(index < static_cast<unsigned>(length()));
@@ -55,7 +47,7 @@
     return single_character_buffer_;
   }
 
-  return GetString()[PositionStartOffset() + index];
+  return text_[PositionStartOffset() + index];
 }
 
 String TextIteratorTextState::Substring(unsigned position,
@@ -69,7 +61,7 @@
     DCHECK_EQ(length, 1u);
     return String(&single_character_buffer_, 1);
   }
-  return GetString().Substring(PositionStartOffset() + position, length);
+  return text_.Substring(PositionStartOffset() + position, length);
 }
 
 void TextIteratorTextState::AppendTextToStringBuilder(
@@ -84,8 +76,7 @@
     DCHECK_EQ(position, 0u);
     builder.Append(single_character_buffer_);
   } else {
-    builder.Append(GetString(), PositionStartOffset() + position,
-                   length_to_append);
+    builder.Append(text_, PositionStartOffset() + position, length_to_append);
   }
 }
 
@@ -193,10 +184,10 @@
   if (PositionNode()) {
     FlushPositionOffsets();
     unsigned offset = PositionStartOffset() + position;
-    if (GetString().Is8Bit())
-      output->PushRange(GetString().Characters8() + offset, length_to_append);
+    if (text_.Is8Bit())
+      output->PushRange(text_.Characters8() + offset, length_to_append);
     else
-      output->PushRange(GetString().Characters16() + offset, length_to_append);
+      output->PushRange(text_.Characters16() + offset, length_to_append);
     return;
   }
   // We shouldn't be attempting to append text that doesn't exist.
diff --git a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
index f9f52dd..aeff02db 100644
--- a/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
+++ b/third_party/WebKit/Source/core/editing/iterators/TextIteratorTextState.h
@@ -45,8 +45,6 @@
   explicit TextIteratorTextState(const TextIteratorBehavior&);
   ~TextIteratorTextState() {}
 
-  const String& GetString() const { return text_; }
-
   int length() const { return text_length_; }
   UChar CharacterAt(unsigned index) const;
   String Substring(unsigned position, unsigned length) const;
@@ -82,31 +80,31 @@
                     unsigned length_to_append) const;
 
  private:
-  int text_length_;
+  int text_length_ = 0;
   String text_;
 
   // Used for whitespace characters that aren't in the DOM, so we can point at
   // them.
   // If non-zero, overrides m_text.
-  UChar single_character_buffer_;
+  UChar single_character_buffer_ = 0;
 
   // The current text and its position, in the form to be returned from the
   // iterator.
   Member<Node> position_node_;
   mutable Member<Node> position_offset_base_node_;
-  mutable int position_start_offset_;
-  mutable int position_end_offset_;
+  mutable int position_start_offset_ = 0;
+  mutable int position_end_offset_ = 0;
 
   // Used when deciding whether to emit a "positioning" (e.g. newline) before
   // any other content
-  bool has_emitted_;
-  UChar last_character_;
+  bool has_emitted_ = false;
+  UChar last_character_ = 0;
 
   const TextIteratorBehavior behavior_;
 
   // Stores the length of :first-letter when we are at the remaining text.
   // Equals to 0 in all other cases.
-  int text_start_offset_;
+  int text_start_offset_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(TextIteratorTextState);
 };
diff --git a/third_party/WebKit/Source/core/editing/markers/CompositionMarker.cpp b/third_party/WebKit/Source/core/editing/markers/CompositionMarker.cpp
index f24217d..23a52f5 100644
--- a/third_party/WebKit/Source/core/editing/markers/CompositionMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/CompositionMarker.cpp
@@ -9,12 +9,12 @@
 CompositionMarker::CompositionMarker(unsigned start_offset,
                                      unsigned end_offset,
                                      Color underline_color,
-                                     bool thick,
+                                     Thickness thickness,
                                      Color background_color)
     : DocumentMarker(start_offset, end_offset),
       underline_color_(underline_color),
       background_color_(background_color),
-      thick_(thick) {}
+      thickness_(thickness) {}
 
 DocumentMarker::MarkerType CompositionMarker::GetType() const {
   return DocumentMarker::kComposition;
@@ -24,8 +24,8 @@
   return underline_color_;
 }
 
-bool CompositionMarker::Thick() const {
-  return thick_;
+bool CompositionMarker::IsThick() const {
+  return thickness_ == Thickness::kThick;
 }
 
 Color CompositionMarker::BackgroundColor() const {
diff --git a/third_party/WebKit/Source/core/editing/markers/CompositionMarker.h b/third_party/WebKit/Source/core/editing/markers/CompositionMarker.h
index fa476cb..a88674c 100644
--- a/third_party/WebKit/Source/core/editing/markers/CompositionMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/CompositionMarker.h
@@ -16,10 +16,12 @@
 // transparent).
 class CORE_EXPORT CompositionMarker final : public DocumentMarker {
  public:
+  enum class Thickness { kThin, kThick };
+
   CompositionMarker(unsigned start_offset,
                     unsigned end_offset,
                     Color underline_color,
-                    bool thick,
+                    Thickness,
                     Color background_color);
 
   // DocumentMarker implementations
@@ -27,13 +29,13 @@
 
   // CompositionMarker-specific
   Color UnderlineColor() const;
-  bool Thick() const;
+  bool IsThick() const;
   Color BackgroundColor() const;
 
  private:
   const Color underline_color_;
   const Color background_color_;
-  const bool thick_;
+  const Thickness thickness_;
 
   DISALLOW_COPY_AND_ASSIGN(CompositionMarker);
 };
diff --git a/third_party/WebKit/Source/core/editing/markers/CompositionMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/CompositionMarkerListImplTest.cpp
index 5a6e3239..8f14333 100644
--- a/third_party/WebKit/Source/core/editing/markers/CompositionMarkerListImplTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/CompositionMarkerListImplTest.cpp
@@ -15,7 +15,8 @@
       : marker_list_(new CompositionMarkerListImpl()) {}
 
   DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
-    return new CompositionMarker(start_offset, end_offset, Color::kBlack, false,
+    return new CompositionMarker(start_offset, end_offset, Color::kBlack,
+                                 CompositionMarker::Thickness::kThin,
                                  Color::kBlack);
   }
 
diff --git a/third_party/WebKit/Source/core/editing/markers/CompositionMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/CompositionMarkerTest.cpp
index f45f647..3db1f7e 100644
--- a/third_party/WebKit/Source/core/editing/markers/CompositionMarkerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/CompositionMarkerTest.cpp
@@ -11,21 +11,24 @@
 class CompositionMarkerTest : public ::testing::Test {};
 
 TEST_F(CompositionMarkerTest, MarkerType) {
-  DocumentMarker* marker = new CompositionMarker(0, 1, Color::kTransparent,
-                                                 false, Color::kTransparent);
+  DocumentMarker* marker = new CompositionMarker(
+      0, 1, Color::kTransparent, CompositionMarker::Thickness::kThin,
+      Color::kTransparent);
   EXPECT_EQ(DocumentMarker::kComposition, marker->GetType());
 }
 
 TEST_F(CompositionMarkerTest, ConstructorAndGetters) {
   CompositionMarker* marker =
-      new CompositionMarker(0, 1, Color::kDarkGray, false, Color::kGray);
+      new CompositionMarker(0, 1, Color::kDarkGray,
+                            CompositionMarker::Thickness::kThin, Color::kGray);
   EXPECT_EQ(Color::kDarkGray, marker->UnderlineColor());
-  EXPECT_FALSE(marker->Thick());
+  EXPECT_FALSE(marker->IsThick());
   EXPECT_EQ(Color::kGray, marker->BackgroundColor());
 
   CompositionMarker* thick_marker =
-      new CompositionMarker(0, 1, Color::kDarkGray, true, Color::kGray);
-  EXPECT_EQ(true, thick_marker->Thick());
+      new CompositionMarker(0, 1, Color::kDarkGray,
+                            CompositionMarker::Thickness::kThick, Color::kGray);
+  EXPECT_EQ(true, thick_marker->IsThick());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index 55800d22..df94753 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -150,15 +150,16 @@
   // throttling algorithm. crbug.com/6819.
 }
 
-void DocumentMarkerController::AddCompositionMarker(const EphemeralRange& range,
-                                                    Color underline_color,
-                                                    bool thick,
-                                                    Color background_color) {
+void DocumentMarkerController::AddCompositionMarker(
+    const EphemeralRange& range,
+    Color underline_color,
+    CompositionMarker::Thickness thickness,
+    Color background_color) {
   DCHECK(!document_->NeedsLayoutTreeUpdate());
-  AddMarkerInternal(range, [underline_color, thick, background_color](
+  AddMarkerInternal(range, [underline_color, thickness, background_color](
                                int start_offset, int end_offset) {
     return new CompositionMarker(start_offset, end_offset, underline_color,
-                                 thick, background_color);
+                                 thickness, background_color);
   });
 }
 
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
index eae9dcd..16e5008 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
@@ -32,6 +32,7 @@
 #include "core/CoreExport.h"
 #include "core/dom/SynchronousMutationObserver.h"
 #include "core/editing/iterators/TextIterator.h"
+#include "core/editing/markers/CompositionMarker.h"
 #include "core/editing/markers/DocumentMarker.h"
 #include "core/editing/markers/TextMatchMarker.h"
 #include "platform/geometry/IntRect.h"
@@ -61,7 +62,7 @@
   void AddTextMatchMarker(const EphemeralRange&, TextMatchMarker::MatchStatus);
   void AddCompositionMarker(const EphemeralRange&,
                             Color underline_color,
-                            bool thick,
+                            CompositionMarker::Thickness,
                             Color background_color);
 
   void MoveMarkers(Node* src_node, int length, Node* dst_node);
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
index c26976e2..ad8c4855 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerControllerTest.cpp
@@ -220,10 +220,10 @@
   GetDocument().UpdateStyleAndLayout();
   MarkerController().AddCompositionMarker(
       EphemeralRange(Position(text, 0), Position(text, 1)), Color::kBlack,
-      false, Color::kBlack);
+      CompositionMarker::Thickness::kThin, Color::kBlack);
   MarkerController().AddCompositionMarker(
-      EphemeralRange(Position(text, 1), Position(text, 3)), Color::kBlack, true,
-      Color::kBlack);
+      EphemeralRange(Position(text, 1), Position(text, 3)), Color::kBlack,
+      CompositionMarker::Thickness::kThick, Color::kBlack);
 
   EXPECT_EQ(2u, MarkerController().Markers().size());
 }
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
index b629b20b..f7477a8 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
@@ -52,32 +52,24 @@
   return didMoveMarker;
 }
 
-// TODO(rlanday): this method was created by cutting and pasting code from
-// DocumentMarkerController::RemoveMarkers(), it should be refactored in a
-// future CL
 bool DocumentMarkerListEditor::RemoveMarkers(MarkerList* list,
                                              unsigned start_offset,
                                              int length) {
-  bool doc_dirty = false;
   const unsigned end_offset = start_offset + length;
   MarkerList::iterator start_pos = std::upper_bound(
       list->begin(), list->end(), start_offset,
       [](size_t start_offset, const Member<DocumentMarker>& marker) {
         return start_offset < marker->EndOffset();
       });
-  for (MarkerList::iterator i = start_pos; i != list->end();) {
-    const DocumentMarker& marker = *i->Get();
 
-    // markers are returned in order, so stop if we are now past the specified
-    // range
-    if (marker.StartOffset() >= end_offset)
-      break;
+  MarkerList::iterator end_pos = std::lower_bound(
+      list->begin(), list->end(), end_offset,
+      [](const Member<DocumentMarker>& marker, size_t end_offset) {
+        return marker->StartOffset() < end_offset;
+      });
 
-    list->erase(i - list->begin());
-    doc_dirty = true;
-  }
-
-  return doc_dirty;
+  list->erase(start_pos - list->begin(), end_pos - start_pos);
+  return start_pos != end_pos;
 }
 
 // TODO(rlanday): make this not take O(n^2) time when all the markers are
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp
index 2bf66f9..30c4bdfd 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditorTest.cpp
@@ -17,6 +17,40 @@
   }
 };
 
+TEST_F(DocumentMarkerListEditorTest, RemoveMarkersEmptyList) {
+  DocumentMarkerListEditor::MarkerList markers;
+  DocumentMarkerListEditor::RemoveMarkers(&markers, 0, 10);
+  EXPECT_EQ(0u, markers.size());
+}
+
+TEST_F(DocumentMarkerListEditorTest, RemoveMarkersTouchingEndpoints) {
+  DocumentMarkerListEditor::MarkerList markers;
+  markers.push_back(CreateMarker(0, 10));
+  markers.push_back(CreateMarker(10, 20));
+  markers.push_back(CreateMarker(20, 30));
+
+  DocumentMarkerListEditor::RemoveMarkers(&markers, 10, 10);
+
+  EXPECT_EQ(2u, markers.size());
+
+  EXPECT_EQ(0u, markers[0]->StartOffset());
+  EXPECT_EQ(10u, markers[0]->EndOffset());
+
+  EXPECT_EQ(20u, markers[1]->StartOffset());
+  EXPECT_EQ(30u, markers[1]->EndOffset());
+}
+
+TEST_F(DocumentMarkerListEditorTest, RemoveMarkersOneCharacterIntoInterior) {
+  DocumentMarkerListEditor::MarkerList markers;
+  markers.push_back(CreateMarker(0, 10));
+  markers.push_back(CreateMarker(10, 20));
+  markers.push_back(CreateMarker(20, 30));
+
+  DocumentMarkerListEditor::RemoveMarkers(&markers, 9, 12);
+
+  EXPECT_EQ(0u, markers.size());
+}
+
 TEST_F(DocumentMarkerListEditorTest,
        ContentDependentMarker_ReplaceStartOfMarker) {
   DocumentMarkerListEditor::MarkerList markers;
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.cpp b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.cpp
index 096b8a5e..897f6ab 100644
--- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.cpp
@@ -6,8 +6,56 @@
 
 namespace blink {
 
+TextMatchMarker::TextMatchMarker(unsigned start_offset,
+                                 unsigned end_offset,
+                                 MatchStatus status)
+    : DocumentMarker(start_offset, end_offset), match_status_(status) {}
+
 DocumentMarker::MarkerType TextMatchMarker::GetType() const {
   return DocumentMarker::kTextMatch;
 }
 
+bool TextMatchMarker::IsActiveMatch() const {
+  return match_status_ == MatchStatus::kActive;
+}
+
+void TextMatchMarker::SetIsActiveMatch(bool active) {
+  match_status_ = active ? MatchStatus::kActive : MatchStatus::kInactive;
+}
+
+bool TextMatchMarker::IsRendered() const {
+  return layout_state_ == State::kValidNotNull;
+}
+
+bool TextMatchMarker::Contains(const LayoutPoint& point) const {
+  DCHECK_EQ(layout_state_, State::kValidNotNull);
+  return rendered_rect_.Contains(point);
+}
+
+void TextMatchMarker::SetRenderedRect(const LayoutRect& rect) {
+  if (layout_state_ == State::kValidNotNull && rect == rendered_rect_)
+    return;
+  layout_state_ = State::kValidNotNull;
+  rendered_rect_ = rect;
+}
+
+const LayoutRect& TextMatchMarker::RenderedRect() const {
+  DCHECK_EQ(layout_state_, State::kValidNotNull);
+  return rendered_rect_;
+}
+
+void TextMatchMarker::NullifyRenderedRect() {
+  layout_state_ = State::kValidNull;
+  // Now |rendered_rect_| can not be accessed until |SetRenderedRect| is
+  // called.
+}
+
+void TextMatchMarker::Invalidate() {
+  layout_state_ = State::kInvalid;
+}
+
+bool TextMatchMarker::IsValid() const {
+  return layout_state_ != State::kInvalid;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
index e4c9fc2..dd9908c 100644
--- a/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/TextMatchMarker.h
@@ -43,52 +43,27 @@
  public:
   enum class MatchStatus { kInactive, kActive };
 
-  TextMatchMarker(unsigned start_offset,
-                  unsigned end_offset,
-                  MatchStatus status)
-      : DocumentMarker(start_offset, end_offset), match_status_(status) {
-    layout_state_ = State::kInvalid;
-  }
+  TextMatchMarker(unsigned start_offset, unsigned end_offset, MatchStatus);
 
   // DocumentMarker implementations
   MarkerType GetType() const final;
 
   // TextMatchMarker-specific
-  bool IsActiveMatch() const { return match_status_ == MatchStatus::kActive; }
-  void SetIsActiveMatch(bool active) {
-    match_status_ = active ? MatchStatus::kActive : MatchStatus::kInactive;
-  }
+  bool IsActiveMatch() const;
+  void SetIsActiveMatch(bool active);
 
-  bool IsRendered() const { return layout_state_ == State::kValidNotNull; }
-  bool Contains(const LayoutPoint& point) const {
-    DCHECK_EQ(layout_state_, State::kValidNotNull);
-    return rendered_rect_.Contains(point);
-  }
-  void SetRenderedRect(const LayoutRect& rect) {
-    if (layout_state_ == State::kValidNotNull && rect == rendered_rect_)
-      return;
-    layout_state_ = State::kValidNotNull;
-    rendered_rect_ = rect;
-  }
-
-  const LayoutRect& RenderedRect() const {
-    DCHECK_EQ(layout_state_, State::kValidNotNull);
-    return rendered_rect_;
-  }
-
-  void NullifyRenderedRect() {
-    layout_state_ = State::kValidNull;
-    // Now |m_renderedRect| can not be accessed until |setRenderedRect| is
-    // called.
-  }
-
-  void Invalidate() { layout_state_ = State::kInvalid; }
-  bool IsValid() const { return layout_state_ != State::kInvalid; }
+  bool IsRendered() const;
+  bool Contains(const LayoutPoint&) const;
+  void SetRenderedRect(const LayoutRect&);
+  const LayoutRect& RenderedRect() const;
+  void NullifyRenderedRect();
+  void Invalidate();
+  bool IsValid() const;
 
  private:
   MatchStatus match_status_;
   LayoutRect rendered_rect_;
-  State layout_state_;
+  State layout_state_ = State::kInvalid;
 
   DISALLOW_COPY_AND_ASSIGN(TextMatchMarker);
 };
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
index 3dad9c7..540da8f9 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -607,7 +607,7 @@
     // behavior and should be rewritten.
     // Attempt to save the caret position so we can restore it later if needed
     const Position& caret_position =
-        GetFrame().Selection().ComputeVisibleSelectionInDOMTree().end();
+        GetFrame().Selection().ComputeVisibleSelectionInDOMTree().End();
     const Position& paragraph_start = checking_range.StartPosition();
     const int selection_offset =
         paragraph_start < caret_position
@@ -1139,15 +1139,15 @@
   // needs that much context. Determine the character offset from the start of
   // the paragraph to the start of the original search range, since we will want
   // to ignore results in this area.
-  Position paragraph_start =
-      StartOfParagraph(CreateVisiblePosition(start)).ToParentAnchoredPosition();
-  Position paragraph_end = end;
-  int total_range_length =
-      TextIterator::RangeLength(paragraph_start, paragraph_end);
-  paragraph_end =
-      EndOfParagraph(CreateVisiblePosition(start)).ToParentAnchoredPosition();
+  EphemeralRange paragraph_range =
+      ExpandToParagraphBoundary(EphemeralRange(start, start));
+  Position paragraph_start = paragraph_range.StartPosition();
+  Position paragraph_end = paragraph_range.EndPosition();
 
-  int range_start_offset = TextIterator::RangeLength(paragraph_start, start);
+  const int total_range_length =
+      TextIterator::RangeLength(paragraph_start, end);
+  const int range_start_offset =
+      TextIterator::RangeLength(paragraph_start, start);
   int total_length_processed = 0;
 
   bool first_iteration = true;
@@ -1168,8 +1168,7 @@
       last_iteration = true;
     }
     if (current_start_offset < current_end_offset) {
-      String paragraph_string =
-          PlainText(EphemeralRange(paragraph_start, paragraph_end));
+      String paragraph_string = PlainText(paragraph_range);
       if (paragraph_string.length() > 0) {
         int spelling_location = 0;
 
@@ -1203,14 +1202,16 @@
     if (last_iteration ||
         total_length_processed + current_length >= total_range_length)
       break;
-    VisiblePosition new_paragraph_start =
-        StartOfNextParagraph(CreateVisiblePosition(paragraph_end));
+    Position new_paragraph_start =
+        StartOfNextParagraph(CreateVisiblePosition(paragraph_end))
+            .DeepEquivalent();
     if (new_paragraph_start.IsNull())
       break;
 
-    paragraph_start = new_paragraph_start.ToParentAnchoredPosition();
-    paragraph_end =
-        EndOfParagraph(new_paragraph_start).ToParentAnchoredPosition();
+    paragraph_range = ExpandToParagraphBoundary(
+        EphemeralRange(new_paragraph_start, new_paragraph_start));
+    paragraph_start = paragraph_range.StartPosition();
+    paragraph_end = paragraph_range.EndPosition();
     first_iteration = false;
     total_length_processed += current_length;
   }
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp
index 3e393d9..6fb4114 100644
--- a/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellCheckerTest.cpp
@@ -55,6 +55,21 @@
   GetDocument().GetFrame()->GetSpellChecker().AdvanceToNextMisspelling(false);
 }
 
+// Regression test for crbug.com/728801
+TEST_F(SpellCheckerTest, AdvancedToNextMisspellingWrapSearchNoCrash) {
+  SetBodyContent("<div contenteditable>  zz zz zz  </div>");
+
+  Element* div = GetDocument().QuerySelector("div");
+  div->focus();
+  Selection().SetSelection(SelectionInDOMTree::Builder()
+                               .Collapse(Position::LastPositionInNode(div))
+                               .Build());
+  UpdateAllLifecyclePhases();
+
+  // TODO(xiaochengh): We should have SpellCheckTestBase::GetSpellChecker().
+  GetFrame().GetSpellChecker().AdvanceToNextMisspelling(false);
+}
+
 TEST_F(SpellCheckerTest, SpellCheckDoesNotCauseUpdateLayout) {
   SetBodyContent("<input>");
   HTMLInputElement* input =
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 5da0362..eb4a4a1 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -2094,7 +2094,7 @@
       PrimaryDirectionOf(*visible_selection.Start().AnchorNode()) ==
       TextDirection::kRtl;
   selection.end.is_text_direction_rtl |=
-      PrimaryDirectionOf(*visible_selection.end().AnchorNode()) ==
+      PrimaryDirectionOf(*visible_selection.End().AnchorNode()) ==
       TextDirection::kRtl;
 
   return true;
diff --git a/third_party/WebKit/Source/core/html/TextControlElement.cpp b/third_party/WebKit/Source/core/html/TextControlElement.cpp
index e7e5ad0..082ff0bf6 100644
--- a/third_party/WebKit/Source/core/html/TextControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/TextControlElement.cpp
@@ -541,7 +541,7 @@
   }
   const VisibleSelection& visible_selection =
       frame->Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
-  return IndexForPosition(InnerEditorElement(), visible_selection.end());
+  return IndexForPosition(InnerEditorElement(), visible_selection.End());
 }
 
 static const AtomicString& DirectionString(
diff --git a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
index 285f7e29..8a39195 100644
--- a/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandlerTest.cpp
@@ -192,11 +192,11 @@
           ->GetEditor()
           .IsSelectTrailingWhitespaceEnabled()) {
     EXPECT_EQ(Position(line, 4),
-              Selection().ComputeVisibleSelectionInDOMTreeDeprecated().end());
+              Selection().ComputeVisibleSelectionInDOMTreeDeprecated().End());
     EXPECT_EQ("One ", WebString(Selection().SelectedText()).Utf8());
   } else {
     EXPECT_EQ(Position(line, 3),
-              Selection().ComputeVisibleSelectionInDOMTreeDeprecated().end());
+              Selection().ComputeVisibleSelectionInDOMTreeDeprecated().End());
     EXPECT_EQ("One", WebString(Selection().SelectedText()).Utf8());
   }
 
@@ -208,7 +208,7 @@
   EXPECT_EQ(Position(line, 0),
             Selection().ComputeVisibleSelectionInDOMTreeDeprecated().Start());
   EXPECT_EQ(Position(line, 13),
-            Selection().ComputeVisibleSelectionInDOMTreeDeprecated().end());
+            Selection().ComputeVisibleSelectionInDOMTreeDeprecated().End());
   EXPECT_EQ("One Two Three", WebString(Selection().SelectedText()).Utf8());
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 6141f60d..7439981 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -834,11 +834,17 @@
 
 void LayoutBox::SetLocationAndUpdateOverflowControlsIfNeeded(
     const LayoutPoint& location) {
+  if (!HasLayer()) {
+    SetLocation(location);
+    return;
+  }
+  // The Layer does not yet have the up to date subpixel accumulation
+  // so we base the size strictly on the frame rect's location.
   IntSize old_pixel_snapped_border_rect_size =
       PixelSnappedBorderBoxRect().Size();
   SetLocation(location);
-  if (HasLayer() && PixelSnappedBorderBoxRect().Size() !=
-                        old_pixel_snapped_border_rect_size) {
+  if (PixelSnappedBorderBoxRect().Size() !=
+      old_pixel_snapped_border_rect_size) {
     Layer()->UpdateSizeAndScrollingAfterLayout();
   }
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index d2b3f86..2af18c4 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -376,8 +376,12 @@
   DISABLE_CFI_PERF LayoutRect PaddingBoxRect() const {
     return LayoutRect(ClientLeft(), ClientTop(), ClientWidth(), ClientHeight());
   }
-  IntRect PixelSnappedBorderBoxRect() const {
-    return IntRect(IntPoint(), frame_rect_.PixelSnappedSize());
+
+  IntRect PixelSnappedBorderBoxRect(
+      const LayoutSize& offset = LayoutSize()) const {
+    return IntRect(IntPoint(),
+                   PixelSnappedIntSize(frame_rect_.Size(),
+                                       frame_rect_.Location() + offset));
   }
   IntRect BorderBoundingBox() const final {
     return PixelSnappedBorderBoxRect();
diff --git a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
index e26e12c..dded374 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTreeAsText.cpp
@@ -788,8 +788,8 @@
     ts << "selection start: position "
        << selection.Start().ComputeEditingOffset() << " of "
        << NodePosition(selection.Start().AnchorNode()) << "\n"
-       << "selection end:   position " << selection.end().ComputeEditingOffset()
-       << " of " << NodePosition(selection.end().AnchorNode()) << "\n";
+       << "selection end:   position " << selection.End().ComputeEditingOffset()
+       << " of " << NodePosition(selection.End().AnchorNode()) << "\n";
   }
 }
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
index 09649664..bea0b2b 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -1350,7 +1350,8 @@
   overflow_controls_host_layer_->SetPosition(FloatPoint(host_layer_position));
 
   const IntRect border_box =
-      ToLayoutBox(owning_layer_.GetLayoutObject()).PixelSnappedBorderBoxRect();
+      owning_layer_.GetLayoutBox()->PixelSnappedBorderBoxRect(
+          owning_layer_.SubpixelAccumulation());
   overflow_controls_host_layer_->SetSize(FloatSize(border_box.Size()));
   overflow_controls_host_layer_->SetMasksToBounds(true);
   overflow_controls_host_layer_->SetBackfaceVisibility(
@@ -1455,8 +1456,8 @@
 
   DCHECK(scrolling_contents_layer_);
   LayoutBox& layout_box = ToLayoutBox(GetLayoutObject());
-  IntRect overflow_clip_rect =
-      PixelSnappedIntRect(layout_box.OverflowClipRect(LayoutPoint()));
+  IntRect overflow_clip_rect = PixelSnappedIntRect(layout_box.OverflowClipRect(
+      LayoutPoint(owning_layer_.SubpixelAccumulation())));
 
   // When a m_childTransformLayer exists, local content offsets for the
   // m_scrollingLayer have already been applied. Otherwise, we apply them here.
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index 17249ed..601fda49 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -681,7 +681,7 @@
             ToCompositionMarker(marker);
         CompositionUnderline underline(
             composition_marker.StartOffset(), composition_marker.EndOffset(),
-            composition_marker.UnderlineColor(), composition_marker.Thick(),
+            composition_marker.UnderlineColor(), composition_marker.IsThick(),
             composition_marker.BackgroundColor());
         if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground)
           PaintSingleCompositionBackgroundRun(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 5d76895c4..2c36dae 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -278,8 +278,12 @@
 }
 
 void PaintLayer::SetSubpixelAccumulation(const LayoutSize& size) {
-  if (rare_data_ || !size.IsZero())
+  if (rare_data_ || !size.IsZero()) {
     EnsureRareData().subpixel_accumulation = size;
+    if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) {
+      scrollable_area->PositionOverflowControls();
+    }
+  }
 }
 
 void PaintLayer::UpdateLayerPositionsAfterLayout() {
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index a268a74f..4fc2ebdc 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -309,9 +309,11 @@
   bool has_vertical_bar = VerticalScrollbar();
   bool has_resizer = Box().Style()->Resize() != RESIZE_NONE;
   if ((has_horizontal_bar && has_vertical_bar) ||
-      (has_resizer && (has_horizontal_bar || has_vertical_bar)))
-    return CornerRect(Box(), HorizontalScrollbar(), VerticalScrollbar(),
-                      Box().PixelSnappedBorderBoxRect());
+      (has_resizer && (has_horizontal_bar || has_vertical_bar))) {
+    return CornerRect(
+        Box(), HorizontalScrollbar(), VerticalScrollbar(),
+        Box().PixelSnappedBorderBoxRect(Layer()->SubpixelAccumulation()));
+  }
   return IntRect();
 }
 
@@ -1156,7 +1158,8 @@
   if (Box().ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
     x += HasVerticalScrollbar()
              ? VerticalScrollbar()->ScrollbarThickness()
-             : ResizerCornerRect(Box().PixelSnappedBorderBoxRect(),
+             : ResizerCornerRect(Box().PixelSnappedBorderBoxRect(
+                                     Layer()->SubpixelAccumulation()),
                                  kResizerForPointer)
                    .Width();
   return x;
@@ -1398,7 +1401,9 @@
   if (!HasScrollbar() && !Box().CanResize())
     return;
 
-  const IntRect border_box = Box().PixelSnappedBorderBoxRect();
+  const IntRect border_box =
+      Box().PixelSnappedBorderBoxRect(layer_.SubpixelAccumulation());
+
   if (Scrollbar* vertical_scrollbar = this->VerticalScrollbar())
     vertical_scrollbar->SetFrameRect(RectForVerticalScrollbar(border_box));
 
@@ -1454,8 +1459,9 @@
 
   IntRect resize_control_rect;
   if (Box().Style()->Resize() != RESIZE_NONE) {
-    resize_control_rect = ResizerCornerRect(Box().PixelSnappedBorderBoxRect(),
-                                            kResizerForPointer);
+    resize_control_rect = ResizerCornerRect(
+        Box().PixelSnappedBorderBoxRect(Layer()->SubpixelAccumulation()),
+        kResizerForPointer);
     if (resize_control_rect.Contains(local_point))
       return true;
   }
@@ -1528,9 +1534,11 @@
 
 IntRect PaintLayerScrollableArea::ScrollCornerAndResizerRect() const {
   IntRect scroll_corner_and_resizer = ScrollCornerRect();
-  if (scroll_corner_and_resizer.IsEmpty())
+  if (scroll_corner_and_resizer.IsEmpty()) {
     scroll_corner_and_resizer = ResizerCornerRect(
-        Box().PixelSnappedBorderBoxRect(), kResizerForPointer);
+        Box().PixelSnappedBorderBoxRect(Layer()->SubpixelAccumulation()),
+        kResizerForPointer);
+  }
   return scroll_corner_and_resizer;
 }
 
diff --git a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
index 346a8af..9752ec0 100644
--- a/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/ScrollableAreaPainter.cpp
@@ -28,7 +28,8 @@
     return;
 
   IntRect abs_rect = GetScrollableArea().ResizerCornerRect(
-      GetScrollableArea().Box().PixelSnappedBorderBoxRect(),
+      GetScrollableArea().Box().PixelSnappedBorderBoxRect(
+          GetScrollableArea().Layer()->SubpixelAccumulation()),
       kResizerForPointer);
   if (abs_rect.IsEmpty())
     return;
@@ -225,7 +226,8 @@
 bool ScrollableAreaPainter::OverflowControlsIntersectRect(
     const CullRect& cull_rect) const {
   const IntRect border_box =
-      GetScrollableArea().Box().PixelSnappedBorderBoxRect();
+      GetScrollableArea().Box().PixelSnappedBorderBoxRect(
+          GetScrollableArea().Layer()->SubpixelAccumulation());
 
   if (cull_rect.IntersectsCullRect(
           GetScrollableArea().RectForHorizontalScrollbar(border_box)))
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 6829be1f..4f71ec46 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -1061,14 +1061,32 @@
   return true;
 }
 
+static WTF::Optional<CompositionMarker::Thickness> ThicknessFrom(
+    const String& thickness) {
+  if (EqualIgnoringASCIICase(thickness, "thin"))
+    return CompositionMarker::Thickness::kThin;
+  if (EqualIgnoringASCIICase(thickness, "thick"))
+    return CompositionMarker::Thickness::kThick;
+  return WTF::nullopt;
+}
+
 void Internals::addCompositionMarker(const Range* range,
                                      const String& underline_color_value,
-                                     bool thick,
+                                     const String& thickness_value,
                                      const String& background_color_value,
                                      ExceptionState& exception_state) {
   DCHECK(range);
   range->OwnerDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
 
+  WTF::Optional<CompositionMarker::Thickness> thickness =
+      ThicknessFrom(thickness_value);
+  if (!thickness) {
+    exception_state.ThrowDOMException(
+        kSyntaxError,
+        "The thickness provided ('" + thickness_value + "') is invalid.");
+    return;
+  }
+
   Color underline_color;
   Color background_color;
   if (ParseColor(underline_color_value, underline_color, exception_state,
@@ -1076,7 +1094,8 @@
       ParseColor(background_color_value, background_color, exception_state,
                  "Invalid background color.")) {
     range->OwnerDocument().Markers().AddCompositionMarker(
-        EphemeralRange(range), underline_color, thick, background_color);
+        EphemeralRange(range), underline_color, thickness.value(),
+        background_color);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 593a4029..428a64f 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -190,7 +190,7 @@
                           ExceptionState&);
   void addCompositionMarker(const Range*,
                             const String& underline_color_value,
-                            bool thick,
+                            const String& thickness_value,
                             const String& background_color_value,
                             ExceptionState&);
   void setTextMatchMarkersActive(Node*,
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index 5004e3a..918c88f 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -106,7 +106,7 @@
     [RaisesException] Range markerRangeForNode(Node node, DOMString markerType, unsigned long index);
     [RaisesException] DOMString markerDescriptionForNode(Node node, DOMString markerType, unsigned long index);
     [RaisesException] void addTextMatchMarker(Range range, DOMString matchStatus);
-    [RaisesException] void addCompositionMarker(Range range, DOMString underlineColorValue, boolean thick, DOMString backgroundColorValue);
+    [RaisesException] void addCompositionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
     void setTextMatchMarkersActive(Node node, unsigned long startOffset, unsigned long endOffset, boolean active);
     void setMarkedTextMatchesAreHighlighted(Document document, boolean highlight);
 
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 47296f2..9859c164 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -125,10 +125,9 @@
   "front_end/common/Trie.js",
   "front_end/common/UIString.js",
   "front_end/common/Worker.js",
-  "front_end/components/breakpointsList.css",
-  "front_end/components/BreakpointsSidebarPaneBase.js",
   "front_end/components/DataSaverInfobar.js",
   "front_end/components/DockController.js",
+  "front_end/components/domBreakpointsSidebarPane.css",
   "front_end/components/DOMBreakpointsSidebarPane.js",
   "front_end/components/DOMPresentationUtils.js",
   "front_end/components/domUtils.css",
@@ -558,6 +557,7 @@
   "front_end/sources/FilteredUISourceCodeListProvider.js",
   "front_end/sources/GoToLineQuickOpen.js",
   "front_end/sources/InplaceFormatterEditorAction.js",
+  "front_end/sources/javaScriptBreakpointsSidebarPane.css",
   "front_end/sources/JavaScriptBreakpointsSidebarPane.js",
   "front_end/sources/JavaScriptCompiler.js",
   "front_end/sources/JavaScriptSourceFrame.js",
@@ -591,6 +591,7 @@
   "front_end/sources/watchExpressionsSidebarPane.css",
   "front_end/sources/WatchExpressionsSidebarPane.js",
   "front_end/sources/WorkspaceMappingTip.js",
+  "front_end/sources/xhrBreakpointsSidebarPane.css",
   "front_end/sources/XHRBreakpointsSidebarPane.js",
   "front_end/terminal/terminal.css",
   "front_end/terminal/TerminalWidget.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js b/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js
deleted file mode 100644
index 1f02e3e..0000000
--- a/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @unrestricted
- */
-Components.BreakpointsSidebarPaneBase = class extends UI.VBox {
-  constructor() {
-    super();
-    this.registerRequiredCSS('components/breakpointsList.css');
-
-    this.listElement = createElement('ol');
-    this.listElement.className = 'breakpoint-list';
-
-    this.emptyElement = createElement('div');
-    this.emptyElement.className = 'gray-info-message';
-    this.emptyElement.textContent = Common.UIString('No Breakpoints');
-
-    this.element.appendChild(this.emptyElement);
-  }
-
-  /**
-   * @param {!Element} element
-   * @param {?Node=} beforeNode
-   * @protected
-   */
-  addListElement(element, beforeNode) {
-    if (beforeNode) {
-      this.listElement.insertBefore(element, beforeNode);
-    } else {
-      if (!this.listElement.firstChild) {
-        this.element.removeChild(this.emptyElement);
-        this.element.appendChild(this.listElement);
-      }
-      this.listElement.appendChild(element);
-    }
-  }
-
-  /**
-   * @param {!Element} element
-   * @protected
-   */
-  removeListElement(element) {
-    this.listElement.removeChild(element);
-    if (!this.listElement.firstChild) {
-      this.element.removeChild(this.listElement);
-      this.element.appendChild(this.emptyElement);
-    }
-  }
-
-  /**
-   * @protected
-   */
-  reset() {
-    this.listElement.removeChildren();
-    if (this.listElement.parentElement) {
-      this.element.removeChild(this.listElement);
-      this.element.appendChild(this.emptyElement);
-    }
-  }
-};
diff --git a/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
index 2b55e54..308f43e5 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
@@ -31,11 +31,14 @@
 /**
  * @implements {UI.ContextFlavorListener}
  */
-Components.DOMBreakpointsSidebarPane = class extends Components.BreakpointsSidebarPaneBase {
+Components.DOMBreakpointsSidebarPane = class extends UI.VBox {
   constructor() {
-    super();
-    this.registerRequiredCSS('components/breakpointsList.css');
-    this.listElement.classList.add('dom-breakpoints-list');
+    super(true);
+    this.registerRequiredCSS('components/domBreakpointsSidebarPane.css');
+
+    this._listElement = this.contentElement.createChild('div', 'breakpoint-list hidden');
+    this._emptyElement = this.contentElement.createChild('div', 'gray-info-message');
+    this._emptyElement.textContent = Common.UIString('No Breakpoints');
 
     /** @type {!Map<!SDK.DOMDebuggerModel.DOMBreakpoint, !Components.DOMBreakpointsSidebarPane.Item>} */
     this._items = new Map();
@@ -117,16 +120,20 @@
       var item = this._items.get(breakpoint);
       if (item) {
         this._items.delete(breakpoint);
-        this.removeListElement(item.element);
+        this._listElement.removeChild(item.element);
       }
     }
+    if (!this._listElement.firstChild) {
+      this._emptyElement.classList.remove('hidden');
+      this._listElement.classList.add('hidden');
+    }
   }
 
   /**
    * @param {!SDK.DOMDebuggerModel.DOMBreakpoint} breakpoint
    */
   _addBreakpoint(breakpoint) {
-    var element = createElement('li');
+    var element = createElementWithClass('div', 'breakpoint-entry');
     element.addEventListener('contextmenu', this._contextMenu.bind(this, breakpoint), true);
 
     var checkboxLabel = UI.CheckboxLabel.create('', breakpoint.enabled);
@@ -150,13 +157,15 @@
     element._item = item;
     this._items.set(breakpoint, item);
 
-    var currentElement = this.listElement.firstChild;
+    var currentElement = this._listElement.firstChild;
     while (currentElement) {
       if (currentElement._item && currentElement._item.breakpoint.type < breakpoint.type)
         break;
       currentElement = currentElement.nextSibling;
     }
-    this.addListElement(element, currentElement);
+    this._listElement.insertBefore(element, currentElement);
+    this._emptyElement.classList.add('hidden');
+    this._listElement.classList.remove('hidden');
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css b/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css
deleted file mode 100644
index b4d077c80..0000000
--- a/third_party/WebKit/Source/devtools/front_end/components/breakpointsList.css
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc.  All rights reserved.
- * Copyright (C) 2009 Anthony Ricaud <rik@webkit.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1.  Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright
- *     notice, this list of conditions and the following disclaimer in the
- *     documentation and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- *     its contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-.breakpoint-entry {
-    padding: 3px 8px 3px 8px;
-    min-height: 18px;
-    line-height: 15px;
-    border-top: 1px solid #efefef;
-}
-
-.breakpoint-entry [is=dt-checkbox] {
-    max-width: 100%;
-}
-
-.breakpoint-entry label {
-     white-space: nowrap;
-}
-
-:not(.breakpoints-list-deactivated) > .breakpoint-entry:hover {
-    background-color: #eee;
-}
-
-.breakpoint-entry > .source-text {
-    cursor: pointer;
-    text-overflow: ellipsis;
-    overflow: hidden;
-    white-space: nowrap;
-}
-
-.breakpoint-condition {
-    display: block;
-    margin-top: 4px;
-    margin-bottom: 4px;
-    margin-left: 23px;
-    margin-right: 8px;
-}
-
-.breakpoint-list .editing.being-edited {
-    overflow: hidden;
-    white-space: nowrap;
-}
-
-#breakpoint-condition-input {
-    display: block;
-    margin-left: 0;
-    margin-right: 0;
-    outline: none !important;
-    border: 1px solid rgb(66%, 66%, 66%);
-}
-
-ol.breakpoint-list {
-    -webkit-padding-start: 0;
-    list-style: none;
-    margin: 0;
-    padding-bottom: 3px;
-}
-
-.breakpoints-list-deactivated {
-    background-color: #eee;
-    opacity: 0.3;
-}
-
-.breakpoint-list li {
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    overflow: hidden;
-    padding: 2px 0;
-}
-
-.breakpoint-list li:hover {
-    background-color: #eee;
-}
-
-.breakpoint-list .source-text {
-    white-space: nowrap;
-    text-overflow: ellipsis;
-    overflow: hidden;
-    margin: 2px 0 0 20px;
-}
-
-.breakpoint-hit {
-    background-color: rgb(255, 255, 194);
-}
-
-.-theme-with-dark-background .sidebar-pane .breakpoint-hit {
-    background-color: hsl(46, 98%, 22%);
-    color: #ccc;
-}
-
-li.breakpoint-hit .breakpoint-hit-marker {
-    background-color: rgb(255, 255, 194);
-    height: 18px;
-    left: 0;
-    margin-top: -16px;
-    position: absolute;
-    right: 0;
-    z-index: -1;
-}
-
-.dom-breakpoints-list > li {
-    display: flex;
-}
-
-.dom-breakpoints-list .dom-breakpoint > div {
-    overflow: hidden;
-    text-overflow: ellipsis;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/components/domBreakpointsSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/components/domBreakpointsSidebarPane.css
new file mode 100644
index 0000000..e58d8201
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/components/domBreakpointsSidebarPane.css
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+.breakpoint-list {
+    padding-bottom: 3px;
+}
+
+.breakpoint-list .dom-breakpoint > div {
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.breakpoint-entry {
+    display: flex;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    padding: 2px 0;
+}
+
+.breakpoint-list .breakpoint-entry:hover {
+    background-color: #eee;
+}
+
+.breakpoint-hit {
+    background-color: rgb(255, 255, 194);
+}
+
+:host-context(.-theme-with-dark-background) .breakpoint-hit {
+    background-color: hsl(46, 98%, 22%);
+    color: #ccc;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/components/module.json b/third_party/WebKit/Source/devtools/front_end/components/module.json
index 99999d2e..f7ffb0a5 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/components/module.json
@@ -47,7 +47,6 @@
         "network_log"
     ],
     "scripts": [
-        "BreakpointsSidebarPaneBase.js",
         "DataSaverInfobar.js",
         "DOMBreakpointsSidebarPane.js",
         "DOMPresentationUtils.js",
@@ -56,7 +55,7 @@
         "Reload.js"
     ],
     "resources": [
-        "breakpointsList.css",
+        "domBreakpointsSidebarPane.css",
         "domUtils.css",
         "imagePreview.css"
     ]
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
index 217e351..6cc50e9 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
@@ -76,8 +76,9 @@
   /**
    * @param {!DataGrid.DataGridNode} node
    */
-  _deleteButtonClicked(node) {
-    this._model.deleteCacheEntry(this._cache, /** @type {string} */ (node.data['request']), node.remove.bind(node));
+  async _deleteButtonClicked(node) {
+    await this._model.deleteCacheEntry(this._cache, /** @type {string} */ (node.data['request']));
+    node.remove();
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
index e04e96c..0c6415d 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ServiceWorkerCacheModel.js
@@ -57,39 +57,28 @@
   /**
    * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
    */
-  deleteCache(cache) {
-    /**
-     * @this {SDK.ServiceWorkerCacheModel}
-     */
-    function callback(error) {
-      if (error) {
-        console.error('ServiceWorkerCacheAgent error deleting cache ', cache.toString(), ': ', error);
-        return;
-      }
-      this._caches.delete(cache.cacheId);
-      this._cacheRemoved(cache);
+  async deleteCache(cache) {
+    var response = await this._agent.invoke_deleteCache({cacheId: cache.cacheId});
+    if (response[Protocol.Error]) {
+      console.error(`ServiceWorkerCacheAgent error deleting cache ${cache.toString()}: ${response[Protocol.Error]}`);
+      return;
     }
-    this._agent.deleteCache(cache.cacheId, callback.bind(this));
+    this._caches.delete(cache.cacheId);
+    this._cacheRemoved(cache);
   }
 
   /**
    * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
    * @param {string} request
-   * @param {function()} callback
+   * @return {!Promise}
    */
-  deleteCacheEntry(cache, request, callback) {
-    /**
-     * @param {?Protocol.Error} error
-     */
-    function myCallback(error) {
-      if (error) {
-        Common.console.error(Common.UIString(
-            'ServiceWorkerCacheAgent error deleting cache entry %s in cache: %s', cache.toString(), error));
-        return;
-      }
-      callback();
-    }
-    this._agent.deleteEntry(cache.cacheId, request, myCallback);
+  async deleteCacheEntry(cache, request) {
+    var response = await this._agent.invoke_deleteEntry({cacheId: cache.cacheId, request});
+    if (!response[Protocol.Error])
+      return;
+    Common.console.error(Common.UIString(
+        'ServiceWorkerCacheAgent error deleting cache entry %s in cache: %s', cache.toString(),
+        response[Protocol.Error]));
   }
 
   /**
@@ -147,20 +136,11 @@
   /**
    * @param {string} securityOrigin
    */
-  _loadCacheNames(securityOrigin) {
-    /**
-     * @param {?Protocol.Error} error
-     * @param {!Array.<!SDK.ServiceWorkerCacheModel.Cache>} caches
-     * @this {SDK.ServiceWorkerCacheModel}
-     */
-    function callback(error, caches) {
-      if (error) {
-        console.error('ServiceWorkerCacheAgent error while loading caches: ', error);
-        return;
-      }
-      this._updateCacheNames(securityOrigin, caches);
-    }
-    this._agent.requestCacheNames(securityOrigin, callback.bind(this));
+  async _loadCacheNames(securityOrigin) {
+    var caches = await this._agent.requestCacheNames(securityOrigin);
+    if (!caches)
+      return;
+    this._updateCacheNames(securityOrigin, caches);
   }
 
   /**
@@ -234,26 +214,17 @@
    * @param {!SDK.ServiceWorkerCacheModel.Cache} cache
    * @param {number} skipCount
    * @param {number} pageSize
-   * @param {function(!Array.<!SDK.ServiceWorkerCacheModel.Entry>, boolean)} callback
+   * @param {function(!Array<!SDK.ServiceWorkerCacheModel.Entry>, boolean)} callback
    */
-  _requestEntries(cache, skipCount, pageSize, callback) {
-    /**
-     * @param {?Protocol.Error} error
-     * @param {!Array.<!SDK.ServiceWorkerCacheModel.Entry>} dataEntries
-     * @param {boolean} hasMore
-     */
-    function innerCallback(error, dataEntries, hasMore) {
-      if (error) {
-        console.error('ServiceWorkerCacheAgent error while requesting entries: ', error);
-        return;
-      }
-      var entries = [];
-      for (var i = 0; i < dataEntries.length; ++i)
-        entries.push(new SDK.ServiceWorkerCacheModel.Entry(dataEntries[i].request, dataEntries[i].response));
-
-      callback(entries, hasMore);
+  async _requestEntries(cache, skipCount, pageSize, callback) {
+    var response = await this._agent.invoke_requestEntries({cacheId: cache.cacheId, skipCount, pageSize});
+    if (response[Protocol.Error]) {
+      console.error('ServiceWorkerCacheAgent error while requesting entries: ', response[Protocol.Error]);
+      return;
     }
-    this._agent.requestEntries(cache.cacheId, skipCount, pageSize, innerCallback);
+    var entries = response.cacheDataEntries.map(
+        dataEntry => new SDK.ServiceWorkerCacheModel.Entry(dataEntry.request, dataEntry.response));
+    callback(entries, response.hasMore);
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
index 42f6ec8..2cb5e94 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
@@ -7,8 +7,6 @@
 Sources.EventListenerBreakpointsSidebarPane = class extends UI.VBox {
   constructor() {
     super(true);
-    this.registerRequiredCSS('components/breakpointsList.css');
-
     this._categoriesTreeOutline = new UI.TreeOutlineInShadow();
     this._categoriesTreeOutline.element.tabIndex = 0;
     this._categoriesTreeOutline.registerRequiredCSS('sources/eventListenerBreakpoints.css');
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
index 6b9f281..88a0cb4 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
@@ -8,7 +8,7 @@
 Sources.JavaScriptBreakpointsSidebarPane = class extends UI.ThrottledWidget {
   constructor() {
     super(true);
-    this.registerRequiredCSS('components/breakpointsList.css');
+    this.registerRequiredCSS('sources/javaScriptBreakpointsSidebarPane.css');
 
     this._breakpointManager = Bindings.breakpointManager;
     this._breakpointManager.addEventListener(Bindings.BreakpointManager.Events.BreakpointAdded, this.update, this);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
index e8094646..7a05db3 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
@@ -6,16 +6,22 @@
  * @implements {UI.ToolbarItem.ItemsProvider}
  * @unrestricted
  */
-Sources.XHRBreakpointsSidebarPane = class extends Components.BreakpointsSidebarPaneBase {
+Sources.XHRBreakpointsSidebarPane = class extends UI.VBox {
   constructor() {
-    super();
+    super(true);
+    this.registerRequiredCSS('sources/xhrBreakpointsSidebarPane.css');
+
+    this._listElement = this.contentElement.createChild('div', 'breakpoint-list hidden');
+    this._emptyElement = this.contentElement.createChild('div', 'gray-info-message');
+    this._emptyElement.textContent = Common.UIString('No Breakpoints');
+
     /** @type {!Map.<string, !Element>} */
     this._breakpointElements = new Map();
 
     this._addButton = new UI.ToolbarButton(Common.UIString('Add breakpoint'), 'largeicon-add');
     this._addButton.addEventListener(UI.ToolbarButton.Events.Click, this._addButtonClicked.bind(this));
 
-    this.emptyElement.addEventListener('contextmenu', this._emptyElementContextMenu.bind(this), true);
+    this._emptyElement.addEventListener('contextmenu', this._emptyElementContextMenu.bind(this), true);
     this._restoreBreakpoints();
     this._update();
   }
@@ -40,9 +46,8 @@
     var inputElementContainer = createElementWithClass('p', 'breakpoint-condition');
     inputElementContainer.textContent = Common.UIString('Break when URL contains:');
 
-    var inputElement = inputElementContainer.createChild('span');
-    inputElement.id = 'breakpoint-condition-input';
-    this.addListElement(inputElementContainer, /** @type {?Element} */ (this.listElement.firstChild));
+    var inputElement = inputElementContainer.createChild('span', 'breakpoint-condition-input');
+    this._addListElement(inputElementContainer, /** @type {?Element} */ (this._listElement.firstChild));
 
     /**
      * @param {boolean} accept
@@ -51,7 +56,7 @@
      * @this {Sources.XHRBreakpointsSidebarPane}
      */
     function finishEditing(accept, e, text) {
-      this.removeListElement(inputElementContainer);
+      this._removeListElement(inputElementContainer);
       if (accept) {
         SDK.domDebuggerManager.addXHRBreakpoint(text, true);
         this._setBreakpoint(text, true);
@@ -72,7 +77,7 @@
       return;
     }
 
-    var element = createElement('li');
+    var element = createElementWithClass('div', 'breakpoint-entry');
     element._url = url;
     element.addEventListener('contextmenu', this._contextMenu.bind(this, url), true);
 
@@ -85,13 +90,13 @@
     label.classList.add('cursor-auto');
     label.textElement.addEventListener('dblclick', this._labelClicked.bind(this, url), false);
 
-    var currentElement = /** @type {?Element} */ (this.listElement.firstChild);
+    var currentElement = /** @type {?Element} */ (this._listElement.firstChild);
     while (currentElement) {
       if (currentElement._url && currentElement._url < element._url)
         break;
       currentElement = /** @type {?Element} */ (currentElement.nextSibling);
     }
-    this.addListElement(element, currentElement);
+    this._addListElement(element, currentElement);
     this._breakpointElements.set(url, element);
   }
 
@@ -103,10 +108,31 @@
     if (!element)
       return;
 
-    this.removeListElement(element);
+    this._removeListElement(element);
     this._breakpointElements.delete(url);
   }
 
+  /**
+   * @param {!Element} element
+   * @param {?Node} beforeNode
+   */
+  _addListElement(element, beforeNode) {
+    this._listElement.insertBefore(element, beforeNode);
+    this._emptyElement.classList.add('hidden');
+    this._listElement.classList.remove('hidden');
+  }
+
+  /**
+   * @param {!Element} element
+   */
+  _removeListElement(element) {
+    this._listElement.removeChild(element);
+    if (!this._listElement.firstChild) {
+      this._emptyElement.classList.remove('hidden');
+      this._listElement.classList.add('hidden');
+    }
+  }
+
   _contextMenu(url, event) {
     var contextMenu = new UI.ContextMenu(event);
 
@@ -143,7 +169,7 @@
     var element = this._breakpointElements.get(url) || null;
     var inputElement = createElementWithClass('span', 'breakpoint-condition');
     inputElement.textContent = url;
-    this.listElement.insertBefore(inputElement, element);
+    this._listElement.insertBefore(inputElement, element);
     element.classList.add('hidden');
 
     /**
@@ -153,7 +179,7 @@
      * @this {Sources.XHRBreakpointsSidebarPane}
      */
     function finishEditing(accept, e, text) {
-      this.removeListElement(inputElement);
+      this._removeListElement(inputElement);
       if (accept) {
         SDK.domDebuggerManager.removeXHRBreakpoint(url);
         this._removeBreakpoint(url);
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css
new file mode 100644
index 0000000..301b8be
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sources/javaScriptBreakpointsSidebarPane.css
@@ -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.
+ */
+
+.breakpoint-entry {
+    padding: 3px 8px 3px 8px;
+    min-height: 18px;
+    line-height: 15px;
+    border-top: 1px solid #efefef;
+}
+
+.breakpoint-entry [is=dt-checkbox] {
+    max-width: 100%;
+    white-space: nowrap;
+}
+
+:not(.breakpoints-list-deactivated) > .breakpoint-entry:hover {
+    background-color: #eee;
+}
+
+.breakpoint-entry > .source-text {
+    cursor: pointer;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+.breakpoints-list-deactivated {
+    background-color: #eee;
+    opacity: 0.3;
+}
+
+.breakpoint-hit {
+    background-color: rgb(255, 255, 194);
+}
+
+:host-context(.-theme-with-dark-background) .breakpoint-hit {
+    background-color: hsl(46, 98%, 22%);
+    color: #ccc;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/module.json b/third_party/WebKit/Source/devtools/front_end/sources/module.json
index 3dfa1de..e7abff6 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sources/module.json
@@ -661,6 +661,7 @@
         "debuggerPausedMessage.css",
         "eventListenerBreakpoints.css",
         "fileBasedSearchResultsPane.css",
+        "javaScriptBreakpointsSidebarPane.css",
         "navigatorTree.css",
         "navigatorView.css",
         "revisionHistory.css",
@@ -671,6 +672,7 @@
         "sourcesView.css",
         "threadsSidebarPane.css",
         "watchExpressionsSidebarPane.css",
+        "xhrBreakpointsSidebarPane.css",
         "dialog.css"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/xhrBreakpointsSidebarPane.css b/third_party/WebKit/Source/devtools/front_end/sources/xhrBreakpointsSidebarPane.css
new file mode 100644
index 0000000..317bf57
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/sources/xhrBreakpointsSidebarPane.css
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+.breakpoint-list {
+    padding-bottom: 3px;
+}
+
+.breakpoint-list .editing.being-edited {
+    overflow: hidden;
+    white-space: nowrap;
+}
+
+.breakpoint-condition {
+    display: block;
+    margin-top: 4px;
+    margin-bottom: 4px;
+    margin-left: 23px;
+    margin-right: 8px;
+}
+
+.breakpoint-condition-input {
+    display: block;
+    margin-left: 0;
+    margin-right: 0;
+    outline: none !important;
+    border: 1px solid rgb(66%, 66%, 66%);
+}
+
+.breakpoint-entry {
+    white-space: nowrap;
+    padding: 2px 0;
+}
+
+.breakpoint-list .breakpoint-entry:hover {
+    background-color: #eee;
+}
+
+.breakpoint-entry [is=dt-checkbox] {
+    max-width: 100%;
+}
+
+.breakpoint-hit {
+    background-color: rgb(255, 255, 194);
+}
+
+:host-context(.-theme-with-dark-background) .breakpoint-hit {
+    background-color: hsl(46, 98%, 22%);
+    color: #ccc;
+}
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
index 2b28b1c..c6b4a9c 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -47,7 +47,6 @@
 ref_types = {}
 
 NON_PROMISIFIED_DOMAINS = frozenset([
-    "CacheStorage",
     "CSS",
     "DOMDebugger",
     "IndexedDB",
diff --git a/third_party/WebKit/Source/modules/BUILD.gn b/third_party/WebKit/Source/modules/BUILD.gn
index 4305c7aa..a652254 100644
--- a/third_party/WebKit/Source/modules/BUILD.gn
+++ b/third_party/WebKit/Source/modules/BUILD.gn
@@ -62,10 +62,21 @@
     "ModulesInitializer.h",
   ]
 
+  sources += generated_modules_dictionary_files
+  sources += generated_modules_callback_function_files
+
   # Compile sources generated by module_names script.
   sources += get_target_outputs(":module_names")
 
   sources += bindings_modules_v8_files
+  sources += rebase_path(bindings_modules_generated_interface_files, ".", "//")
+  sources += rebase_path(bindings_modules_generated_union_type_files, ".", "//")
+  sources +=
+      rebase_path(bindings_modules_generated_partial_interface_files, ".", "//")
+  sources +=
+      rebase_path([ bindings_modules_generated_init_partial_interfaces_file ],
+                  ".",
+                  "//")
 
   configs += [
     ":modules_implementation",
@@ -83,7 +94,6 @@
     ":module_names",
     "//device/geolocation/public/interfaces:interfaces_blink",
     "//third_party/WebKit/Source/bindings/modules:generated",
-    "//third_party/WebKit/Source/bindings/modules/v8:bindings_modules_impl",
     "//third_party/WebKit/Source/core",
     "//third_party/WebKit/Source/modules/accessibility",
     "//third_party/WebKit/Source/modules/app_banner",
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
index a246c8c2..f77db328 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -654,7 +654,7 @@
   start = ToWebTextDirection(PrimaryDirectionOf(
       *selection.ComputeVisibleSelectionInDOMTree().Start().AnchorNode()));
   end = ToWebTextDirection(PrimaryDirectionOf(
-      *selection.ComputeVisibleSelectionInDOMTree().end().AnchorNode()));
+      *selection.ComputeVisibleSelectionInDOMTree().End().AnchorNode()));
   return true;
 }
 
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 57bf07ad..3769329 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1112,7 +1112,7 @@
              .Start() != GetFrame()
                              ->Selection()
                              .ComputeVisibleSelectionInDOMTreeDeprecated()
-                             .end();
+                             .End();
 }
 
 WebRange WebLocalFrameImpl::SelectionRange() const {
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 25ac509..bf4ec99 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2445,7 +2445,7 @@
   start = ToWebTextDirection(PrimaryDirectionOf(
       *selection.ComputeVisibleSelectionInDOMTree().Start().AnchorNode()));
   end = ToWebTextDirection(PrimaryDirectionOf(
-      *selection.ComputeVisibleSelectionInDOMTree().end().AnchorNode()));
+      *selection.ComputeVisibleSelectionInDOMTree().End().AnchorNode()));
   return true;
 }
 
diff --git a/third_party/node/chromium_vulcanize.patch b/third_party/node/chromium_vulcanize.patch
new file mode 100644
index 0000000..ddb58ee
--- /dev/null
+++ b/third_party/node/chromium_vulcanize.patch
@@ -0,0 +1,12 @@
+diff --git a/lib/constants.js b/lib/constants.js
+index 21e1380..b6a353a 100644
+--- a/lib/constants.js
++++ b/lib/constants.js
+@@ -13,6 +13,6 @@ module.exports = {
+   ABS_URL: /(^\/)|(^#)|(^[\w-\d]*:)/,
+   URL: /url\([^)]*\)/g,
+   URL_ATTR: ['href', 'src', 'action', 'style', 'assetpath'],
+-  URL_TEMPLATE: '{{.*}}|\\[\\[.*\\]\\]',
++  URL_TEMPLATE: '{{.*}}|\\[\\[.*\\]\\]|\\$i18n[^{]*{[^}]*}',
+   OLD_POLYMER: 'This version of vulcanize is not compatible with Polymer < 0.8. Please use vulcanize 0.7.x.'
+ };
diff --git a/third_party/node/node_modules.tar.gz.sha1 b/third_party/node/node_modules.tar.gz.sha1
index 7cc0ad9..85949287 100644
--- a/third_party/node/node_modules.tar.gz.sha1
+++ b/third_party/node/node_modules.tar.gz.sha1
@@ -1 +1 @@
-1bbb442738b5c016c87d50cdf364ec6bcd779e6a
+70eddb115269dddec7f911b3833fff3e37a6fbe8
diff --git a/third_party/node/package.json b/third_party/node/package.json
index a2bd3ecf..3ed265a 100644
--- a/third_party/node/package.json
+++ b/third_party/node/package.json
@@ -4,9 +4,9 @@
   "author": "dpapad@chromium.org",
   "dependencies": {
     "crisper": "2.0.2",
-    "eslint": "^3.19.0",
-    "polymer-css-build": "0.0.9",
+    "eslint": "3.19.0",
+    "polymer-css-build": "0.1.2",
     "uglifyjs": "2.4.10",
-    "vulcanize": "1.15.2"
+    "vulcanize": "1.15.4"
   }
 }
diff --git a/third_party/node/patch_vulcanize.diff b/third_party/node/patch_vulcanize.diff
deleted file mode 100644
index 94ef2fd..0000000
--- a/third_party/node/patch_vulcanize.diff
+++ /dev/null
@@ -1,92 +0,0 @@
-diff --git a/bin/vulcanize b/bin/vulcanize
-index 956b2bc..ad8b29d 100755
---- a/bin/vulcanize
-+++ b/bin/vulcanize
-@@ -35,6 +35,7 @@ var help = [
-   '  --redirect <uri>|<path>: Takes an argument in the form of URI|PATH where url is a URI composed of a protocol, hostname, and path and PATH is a local filesystem path to replace the matched URI part with. Multiple redirects may be specified; the earliest ones have the highest priority.',
-   '  --no-implicit-strip: DANGEROUS! Avoid stripping imports of the transitive dependencies of imports specified with `--exclude`. May result in duplicate javascript inlining.',
-   '  --out-html <path>: If specified, output will be written to <path> instead of stdout.',
-+  '  --out-request-list <path>: Writes a list of request URLs required to vulcanize <html file> to <path> on success.',
-   'Examples:',
-   '  The command',
-   '',
-@@ -82,7 +83,8 @@ var args = nopt(
-     'no-implicit-strip': Boolean,
-     'inline-scripts': Boolean,
-     'inline-css': Boolean,
--    'out-html': String
-+    'out-html': String,
-+    'out-request-list': String
-   },
-   {
-     'h': ['--help'],
-@@ -126,15 +128,23 @@ args.implicitStrip = !args['no-implicit-strip'];
- args.inlineScripts = args['inline-scripts'];
- args.inlineCss = args['inline-css'];
- 
--(new vulcan(args)).process(target, function(err, content) {
-+var vulcanize = new vulcan(args);
-+vulcanize.process(target, function(err, content) {
-   if (err) {
-     process.stderr.write(require('util').inspect(err));
-     process.exit(1);
-   }
-+
-+  if (args['out-request-list']) {
-+    var urls = Object.keys(vulcanize.loader.requests).filter(function(request) {
-+      // Filter out excluded URLs.
-+      return !vulcanize.isExcludedHref(request);
-+    });
-+    fs.writeFileSync(args['out-request-list'], urls.join('\n') + '\n');
-+  }
-+
-   if (args['out-html']) {
--      var fd = fs.openSync(args['out-html'], 'w');
--      fs.writeSync(fd, content + "\n");
--      fs.closeSync(fd);
-+    fs.writeFileSync(args['out-html'], content + '\n');
-   } else {
-     process.stdout.write(content);
-   }
-diff --git a/lib/constants.js b/lib/constants.js
-index 21e1380..b6a353a 100644
---- a/lib/constants.js
-+++ b/lib/constants.js
-@@ -13,6 +13,6 @@ module.exports = {
-   ABS_URL: /(^\/)|(^#)|(^[\w-\d]*:)/,
-   URL: /url\([^)]*\)/g,
-   URL_ATTR: ['href', 'src', 'action', 'style', 'assetpath'],
--  URL_TEMPLATE: '{{.*}}|\\[\\[.*\\]\\]',
-+  URL_TEMPLATE: '{{.*}}|\\[\\[.*\\]\\]|\\$i18n[^{]*{[^}]*}',
-   OLD_POLYMER: 'This version of vulcanize is not compatible with Polymer < 0.8. Please use vulcanize 0.7.x.'
- };
-diff --git a/lib/vulcan.js b/lib/vulcan.js
-index 5aff456..2540dc1 100644
---- a/lib/vulcan.js
-+++ b/lib/vulcan.js
-@@ -414,19 +414,21 @@ Vulcan.prototype = {
-   },
- 
-   getImplicitExcludes: function getImplicitExcludes(excludes) {
--    // Build a loader that doesn't have to stop at our excludes, since we need them.
-+    // Build a loader that doesn't have to stop at our HTML excludes, since we
-+    // need them. JS excludes should still be excluded.
-     var loader = buildLoader({
-       abspath: this.abspath,
-       fsResolver: this.fsResolver,
--      redirects: this.redirects
-+      redirects: this.redirects,
-+      excludes: excludes.filter(function(e) { return e.match(/.js$/i); })
-     });
-     var analyzer = new hyd.Analyzer(true, loader);
-     var analyzedExcludes = [];
-     excludes.forEach(function(exclude) {
--      if (exclude.match(/.js$/)) {
-+      if (exclude.match(/.js$/i)) {
-         return;
-       }
--      if (exclude.match(/.css$/)) {
-+      if (exclude.match(/.css$/i)) {
-         return;
-       }
-       if (exclude.slice(-1) === '/') {
diff --git a/third_party/node/update_npm_deps b/third_party/node/update_npm_deps
index 9997ec1..5deef8a 100755
--- a/third_party/node/update_npm_deps
+++ b/third_party/node/update_npm_deps
@@ -18,8 +18,8 @@
 
 npm install --no-bin-links --only=prod
 
-# Apply local patch to vulacanize.
-patch -d node_modules/vulcanize/ -p1 < patch_vulcanize.diff
+# Apply local patch to vulcanize.
+patch -d node_modules/vulcanize/ -p1 < chromium_vulcanize.patch
 
 rsync -c --delete -r -q --exclude-from="npm_exclude.txt" \
       --prune-empty-dirs "node_modules/" "node_modules_filtered/"
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b398515..9402456 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -59678,9 +59678,19 @@
 <histogram name="Renderer4.ImageDecodeTaskDurationUs" units="microseconds">
   <owner>vmpstr@chromium.org</owner>
   <summary>
-    This metric records the duration of an image decode in the compositor. It is
-    recorded every time we decode an image. It is suffixed by the type of
-    rasterization we're in (either Gpu or Software).
+    This metric records the duration of an image decode for the raster path in
+    the compositor. It is recorded every time we decode an image. It is suffixed
+    by the type of rasterization we're in (either Gpu or Software).
+  </summary>
+</histogram>
+
+<histogram name="Renderer4.ImageDecodeTaskDurationUs.OutOfRaster"
+    units="microseconds">
+  <owner>vmpstr@chromium.org, khushalsagar@chromium.org</owner>
+  <summary>
+    This metric records the duration of an image decode for out of raster path
+    in the compositor. It is recorded every time we decode an image. It is
+    suffixed by the type of rasterization we're in (either Gpu or Software).
   </summary>
 </histogram>
 
@@ -92820,6 +92830,7 @@
       name="Compositing.Renderer.RasterTask.RasterPixelsPerMs2"/>
   <affected-histogram name="Compositing.Renderer.RasterTask.RasterUs"/>
   <affected-histogram name="Renderer4.ImageDecodeTaskDurationUs"/>
+  <affected-histogram name="Renderer4.ImageDecodeTaskDurationUs.OutOfRaster"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="ReferrerAttribution" separator=".">
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py
index b2963dc..0c217119 100644
--- a/tools/perf/benchmarks/loading.py
+++ b/tools/perf/benchmarks/loading.py
@@ -69,6 +69,9 @@
         cache_temperatures=[cache_temperature.ANY],
         traffic_settings=[traffic_setting.NONE, traffic_setting.REGULAR_3G])
 
+  def GetExpectations(self):
+    return page_sets.LoadingMobileExpectations()
+
   @classmethod
   def Name(cls):
     return 'loading.mobile'
diff --git a/tools/perf/benchmarks/oortonline.py b/tools/perf/benchmarks/oortonline.py
index 488d9f9..cddf023 100644
--- a/tools/perf/benchmarks/oortonline.py
+++ b/tools/perf/benchmarks/oortonline.py
@@ -50,7 +50,8 @@
     return page_sets.OortOnlinePageSet()
 
 
-@benchmark.Disabled('win')
+# Disabled on Linux due to timeouts; crbug.com/727850
+@benchmark.Disabled('linux', 'win')
 @benchmark.Owner(emails=['ulan@chromium.org'])
 class OortOnlineTBMv2(perf_benchmark.PerfBenchmark):
   """OortOnline benchmark that measures WebGL and V8 performance.
diff --git a/tools/perf/page_sets/loading_mobile.py b/tools/perf/page_sets/loading_mobile.py
index fc970a91..54f9ffe2 100644
--- a/tools/perf/page_sets/loading_mobile.py
+++ b/tools/perf/page_sets/loading_mobile.py
@@ -37,16 +37,11 @@
        'GoogleIndia'),
       ('https://www.google.com.br/search?q=flor#q=Entrega+de+flores&start=10',
        'GoogleBrazil'),
-      # Disabled because of crbug.com/653775
-      # pylint: disable=line-too-long
-      # ('https://googleblog.blogspot.jp/2016/02/building-safer-web-for-everyone.html',
-      #  'Blogspot'),
       ('https://www.google.co.id/#q=pengiriman+bunga', 'GoogleIndonesia'),
       ('https://m.facebook.com/?soft=messages', 'Facebook'),
-      # Disabled because of crbug.com/656861
       # pylint: disable=line-too-long
-      # ('http://g1.globo.com/politica/noticia/2016/02/maioria-do-stf-autoriza-fisco-obter-dados-bancarios-sem-decisao-judicial.html',
-      #  'G1'),
+      ('http://g1.globo.com/politica/noticia/2016/02/maioria-do-stf-autoriza-fisco-obter-dados-bancarios-sem-decisao-judicial.html',
+       'G1'),
       # pylint: disable=line-too-long
       ('https://m.baidu.com/s?word=%E9%B2%9C%E8%8A%B1%E9%80%9F%E9%80%92&oq=%E9%B2%9C%E8%8A%B1',
        'Baidu'),
@@ -57,10 +52,6 @@
       # pylint: disable=line-too-long
       ('http://noticias.bol.uol.com.br/ultimas-noticias/brasil/2016/08/03/tufao-nida-nao-deixa-vitimas-mas-prejuizos-de-us-43-milhoes.htm',
        'BOLNoticias'),
-      # Disabled because of crbug.com/653775
-      # pylint: disable=line-too-long
-      # ('http://m.detik.com/finance/read/2016/02/19/151843/3146351/1034/ekspor-tambang-mentah-mau-dibuka-lagi-kalau-sudah-bangun-smelter-bagaimana',
-      #  'Detik'),
       ('http://www.amazon.com/gp/aw/s/ref=is_s/189-8585431-1246432?k=shoes',
        'Amazon'),
       # pylint: disable=line-too-long
@@ -82,6 +73,13 @@
       # pylint: disable=line-too-long
       ('http://enquiry.indianrail.gov.in/mntes/MntesServlet?action=MainMenu&subAction=excep&excpType=EC',
        'EnquiryIndianRail'),
+      # TODO(rnephew): Rerecord this. crbug.com/728882
+      # pylint: disable=line-too-long
+      # ('https://googleblog.blogspot.jp/2016/02/building-safer-web-for-everyone.html',
+      #  'Blogspot'),
+      # pylint: disable=line-too-long
+      # ('http://m.detik.com/finance/read/2016/02/19/151843/3146351/1034/ekspor-tambang-mentah-mau-dibuka-lagi-kalau-sudah-bangun-smelter-bagaimana',
+      #  'Detik'),
     ], cache_temperatures, traffic_settings)
 
     self.AddStories(['pwa'], [
@@ -90,17 +88,10 @@
        'FlipKart'),
       ('https://smp.suumo.jp/mansion/tokyo/sc_104/cond/?moreCond=1',
        'Suumo'),
-      # Disabled because of crbug.com/653775
-      # 'https://airhorner.com', 'AirHorner'),
       ('https://guitar-tuner.appspot.com', 'GuitarTuner'),
-      # Disabled because of crbug.com/653775
-      # ('https://busrouter.sg', 'BusRouter'),
       ('https://andreasbovens.github.io/inbox-attack/',
        'InboxAttack'),
       ('https://voice-memos.appspot.com', 'VoiceMemos'),
-      # Disabled because of crbug.com/653775
-      # ('https://wiki-offline.jakearchibald.com/',
-      #  'WikiOffline'),
       ('https://dev.opera.com/', 'DevOpera'),
       ('https://www.pokedex.org/', 'Pokedex'),
       ('https://2048-opera-pwa.surge.sh/', '2048'),
@@ -108,42 +99,43 @@
        'TrainedToThrill'),
       ('https://townwork.net', 'TownWork'),
       ('https://flipboard.com/topic/yoga', 'FlipBoard'),
+      # TODO(rnephew): Record these. crbug.com/728882
+      # ('https://wiki-offline.jakearchibald.com/',
+      #  'WikiOffline'),
+      # ('https://busrouter.sg', 'BusRouter'),
+      # ('https://airhorner.com', 'AirHorner'),
     ], cache_temperatures, traffic_settings)
 
     self.AddStories(['tough_ttfmp'], [
       ('http://www.localmoxie.com', 'LocalMoxie'),
       ('http://www.dawn.com', 'Dawn'),
       ('http://www.thairath.co.th', 'Thairath'),
-      # Disabled to avoid Nexus5X bot timeout crbug.com/702175
-      # ('http://www.hashocean.com', 'HashOcean'),
-      # ('http://www.163.com', '163'),
+      ('http://www.hashocean.com', 'HashOcean'),
+      ('http://www.163.com', '163'),
     ], cache_temperatures, traffic_settings)
 
     self.AddStories(['easy_ttfmp'], [
       ('http://www.slideshare.net', 'SlideShare'),
       ('http://www.bradesco.com.br', 'Bradesco'),
       ('http://www.gsshop.com', 'GSShop'),
-      # Disabled to avoid Nexus5X bot timeout crbug.com/702175
-      # ('http://www.sbs.co.kr', 'SBS'),
-      # ('http://www.futura-sciences.com', 'FuturaSciences'),
+      ('http://www.sbs.co.kr', 'SBS'),
+      ('http://www.futura-sciences.com', 'FuturaSciences'),
     ], cache_temperatures, traffic_settings)
 
     self.AddStories(['tough_tti'], [
       ('http://www.thestar.com.my', 'TheStar'),
       ('http://www.58pic.com', '58Pic'),
       ('http://www.hongkiat.com', 'Hongkiat'),
-      # Disabled to avoid Nexus5X bot timeout crbug.com/702175
-      # ('http://www.ebs.in', 'EBS'),
-      # ('http://www.ibicn.com', 'IBI'),
+      ('http://www.ebs.in', 'EBS'),
+      ('http://www.ibicn.com', 'IBI'),
     ], cache_temperatures, traffic_settings)
 
     self.AddStories(['easy_tti'], [
       ('http://www.dramaq.com.tw', 'Dramaq'),
       ('http://www.locanto.in', 'Locanto'),
       ('http://www.francetvinfo.fr', 'FranceTVInfo'),
-      # Disabled to avoid Nexus5X bot timeout crbug.com/702175
-      # ('http://www.gfk.com', 'GFK'),
-      # ('http://www.mlsmatrix.com' 'MLSMatrix'),
+      ('http://www.gfk.com', 'GFK'),
+      ('http://www.mlsmatrix.com', 'MLSMatrix'),
     ], cache_temperatures, traffic_settings)
 
   def AddStories(self, tags, urls, cache_temperatures, traffic_settings):
@@ -153,3 +145,33 @@
           self.AddStory(page_cycler_story.PageCyclerStory(url, self, name=name,
               shared_page_state_class=shared_page_state.SharedMobilePageState,
               cache_temperature=temp, traffic_setting=traffic, tags=tags))
+
+class LoadingMobileExpectations(story.expectations.StoryExpectations):
+  def SetExpectations(self):
+    self.DisableStory('GFK', [story.expectations.ALL],
+                      'N5X Timeout issue: crbug.com/702175')
+    self.DisableStory('MLSMatrix', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('EBS', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('IBI', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('SBS', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('FuturaSciences', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('HashOcean', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    self.DisableStory('163', [story.expectations.ALL],
+                      'N5XTimeout issue: crbug.com/702175')
+    # TODO(rnephew): Uncomment Disablings. crbug.com/728882
+    # self.DisableStory(
+    #     'AirHorner', [story.expectations.ALL], 'crbug.com/653775')
+    # self.DisableStory(
+    #     'BusRouter', [story.expectations.ALL], 'crbug.com/653775')
+    # self.DisableStory('WikiOffline', [story.expectations.ALL],
+    #                   'crbug.com/653775')
+    # self.DisableStory('Detik', [story.expectations.ALL], 'crbug.com/653775')
+    # self.DisableStory(
+    #     'Blogspot', [story.expectations.ALL], 'crbug.com/653775')
+    self.DisableStory('G1', [story.expectations.ALL], 'crbug.com/656861')
diff --git a/ui/events/keycodes/dom/keycode_converter.cc b/ui/events/keycodes/dom/keycode_converter.cc
index 94792e5..1d5408c 100644
--- a/ui/events/keycodes/dom/keycode_converter.cc
+++ b/ui/events/keycodes/dom/keycode_converter.cc
@@ -75,6 +75,9 @@
   return usb_keycode_map[0].native_keycode;
 }
 
+// TODO(zijiehe): Most of the following functions can be optimized by using
+// either multiple arrays or unordered_map.
+
 // static
 DomCode KeycodeConverter::NativeKeycodeToDomCode(int native_keycode) {
   for (size_t i = 0; i < kKeycodeMapEntries; ++i) {
@@ -297,7 +300,7 @@
 }
 
 // static
-uint32_t KeycodeConverter::CodeToUsbKeycode(const std::string& code) {
+uint32_t KeycodeConverter::CodeStringToUsbKeycode(const std::string& code) {
   if (code.empty())
     return InvalidUsbKeycode();
 
@@ -309,4 +312,9 @@
   return InvalidUsbKeycode();
 }
 
+// static
+int KeycodeConverter::CodeStringToNativeKeycode(const std::string& code) {
+  return UsbKeycodeToNativeKeycode(CodeStringToUsbKeycode(code));
+}
+
 }  // namespace ui
diff --git a/ui/events/keycodes/dom/keycode_converter.h b/ui/events/keycodes/dom/keycode_converter.h
index 1834835c..a4908e2 100644
--- a/ui/events/keycodes/dom/keycode_converter.h
+++ b/ui/events/keycodes/dom/keycode_converter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_EVENTS_KEYCODES_DOM4_KEYCODE_CONVERTER_H_
-#define UI_EVENTS_KEYCODES_DOM4_KEYCODE_CONVERTER_H_
+#ifndef UI_EVENTS_KEYCODES_DOM_KEYCODE_CONVERTER_H_
+#define UI_EVENTS_KEYCODES_DOM_KEYCODE_CONVERTER_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -99,8 +99,11 @@
   // Convert a DomCode into a USB keycode.
   static uint32_t DomCodeToUsbKeycode(DomCode dom_code);
 
-  // Convert a DOM3 Event |code| string into a USB keycode value.
-  static uint32_t CodeToUsbKeycode(const std::string& code);
+  // Convert a UI Event |code| string into a USB keycode value.
+  static uint32_t CodeStringToUsbKeycode(const std::string& code);
+
+  // Convert a UI Event |code| string into a native keycode.
+  static int CodeStringToNativeKeycode(const std::string& code);
 
   // Static methods to support testing.
   static size_t NumKeycodeMapEntriesForTest();
@@ -113,4 +116,4 @@
 
 }  // namespace ui
 
-#endif  // UI_EVENTS_KEYCODES_DOM4_KEYCODE_CONVERTER_H_
+#endif  // UI_EVENTS_KEYCODES_DOM_KEYCODE_CONVERTER_H_
diff --git a/ui/gl/android/surface_texture.cc b/ui/gl/android/surface_texture.cc
index 2cd25173d..2ddad6c 100644
--- a/ui/gl/android/surface_texture.cc
+++ b/ui/gl/android/surface_texture.cc
@@ -16,13 +16,9 @@
 namespace gl {
 
 scoped_refptr<SurfaceTexture> SurfaceTexture::Create(int texture_id) {
-  return new SurfaceTexture(CreateJavaSurfaceTexture(texture_id));
-}
-
-base::android::ScopedJavaLocalRef<jobject>
-SurfaceTexture::CreateJavaSurfaceTexture(int texture_id) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  return Java_SurfaceTexturePlatformWrapper_create(env, texture_id);
+  return new SurfaceTexture(
+      Java_SurfaceTexturePlatformWrapper_create(env, texture_id));
 }
 
 SurfaceTexture::SurfaceTexture(
@@ -31,20 +27,11 @@
 }
 
 SurfaceTexture::~SurfaceTexture() {
-  DestroyJavaObject();
-}
-
-void SurfaceTexture::DestroyJavaObject() {
-  if (j_surface_texture_.is_null())
-    return;
-
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SurfaceTexturePlatformWrapper_destroy(env, j_surface_texture_);
-  j_surface_texture_.Reset();
 }
 
-void SurfaceTexture::SetFrameAvailableCallback(
-    const base::Closure& callback) {
+void SurfaceTexture::SetFrameAvailableCallback(const base::Closure& callback) {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SurfaceTexturePlatformWrapper_setFrameAvailableCallback(
       env, j_surface_texture_,
@@ -102,12 +89,12 @@
   // ANativeWindow_fromSurface are released immediately. This is needed as a
   // workaround for https://code.google.com/p/android/issues/detail?id=68174
   base::android::ScopedJavaLocalFrame scoped_local_reference_frame(env);
-  ANativeWindow* native_window = ANativeWindow_fromSurface(
-      env, surface.j_surface().obj());
+  ANativeWindow* native_window =
+      ANativeWindow_fromSurface(env, surface.j_surface().obj());
   return native_window;
 }
 
-void SurfaceTexture::ReleaseSurfaceTexture() {
+void SurfaceTexture::ReleaseBackBuffers() {
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SurfaceTexturePlatformWrapper_release(env, j_surface_texture_);
 }
diff --git a/ui/gl/android/surface_texture.h b/ui/gl/android/surface_texture.h
index db22581..451fc751 100644
--- a/ui/gl/android/surface_texture.h
+++ b/ui/gl/android/surface_texture.h
@@ -20,7 +20,7 @@
 // This class serves as a bridge for native code to call java functions inside
 // android SurfaceTexture class.
 class GL_EXPORT SurfaceTexture
-    : public base::RefCountedThreadSafe<SurfaceTexture>{
+    : public base::RefCountedThreadSafe<SurfaceTexture> {
  public:
   static scoped_refptr<SurfaceTexture> Create(int texture_id);
 
@@ -46,11 +46,11 @@
 
   // Attach the SurfaceTexture to the texture currently bound to
   // GL_TEXTURE_EXTERNAL_OES.
-  virtual void AttachToGLContext();
+  void AttachToGLContext();
 
   // Detaches the SurfaceTexture from the context that owns its current GL
   // texture. Must be called with that context current on the calling thread.
-  virtual void DetachFromGLContext();
+  void DetachFromGLContext();
 
   // Creates a native render surface for this surface texture.
   // The caller must release the underlying reference when done with the handle
@@ -58,9 +58,10 @@
   ANativeWindow* CreateSurface();
 
   // Release the SurfaceTexture back buffers.  The SurfaceTexture is no longer
-  // usable after calling this.  Note that this is not called 'Release', like
-  // the android API, because scoped_refptr<> calls that quite a bit.
-  void ReleaseSurfaceTexture();
+  // usable after calling this but the front buffer is still valid. Note that
+  // this is not called 'Release', like the Android API, because scoped_refptr
+  // calls that quite a bit.
+  void ReleaseBackBuffers();
 
   // Set the default buffer size for the surface texture.
   void SetDefaultBufferSize(int width, int height);
@@ -70,19 +71,12 @@
   }
 
  protected:
-  static base::android::ScopedJavaLocalRef<jobject> CreateJavaSurfaceTexture(
-      int texture_id);
-
   explicit SurfaceTexture(
       const base::android::ScopedJavaLocalRef<jobject>& j_surface_texture);
 
-  virtual ~SurfaceTexture();
-
-  // Destroy |j_surface_texture| if it hasn't been destroyed already.
-  void DestroyJavaObject();
-
  private:
   friend class base::RefCountedThreadSafe<SurfaceTexture>;
+  virtual ~SurfaceTexture();
 
   // Java SurfaceTexture instance.
   base::android::ScopedJavaGlobalRef<jobject> j_surface_texture_;
diff --git a/ui/login/account_picker/md_user_pod_row.css b/ui/login/account_picker/md_user_pod_row.css
index 1fc9f13c..7b98bb6 100644
--- a/ui/login/account_picker/md_user_pod_row.css
+++ b/ui/login/account_picker/md_user_pod_row.css
@@ -108,6 +108,36 @@
   flex: none;
 }
 
+.pod .badge-container {
+  background: #FFF;
+  border-radius: 50%;
+  bottom: 0;
+  display: none;
+  height: 27px;
+  position: absolute;
+  right: 0;
+  width: 27px;
+}
+
+.pod .badge-container iron-icon {
+  --iron-icon-height: 25px;
+  --iron-icon-width: 25px;
+  display: none;
+  padding: 0;
+}
+
+/* Signed-in badge should be hidden when there's another badge. */
+.pod.legacy-supervised.signed-in .signed-in-badge {
+  display: none;
+}
+
+.pod.legacy-supervised .badge-container,
+.pod.signed-in .badge-container,
+.pod.legacy-supervised .legacy-supervised-badge,
+.pod.signed-in .signed-in-badge {
+  display: block;
+}
+
 /* TODO(noms): Refactor this out into a CrOS-specific file and simplify the
  style rule once it is included on CrOS only. crbug.com/397638 */
 html:not([screen=login-add-user]) .pod .user-image {
@@ -201,7 +231,7 @@
   display: none;
 }
 
-#input-line {
+.input-line {
   opacity: 0.34;
   position: absolute;
   stroke: #FFFFFF;
@@ -209,7 +239,7 @@
   top: 40px;
 }
 
-#input-line[active] {
+.input-present .input-line {
   opacity: 1;
 }
 
@@ -228,6 +258,10 @@
   width: 180px;
 }
 
+.capslock-on .password-container {
+  width: 160px;
+}
+
 .pod input[type='password'] {
   background-color: transparent;
   border: none;
@@ -252,18 +286,21 @@
 .capslock-on .capslock-hint-container {
   display: block;
   flex: none;
-  height: 43px;
+  height: 40px;
   position: relative;
   width: 20px;
 }
 </if>
 
 .capslock-hint {
-  -webkit-margin-end: 6px;
-  -webkit-margin-start: -2px;
-  margin: auto;
-  position: relative;
-  top: 15px;
+  --iron-icon-height: 22px;
+  --iron-icon-width: 22px;
+  opacity: 0.34;
+  padding: 13px 0 5px;
+}
+
+.input-present .capslock-hint {
+  opacity: 1;
 }
 
 .password-label,
diff --git a/ui/login/account_picker/md_user_pod_row.js b/ui/login/account_picker/md_user_pod_row.js
index 9316cc9..b3fc866e 100644
--- a/ui/login/account_picker/md_user_pod_row.js
+++ b/ui/login/account_picker/md_user_pod_row.js
@@ -1306,7 +1306,9 @@
 
     setUserPodIconType: function(userTypeClass) {
       this.userTypeIconAreaElement.classList.add(userTypeClass);
-      this.userTypeIconAreaElement.hidden = false;
+      // TODO(wzang): Evaluate all icon types other than supervised user and
+      // switch them to badges per the design spec.
+      this.userTypeIconAreaElement.hidden = true;
     },
 
     isFingerprintIconShown: function() {
@@ -2044,13 +2046,7 @@
       }
       this.showError = false;
       $('bubble').hide();
-      var inputLine = this.querySelector('#input-line');
-      if (inputLine) {
-        if (!isEmpty)
-          inputLine.setAttribute('active', 'true');
-        else
-          inputLine.removeAttribute('active');
-      }
+      this.classList.toggle('input-present', !isEmpty);
     },
 
     /**
diff --git a/ui/login/account_picker/md_user_pod_template.html b/ui/login/account_picker/md_user_pod_template.html
index 0b69870..82ee6c51 100644
--- a/ui/login/account_picker/md_user_pod_template.html
+++ b/ui/login/account_picker/md_user_pod_template.html
@@ -20,6 +20,15 @@
       <g id="dropdown" fill="#FFFFFF" stroke="none" stroke-width="1" fill-rule="evenodd" opacity="0.34">
           <polygon points="16.59 8.59 12 13.17 7.41 8.59 6 10 12 16 18 10"></polygon>
       </g>
+      <g id="legacy-supervised-badge">
+          <path d="M16.5,13.5 C17.42,13.5 18.16,12.7533333 18.16,11.8333333 C18.16,10.9133333 17.42,10.1666667 16.5,10.1666667 C15.58,10.1666667 14.8333333,10.9133333 14.8333333,11.8333333 C14.8333333,12.7533333 15.58,13.5 16.5,13.5 Z M11.5,12.8333333 C12.6066667,12.8333333 13.4933333,11.94 13.4933333,10.8333333 C13.4933333,9.72666667 12.6066667,8.83333333 11.5,8.83333333 C10.3933333,8.83333333 9.5,9.72666667 9.5,10.8333333 C9.5,11.94 10.3933333,12.8333333 11.5,12.8333333 Z M16.5,14.8333333 C15.28,14.8333333 12.8333333,15.4466667 12.8333333,16.6666667 L12.8333333,18.1666667 L20.1666667,18.1666667 L20.1666667,16.6666667 C20.1666667,15.4466667 17.72,14.8333333 16.5,14.8333333 Z M11.5,14.1666667 C9.94666667,14.1666667 6.83333333,14.9466667 6.83333333,16.5 L6.83333333,18.1666667 L11.5,18.1666667 L11.5,16.6666667 C11.5,16.1 11.72,15.1066667 13.08,14.3533333 C12.5,14.2333333 11.94,14.1666667 11.5,14.1666667 Z" id="Shape" fill="#000000" fill-rule="nonzero" opacity="0.34"></path>
+      </g>
+      <g id="signed-in-badge">
+          <polygon id="Shape" fill="#000000" fill-rule="nonzero" opacity="0.34" points="11.5 16.28 8.72 13.5 7.77333333 14.44 11.5 18.1666667 19.5 10.1666667 18.56 9.22666667"></polygon>
+      </g>
+      <g id="caps-lock">
+          <path d="M2.5,4.49188419 C2.5,3.39179693 3.39339733,2.5 4.49188419,2.5 L15.5081158,2.5 C16.6082031,2.5 17.5,3.39339733 17.5,4.49188419 L17.5,15.5081158 C17.5,16.6082031 16.6066027,17.5 15.5081158,17.5 L4.49188419,17.5 C3.39179693,17.5 2.5,16.6066027 2.5,15.5081158 L2.5,4.49188419 Z M10,7.47368421 L13.825,11.5 L15,10.2631579 L10,5 L5,10.2631579 L6.175,11.5 L10,7.47368421 Z M5,15 L15,15 L15,13.5 L5,13.5 L5,15 Z" id="Combined-Shape" fill="#FFFFFF"></path>
+      </g>
     </defs>
   </svg>
 </iron-iconset-svg>
@@ -30,10 +39,12 @@
       <div class="user-image-container">
         <img class="user-image" alt>
       </div>
-      <div class="indicator-container">
-        <div class="indicator legacy-supervised-indicator"></div>
-        <div class="indicator child-indicator"></div>
-        <div class="indicator locked-indicator"></div>
+      <div class="badge-container">
+        <iron-icon class="legacy-supervised-badge"
+            icon="user-pod:legacy-supervised-badge">
+        </iron-icon>
+        <iron-icon class="signed-in-badge" icon="user-pod:signed-in-badge">
+        </iron-icon>
       </div>
     </div>
 <if expr="chromeos">
@@ -126,8 +137,8 @@
           </div>
 <if expr="chromeos">
           <div class="capslock-hint-container">
-            <img class="capslock-hint"
-                 src="chrome://theme/IDR_LOGIN_PASSWORD_CAPS_LOCK" alt>
+            <iron-icon class="capslock-hint" icon="user-pod:caps-lock">
+            </iron-icon>
           </div>
           <paper-icon-button class="submit-button" disabled
                              aria-label="$i18n{submitButtonAccessibleName}"
@@ -150,7 +161,7 @@
         <div class="launch-app-button-container" hidden>
           <button class="launch-app-button">$i18n{launchAppButton}</button>
         </div>
-        <div id="input-line">
+        <div class="input-line">
           <svg>
             <line x1="0" y1="0" x2="204" y2="0">
           </svg>