diff --git a/AUTHORS b/AUTHORS
index 84b49da..cba67225 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -225,6 +225,7 @@
 Franklin Ta <fta2012@gmail.com>
 Frédéric Jacob <frederic.jacob.78@gmail.com>
 Frédéric Wang <fred.wang@free.fr>
+Fu Junwei <junwei.fu@intel.com>
 Gaetano Mendola <mendola@gmail.com>
 Gajendra N <gajendra.n@samsung.com>
 Gajendra Singh <wxjg68@motorola.com>
diff --git a/DEPS b/DEPS
index 4c30044..bc5aac6 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '5aa9158a24bc0bd27db7d740e4ec07f6aa64f060',
+  'skia_revision': '54d212e1bfaea0be88c3c40820d0b1ae0daebecf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # 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': '32b94557c605f02fa969bc84b3c9b6f5277c258e',
+  'pdfium_revision': '742fa8c3b39f0e3713c3450b1f9979174fbb4c8f',
   # 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': '84775f4ca78a0be205752065afdbd44432555a1b',
+  'catapult_revision': '8cbbd7f6c6207e388918855a3536c5b7f30bff29',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index a0e3871..5f44b673 100644
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -785,24 +785,6 @@
 #endif  // !defined(OS_NACL)
 
 // static
-void GlobalHistogramAllocator::CreateWithSharedMemory(
-    std::unique_ptr<SharedMemory> memory,
-    size_t size,
-    uint64_t id,
-    StringPiece name) {
-  if ((!memory->memory() && !memory->Map(size)) ||
-      !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*memory)) {
-    NOTREACHED();
-    return;
-  }
-
-  DCHECK_LE(memory->mapped_size(), size);
-  Set(WrapUnique(
-      new GlobalHistogramAllocator(MakeUnique<SharedPersistentMemoryAllocator>(
-          std::move(memory), 0, StringPiece(), /*readonly=*/false))));
-}
-
-// static
 void GlobalHistogramAllocator::CreateWithSharedMemoryHandle(
     const SharedMemoryHandle& handle,
     size_t size) {
diff --git a/base/metrics/persistent_histogram_allocator.h b/base/metrics/persistent_histogram_allocator.h
index 2eb28dfa..851d7ef 100644
--- a/base/metrics/persistent_histogram_allocator.h
+++ b/base/metrics/persistent_histogram_allocator.h
@@ -431,15 +431,6 @@
                                  FilePath* out_active_path);
 #endif
 
-  // Create a global allocator using a block of shared |memory| of the
-  // specified |size|. The allocator takes ownership of the shared memory
-  // and releases it upon destruction, though the memory will continue to
-  // live if other processes have access to it.
-  static void CreateWithSharedMemory(std::unique_ptr<SharedMemory> memory,
-                                     size_t size,
-                                     uint64_t id,
-                                     StringPiece name);
-
   // Create a global allocator using a block of shared memory accessed
   // through the given |handle| and |size|. The allocator takes ownership
   // of the handle and closes it upon destruction, though the memory will
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 74e3f19..0419926d 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -302,13 +302,20 @@
   # Linux/Android common flags setup.
   # ---------------------------------
   if (is_linux || is_android) {
+    if (use_pic) {
+      cflags += [
+        "-fPIC",
+      ]
+      ldflags += [
+        "-fPIC",
+      ]
+    }
+
     cflags += [
-      "-fPIC",
       "-pipe",  # Use pipes for communicating between sub-processes. Faster.
     ]
 
     ldflags += [
-      "-fPIC",
       "-Wl,-z,noexecstack",
       "-Wl,-z,now",
       "-Wl,-z,relro",
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 787990a..66c65e05 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -58,6 +58,9 @@
   #
   # See crbug.com/669854.
   linkrepro_root_dir = ""
+
+  # Whether or not we should use position independent code.
+  use_pic = true
 }
 
 declare_args() {
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 3819e7e..695e85d 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -25,6 +25,8 @@
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
 
+namespace {
+
 static gfx::Transform OrthoProjectionMatrix(float left,
                                             float right,
                                             float bottom,
@@ -62,6 +64,13 @@
   return canvas;
 }
 
+// Switching between enabling DC layers and not is expensive, so only
+// switch away after a large number of frames not needing DC layers have
+// been produced.
+constexpr int kNumberOfFramesBeforeDisablingDCLayers = 60;
+
+}  // namespace
+
 namespace cc {
 
 DirectRenderer::DrawingFrame::DrawingFrame() = default;
@@ -87,8 +96,8 @@
   if (context_provider) {
     if (context_provider->ContextCapabilities().commit_overlay_planes)
       allow_empty_swap_ = true;
-    if (context_provider->ContextCapabilities().set_draw_rectangle)
-      use_set_draw_rectangle_ = true;
+    if (context_provider->ContextCapabilities().dc_layers)
+      supports_dc_layers_ = true;
   }
 
   initialized_ = true;
@@ -314,6 +323,19 @@
       &current_frame()->dc_layer_overlay_list,
       &current_frame()->root_damage_rect,
       &current_frame()->root_content_bounds);
+  bool was_using_dc_layers = using_dc_layers_;
+  if (!current_frame()->dc_layer_overlay_list.empty()) {
+    DCHECK(supports_dc_layers_);
+    using_dc_layers_ = true;
+    frames_since_using_dc_layers_ = 0;
+  } else if (++frames_since_using_dc_layers_ >=
+             kNumberOfFramesBeforeDisablingDCLayers) {
+    using_dc_layers_ = false;
+  }
+  if (was_using_dc_layers != using_dc_layers_) {
+    current_frame()->root_damage_rect =
+        current_frame()->root_render_pass->output_rect;
+  }
 
   // We can skip all drawing if the damage rect is now empty.
   bool skip_drawing_root_render_pass =
@@ -523,7 +545,7 @@
   // outside the damage rectangle, even if the damage rectangle is the size of
   // the full backbuffer.
   bool render_pass_is_clipped =
-      (use_set_draw_rectangle_ && is_root_render_pass) ||
+      (supports_dc_layers_ && is_root_render_pass) ||
       !render_pass_scissor_in_draw_space.Contains(surface_rect_in_draw_space);
   bool has_external_stencil_test =
       is_root_render_pass && output_surface_->HasExternalStencilTest();
@@ -597,8 +619,10 @@
   if (render_pass == current_frame()->root_render_pass) {
     BindFramebufferToOutputSurface();
 
-    if (use_set_draw_rectangle_)
+    if (supports_dc_layers_) {
+      SetEnableDCLayers(using_dc_layers_);
       output_surface_->SetDrawRectangle(current_frame()->root_damage_rect);
+    }
     InitializeViewport(current_frame(), render_pass->output_rect,
                        gfx::Rect(current_frame()->device_viewport_size),
                        current_frame()->device_viewport_size);
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index eb8ddab3..70632063 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -166,6 +166,7 @@
   virtual void DidChangeVisibility() = 0;
   virtual void CopyCurrentRenderPassToBitmap(
       std::unique_ptr<CopyOutputRequest> request) = 0;
+  virtual void SetEnableDCLayers(bool enable) = 0;
 
   gfx::Size surface_size_for_swap_buffers() const {
     return reshape_surface_size_;
@@ -184,8 +185,14 @@
   bool use_partial_swap_ = false;
   // Whether overdraw feedback is enabled and can be used.
   bool overdraw_feedback_ = false;
-  // Whether the SetDrawRectangle command is in use.
-  bool use_set_draw_rectangle_ = false;
+  // Whether the SetDrawRectangle and EnableDCLayers commands are in
+  // use.
+  bool supports_dc_layers_ = false;
+  // Whether the output surface is actually using DirectComposition.
+  bool using_dc_layers_ = false;
+  // This counts the number of draws since the last time
+  // DirectComposition layers needed to be used.
+  int frames_since_using_dc_layers_ = 0;
 
   // TODO(danakj): Just use a vector of pairs here? Hash map is way overkill.
   std::unordered_map<int, std::unique_ptr<ScopedResource>>
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index d3d4851..809bbdd 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -2464,6 +2464,10 @@
   FlushTextureQuadCache(SHARED_BINDING);
 }
 
+void GLRenderer::SetEnableDCLayers(bool enable) {
+  gl_->SetEnableDCLayersCHROMIUM(enable);
+}
+
 bool GLRenderer::FlippedFramebuffer() const {
   if (force_drawing_frame_framebuffer_unflipped_)
     return false;
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 8e6f9d6..682a3d7ca 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -100,6 +100,7 @@
   void EnsureScissorTestDisabled() override;
   void CopyCurrentRenderPassToBitmap(
       std::unique_ptr<CopyOutputRequest> request) override;
+  void SetEnableDCLayers(bool enable) override;
   void FinishDrawingQuadList() override;
 
   // Returns true if quad requires antialiasing and false otherwise.
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 39929f4..fd5faa1 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -1641,8 +1641,7 @@
 
     // Returns true if draw quads can be represented as CALayers (Mac only).
     MOCK_METHOD0(AllowCALayerOverlays, bool());
-
-    bool AllowDCLayerOverlays() override { return false; }
+    MOCK_METHOD0(AllowDCLayerOverlays, bool());
 
     // A list of possible overlay candidates is presented to this function.
     // The expected result is that those candidates that can be in a separate
@@ -1733,6 +1732,7 @@
   // list because the render pass is cleaned up by DrawFrame.
   EXPECT_CALL(*processor->strategy_, Attempt(_, _, _, _)).Times(0);
   EXPECT_CALL(*validator, AllowCALayerOverlays()).Times(0);
+  EXPECT_CALL(*validator, AllowDCLayerOverlays()).Times(0);
   DrawFrame(&renderer, viewport_size);
   Mock::VerifyAndClearExpectations(processor->strategy_);
   Mock::VerifyAndClearExpectations(validator.get());
@@ -1752,6 +1752,9 @@
   EXPECT_CALL(*validator, AllowCALayerOverlays())
       .Times(1)
       .WillOnce(::testing::Return(false));
+  EXPECT_CALL(*validator, AllowDCLayerOverlays())
+      .Times(1)
+      .WillOnce(::testing::Return(false));
   EXPECT_CALL(*processor->strategy_, Attempt(_, _, _, _)).Times(1);
   DrawFrame(&renderer, viewport_size);
 
@@ -1904,20 +1907,21 @@
 
 class PartialSwapMockGLES2Interface : public TestGLES2Interface {
  public:
-  explicit PartialSwapMockGLES2Interface(bool support_set_draw_rectangle)
-      : support_set_draw_rectangle_(support_set_draw_rectangle) {}
+  explicit PartialSwapMockGLES2Interface(bool support_dc_layers)
+      : support_dc_layers_(support_dc_layers) {}
 
   void InitializeTestContext(TestWebGraphicsContext3D* context) override {
     context->set_have_post_sub_buffer(true);
-    context->set_support_set_draw_rectangle(support_set_draw_rectangle_);
+    context->set_enable_dc_layers(support_dc_layers_);
   }
 
   MOCK_METHOD1(Enable, void(GLenum cap));
   MOCK_METHOD1(Disable, void(GLenum cap));
   MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
+  MOCK_METHOD1(SetEnableDCLayersCHROMIUM, void(GLboolean enable));
 
  private:
-  bool support_set_draw_rectangle_;
+  bool support_dc_layers_;
 };
 
 class GLRendererPartialSwapTest : public GLRendererTest {
@@ -2016,6 +2020,103 @@
   RunTest(false, true);
 }
 
+class DCLayerValidator : public OverlayCandidateValidator {
+ public:
+  void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
+  bool AllowCALayerOverlays() override { return false; }
+  bool AllowDCLayerOverlays() override { return true; }
+  void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
+};
+
+// Test that SetEnableDCLayersCHROMIUM is properly called when enabling
+// and disabling DC layers.
+TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
+  auto gl_owned = base::MakeUnique<PartialSwapMockGLES2Interface>(true);
+  auto* gl = gl_owned.get();
+
+  auto provider = TestContextProvider::Create(std::move(gl_owned));
+  provider->BindToCurrentThread();
+
+  FakeOutputSurfaceClient output_surface_client;
+  std::unique_ptr<FakeOutputSurface> output_surface(
+      FakeOutputSurface::Create3d(std::move(provider)));
+  output_surface->BindToClient(&output_surface_client);
+
+  std::unique_ptr<ResourceProvider> resource_provider =
+      FakeResourceProvider::Create(output_surface->context_provider(), nullptr);
+
+  RendererSettings settings;
+  settings.partial_swap_enabled = true;
+  FakeRendererGL renderer(&settings, output_surface.get(),
+                          resource_provider.get());
+  renderer.Initialize();
+  renderer.SetVisible(true);
+  TestOverlayProcessor* processor =
+      new TestOverlayProcessor(output_surface.get());
+  processor->Initialize();
+  renderer.SetOverlayProcessor(processor);
+  std::unique_ptr<DCLayerValidator> validator(new DCLayerValidator);
+  output_surface->SetOverlayCandidateValidator(validator.get());
+
+  gfx::Size viewport_size(100, 100);
+
+  TextureMailbox mailbox =
+      TextureMailbox(gpu::Mailbox::Generate(), gpu::SyncToken(), GL_TEXTURE_2D,
+                     gfx::Size(256, 256), true, false);
+  std::unique_ptr<SingleReleaseCallbackImpl> release_callback =
+      SingleReleaseCallbackImpl::Create(base::Bind(&MailboxReleased));
+  ResourceId resource_id = resource_provider->CreateResourceFromTextureMailbox(
+      mailbox, std::move(release_callback));
+
+  for (int i = 0; i < 65; i++) {
+    int root_pass_id = 1;
+    RenderPass* root_pass = AddRenderPass(
+        &render_passes_in_draw_order_, root_pass_id, gfx::Rect(viewport_size),
+        gfx::Transform(), FilterOperations());
+    if (i == 0) {
+      gfx::Rect rect(0, 0, 100, 100);
+      gfx::RectF tex_coord_rect(0, 0, 1, 1);
+      SharedQuadState* shared_state =
+          root_pass->CreateAndAppendSharedQuadState();
+      shared_state->SetAll(gfx::Transform(), rect.size(), rect, rect, false, 1,
+                           SkBlendMode::kSrcOver, 0);
+      YUVVideoDrawQuad* quad =
+          root_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
+      quad->SetNew(shared_state, rect, rect, rect, tex_coord_rect,
+                   tex_coord_rect, rect.size(), rect.size(), resource_id,
+                   resource_id, resource_id, resource_id,
+                   YUVVideoDrawQuad::REC_601, gfx::ColorSpace(), 0, 1.0, 8);
+    }
+
+    // A bunch of initialization that happens.
+    EXPECT_CALL(*gl, Disable(_)).Times(AnyNumber());
+    EXPECT_CALL(*gl, Enable(_)).Times(AnyNumber());
+    EXPECT_CALL(*gl, Scissor(_, _, _, _)).Times(AnyNumber());
+
+    // Partial frame, we should use a scissor to swap only that part when
+    // partial swap is enabled.
+    root_pass->damage_rect = gfx::Rect(2, 2, 3, 3);
+    // Frame 0 should be completely damaged because it's the first.
+    // Frame 1 should be because it changed. Frame 60 should be
+    // because it's disabling DC layers.
+    gfx::Rect output_rectangle = (i == 0 || i == 1 || i == 60)
+                                     ? root_pass->output_rect
+                                     : root_pass->damage_rect;
+
+    // Frame 0 should have DC Layers enabled because of the overlay.
+    // After 60 frames of no overlays DC layers should be disabled again.
+    if (i < 60)
+      EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_TRUE));
+    else
+      EXPECT_CALL(*gl, SetEnableDCLayersCHROMIUM(GL_FALSE));
+
+    renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
+    DrawFrame(&renderer, viewport_size);
+    EXPECT_EQ(output_rectangle, output_surface->last_set_draw_rectangle());
+    testing::Mock::VerifyAndClearExpectations(gl);
+  }
+}
+
 class GLRendererWithMockContextTest : public ::testing::Test {
  protected:
   class MockContextSupport : public TestContextSupport {
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 35165f75..d1715cb 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -84,8 +84,8 @@
   virtual void BindFramebuffer() = 0;
 
   // Marks that the given rectangle will be drawn to on the default, bound
-  // framebuffer. Only valid for surfaces with set_draw_rectangle in the
-  // context capabilities.
+  // framebuffer. Only valid for surfaces with dc_layers in the context
+  // capabilities.
   virtual void SetDrawRectangle(const gfx::Rect& rect) = 0;
 
   // Get the class capable of informing cc of hardware overlay capability.
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index c39672c..8bd1e381 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -583,6 +583,10 @@
   request->SendBitmapResult(std::move(bitmap));
 }
 
+void SoftwareRenderer::SetEnableDCLayers(bool enable) {
+  NOTIMPLEMENTED();
+}
+
 void SoftwareRenderer::DidChangeVisibility() {
   if (visible_)
     output_surface_->EnsureBackbuffer();
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h
index 7349a6e..c7204ad 100644
--- a/cc/output/software_renderer.h
+++ b/cc/output/software_renderer.h
@@ -51,6 +51,7 @@
   void EnsureScissorTestDisabled() override;
   void CopyCurrentRenderPassToBitmap(
       std::unique_ptr<CopyOutputRequest> request) override;
+  void SetEnableDCLayers(bool enable) override;
   void DidChangeVisibility() override;
 
  private:
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index c16db55..233c067e 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -347,8 +347,8 @@
   void set_gpu_rasterization(bool gpu_rasterization) {
     test_capabilities_.gpu_rasterization = gpu_rasterization;
   }
-  void set_support_set_draw_rectangle(bool support) {
-    test_capabilities_.set_draw_rectangle = support;
+  void set_enable_dc_layers(bool support) {
+    test_capabilities_.dc_layers = support;
   }
 
   // When this context is lost, all contexts in its share group are also lost.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 7975234..00a7a89 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -213,6 +213,7 @@
     "//services/service_manager/public/interfaces:interfaces_java",
     "//services/service_manager/public/java:service_manager_java",
     "//services/shape_detection/public/interfaces:interfaces_java",
+    "//skia/public/interfaces:interfaces_java",
     "//third_party/WebKit/public:android_mojo_bindings_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/WebKit/public:mojo_bindings_java",
diff --git a/chrome/android/java/res/layout/data_reduction_promo_screen.xml b/chrome/android/java/res/layout/data_reduction_promo_screen.xml
deleted file mode 100644
index 8370f8e..0000000
--- a/chrome/android/java/res/layout/data_reduction_promo_screen.xml
+++ /dev/null
@@ -1,119 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    android:background="#c000" >
-
-    <RelativeLayout
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        android:layout_gravity="center"
-        android:background="#FFFF" >
-
-        <LinearLayout
-            android:layout_height="wrap_content"
-            android:layout_width="match_parent"
-            android:layout_alignParentTop="true"
-            android:orientation="vertical" >
-
-            <ScrollView
-                android:id="@+id/data_reduction_promo_scroll"
-                android:layout_height="0dp"
-                android:layout_width="match_parent"
-                android:layout_weight="1"
-                android:fillViewport="true"
-                android:requiresFadingEdge="vertical"
-                android:fadingEdgeLength="20dp" >
-
-                <LinearLayout
-                    android:id="@+id/data_reduction_promo_content"
-                    android:layout_height="wrap_content"
-                    android:layout_width="match_parent"
-                    android:paddingEnd="24dp"
-                    android:paddingStart="24dp"
-                    android:paddingTop="64dp" >
-
-                    <ImageView
-                        android:id="@+id/data_reduction_illustration"
-                        android:layout_height="wrap_content"
-                        android:layout_width="wrap_content"
-                        android:layout_gravity="center"
-                        android:adjustViewBounds="true"
-                        android:contentDescription="@null"
-                        android:src="@drawable/data_reduction_illustration" />
-
-                    <LinearLayout
-                        android:id="@+id/text_wrapper"
-                        android:layout_height="wrap_content"
-                        android:layout_width="wrap_content"
-                        android:orientation="vertical" >
-
-                        <TextView
-                            android:layout_height="wrap_content"
-                            android:layout_width="match_parent"
-                            android:layout_marginBottom="8dp"
-                            android:text="@string/data_reduction_promo_title"
-                            android:textColor="@color/default_text_color"
-                            android:textSize="@dimen/data_reduction_promo_title_text_size" />
-
-                        <TextView
-                            android:layout_height="wrap_content"
-                            android:layout_width="match_parent"
-                            android:layout_marginBottom="30dp"
-                            android:lineSpacingMultiplier="1.3"
-                            android:text="@string/data_reduction_promo_summary"
-                            android:textColor="#646464"
-                            android:textSize="@dimen/data_reduction_promo_normal_text_size" />
-                    </LinearLayout>
-                </LinearLayout>
-            </ScrollView>
-
-            <LinearLayout
-                android:id="@+id/data_reduction_promo_buttons"
-                android:layout_height="wrap_content"
-                android:layout_width="match_parent"
-                android:orientation="horizontal"
-                android:clipToPadding="false"
-                android:padding="16dp"
-                android:gravity="end" >
-
-                <Button
-                    android:id="@+id/no_thanks_button"
-                    android:layout_height="match_parent"
-                    android:layout_width="wrap_content"
-                    android:layout_marginEnd="8dp"
-                    android:minHeight="40dp"
-                    android:text="@string/no_thanks"
-                    android:textColor="@color/light_normal_color"
-                    android:textSize="@dimen/data_reduction_promo_button_text_size"
-                    style="@style/ButtonCompatBorderless" />
-
-                <org.chromium.ui.widget.ButtonCompat
-                    android:id="@+id/enable_button"
-                    android:layout_height="match_parent"
-                    android:layout_width="wrap_content"
-                    android:elevation="0dp"
-                    android:minHeight="40dp"
-                    android:text="@string/data_reduction_enable_button"
-                    android:textColor="#FFFFFF"
-                    android:textSize="@dimen/data_reduction_promo_button_text_size"
-                    chrome:buttonColor="@color/light_active_color" />
-             </LinearLayout>
-         </LinearLayout>
-         
-         <org.chromium.chrome.browser.widget.TintedImageButton
-            android:id="@+id/close_button"
-            android:layout_height="56dp"
-            android:layout_width="56dp"
-            android:layout_alignParentEnd="true"
-            android:layout_alignParentTop="true"
-            android:background="?android:attr/selectableItemBackground"
-            android:contentDescription="@string/close"
-            android:src="@drawable/btn_close" />
-            
-    </RelativeLayout>
-</org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoView>
diff --git a/chrome/android/java/res/layout/promo_dialog_layout.xml b/chrome/android/java/res/layout/promo_dialog_layout.xml
new file mode 100644
index 0000000..a6aff720
--- /dev/null
+++ b/chrome/android/java/res/layout/promo_dialog_layout.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<!-- This XML should not be inflated by anything except PromoDialog.java.
+
+     This layout is deeply nested to account for the various bits having to flop orientations
+     in landscape.  If these become more frequently used, we should investigate optimizing the
+     layout.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:chrome="http://schemas.android.com/apk/res-auto" >
+
+    <org.chromium.chrome.browser.widget.PromoDialogLayout
+            android:id="@+id/promo_dialog_layout"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:orientation="vertical"
+            android:background="@drawable/menu_bg"
+            chrome:maxWidth="@dimen/promo_dialog_max_width" >
+
+        <org.chromium.chrome.browser.widget.FadingEdgeScrollView
+                android:id="@+id/promo_container"
+                android:layout_width="wrap_content"
+                android:layout_height="0dp"
+                android:layout_weight="1" >
+
+            <!-- This layout pivots when the dialog is wider than it is tall. -->
+            <LinearLayout
+                    android:id="@+id/promo_content"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:padding="@dimen/promo_dialog_padding"
+                    android:gravity="center"
+                    android:orientation="vertical" >
+
+                <ImageView
+                        android:id="@+id/illustration"
+                        android:layout_width="@dimen/promo_dialog_illustration_width"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="center"
+                        android:layout_margin="@dimen/promo_dialog_illustration_margin"
+                        android:scaleType="fitCenter"
+                        android:contentDescription="@null" />
+
+                <org.chromium.chrome.browser.widget.BoundedLinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        chrome:maxWidth="@dimen/promo_dialog_max_content_width" >
+
+                    <TextView
+                            android:id="@+id/header"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginBottom="14dp"
+                            android:textColor="@color/default_text_color"
+                            android:textSize="@dimen/promo_dialog_title_text_size" />
+
+                    <TextView
+                            android:id="@+id/subheader"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:lineSpacingMultiplier="1.3"
+                            android:textColor="#646464"
+                            android:textSize="@dimen/promo_dialog_normal_text_size" />
+                </org.chromium.chrome.browser.widget.BoundedLinearLayout>
+            </LinearLayout>
+
+        </org.chromium.chrome.browser.widget.FadingEdgeScrollView>
+
+        <org.chromium.chrome.browser.widget.DualControlLayout
+                android:id="@+id/button_bar"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="end"
+                android:padding="@dimen/promo_dialog_padding"
+                chrome:buttonAlignment="end"
+                chrome:stackedMargin="@dimen/infobar_padding" />
+
+    </org.chromium.chrome.browser.widget.PromoDialogLayout>
+
+</merge>
diff --git a/chrome/android/java/res/layout/search_engine_promo.xml b/chrome/android/java/res/layout/search_engine_promo.xml
deleted file mode 100644
index bfd03fbe..0000000
--- a/chrome/android/java/res/layout/search_engine_promo.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2016 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:background="#FAFAFA" >
-
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="10dp"
-        android:orientation="vertical"
-        android:padding="20dp" >
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal"
-            android:layout_margin="22dp"
-            android:contentDescription="@null"
-            android:src="@drawable/search_sogou" />
-
-        <TextView
-            android:id="@+id/title"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="14dp"
-            android:text="@string/search_with_sogou"
-            android:textColor="@color/default_text_color"
-            android:textSize="16sp" />
-
-        <TextView
-            android:id="@+id/description"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginBottom="30dp"
-            android:lineSpacingMultiplier="1.3"
-            android:textColor="#646464"
-            android:textSize="14sp" />
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:clipToPadding="false"
-            android:gravity="end"
-            android:orientation="horizontal" >
-
-            <Button
-                android:id="@+id/keep_google_button"
-                style="@style/ButtonCompatBorderless"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:layout_marginEnd="8dp"
-                android:minHeight="40dp"
-                android:text="@string/keep_google"
-                android:textAllCaps="true"
-                android:textColor="@color/light_active_color"
-                android:textSize="13sp" />
-
-            <org.chromium.ui.widget.ButtonCompat
-                android:id="@+id/ok_button"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:elevation="0dp"
-                android:minHeight="30dp"
-                android:text="@string/ok"
-                android:textAllCaps="true"
-                android:textColor="#FFFFFF"
-                android:textSize="13sp"
-                chrome:buttonColor="@color/light_active_color"
-                chrome:buttonRaised="false" />
-        </LinearLayout>
-    </LinearLayout>
-
-</ScrollView>
\ No newline at end of file
diff --git a/chrome/android/java/res/values-sw600dp/dimens.xml b/chrome/android/java/res/values-sw600dp/dimens.xml
index 3a75891..bb92312 100644
--- a/chrome/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/android/java/res/values-sw600dp/dimens.xml
@@ -17,8 +17,6 @@
 
     <!-- Data Saver -->
     <dimen name="data_usage_chart_height">325dp</dimen>
-    <dimen name="data_reduction_promo_screen_width">382dp</dimen>
-    <dimen name="data_reduction_promo_illustration_margin_bottom">62dp</dimen>
 
     <!-- Tab Strip Dimensions -->
     <dimen name="tab_strip_height">40dp</dimen>
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index c550e0c..89936ce 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -294,8 +294,8 @@
         <item name="android:windowEnterAnimation">@anim/fullscreen_notification_in</item>
     </style>
 
-    <!-- Data Saver -->
-    <style name="DataReductionPromoScreenDialog" >
+    <!-- Promo dialogs -->
+    <style name="PromoDialog" >
         <item name="android:background">@android:color/transparent</item>
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:clipChildren">false</item>
@@ -310,6 +310,7 @@
         <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowNoTitle">true</item>
     </style>
+
     <!-- Cast and media playback notifications -->
     <style
         name="MediaNotificationTitle"
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index d156c87..241c4ae 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -30,6 +30,7 @@
     <color name="semi_opaque_white">#80ffffff</color>
     <color name="toolbar_light_tint">#A3000000</color>
     <color name="light_grey">#ccc</color>
+    <color name="modal_dialog_scrim_color">#7f000000</color>
 
     <!-- Infobar colors -->
     <color name="infobar_accent_blue">#4285f4</color>
@@ -189,7 +190,6 @@
     <color name="bottom_bar_shadow_color">#1d000000</color>
 
     <!-- Payments UI colors -->
-    <color name="payments_ui_scrim">#000000</color>
     <color name="payments_section_edit_background">#f5f5f5</color>
     <color name="payments_section_chevron">#b2b2b2</color>
     <color name="payments_section_separator">#e0e0e0</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index eb14fca..07eaf696 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -131,14 +131,17 @@
     <!-- Minimum height/width for a touchable item -->
     <dimen name="min_touch_target_size">48dp</dimen>
 
+    <!-- Promo dialogs -->
+    <dimen name="promo_dialog_illustration_margin">24dp</dimen>
+    <dimen name="promo_dialog_illustration_width">150dp</dimen>
+    <dimen name="promo_dialog_padding">16dp</dimen>
+    <dimen name="promo_dialog_max_width">600dp</dimen>
+    <dimen name="promo_dialog_max_content_width">320dp</dimen>
+    <dimen name="promo_dialog_title_text_size">23sp</dimen>
+    <dimen name="promo_dialog_normal_text_size">14sp</dimen>
+
     <!-- Data Saver -->
     <dimen name="data_usage_chart_height">252dp</dimen>
-    <dimen name="data_reduction_promo_screen_width">330dp</dimen>
-    <dimen name="data_reduction_promo_screen_width_horizontal">500dp</dimen>
-    <dimen name="data_reduction_promo_title_text_size">20sp</dimen>
-    <dimen name="data_reduction_promo_normal_text_size">14sp</dimen>
-    <dimen name="data_reduction_promo_button_text_size">13sp</dimen>
-    <dimen name="data_reduction_promo_illustration_margin_bottom">30dp</dimen>
 
     <!-- The size of the text for tab titles. -->
     <dimen name="compositor_tab_title_text_size">13sp</dimen>
@@ -381,7 +384,6 @@
     <dimen name="payments_section_largest_spacing">32dp</dimen>
     <dimen name="payments_section_checking_spacing">6dp</dimen>
     <dimen name="payments_section_descriptive_item_spacing">40dp</dimen>
-    <dimen name="payments_section_separator_height">1dp</dimen>
     <dimen name="payments_section_logo_width">38dp</dimen>
     <dimen name="payments_section_add_button_height">48dp</dimen>
     <dimen name="payments_ui_max_dialog_width">0dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
index 371d303..2f2b57a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java
@@ -211,6 +211,15 @@
                 int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
                 if (status == DownloadManager.STATUS_SUCCESSFUL) {
                     downloadStatus = DownloadManagerService.DOWNLOAD_STATUS_COMPLETE;
+                    if (mDownloadItem.getDownloadInfo().getFileName() == null) {
+                        DownloadInfo info =
+                                DownloadInfo.Builder
+                                        .fromDownloadInfo(mDownloadItem.getDownloadInfo())
+                                        .setFileName(c.getString(
+                                                c.getColumnIndex(DownloadManager.COLUMN_TITLE)))
+                                        .build();
+                        mDownloadItem.setDownloadInfo(info);
+                    }
                     if (mShowNotifications) {
                         canResolve = DownloadManagerService.isOMADownloadDescription(
                                 mDownloadItem.getDownloadInfo())
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index c1c51ac..d6a0faf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -137,6 +137,15 @@
     // Flag to track if we need to post a task to update download notifications.
     private boolean mIsUIUpdateScheduled;
     private int mAutoResumptionLimit = -1;
+    private DownloadManagerRequestInterceptor mDownloadManagerRequestInterceptor;
+
+    /**
+     * Interface to intercept download request to Android DownloadManager. This is implemented by
+     * tests so that we don't need to actually enqueue a download into the Android DownloadManager.
+     */
+    static interface DownloadManagerRequestInterceptor {
+        void interceptDownloadRequest(DownloadItem item, boolean notifyComplete);
+    }
 
     /**
      * Class representing progress of a download.
@@ -243,10 +252,13 @@
     }
 
     @VisibleForTesting
-    protected DownloadManagerService(Context context,
-            DownloadNotifier downloadNotifier,
-            Handler handler,
-            long updateDelayInMillis) {
+    void setDownloadManagerRequestInterceptor(DownloadManagerRequestInterceptor interceptor) {
+        mDownloadManagerRequestInterceptor = interceptor;
+    }
+
+    @VisibleForTesting
+    protected DownloadManagerService(Context context, DownloadNotifier downloadNotifier,
+            Handler handler, long updateDelayInMillis) {
         mContext = context;
         mSharedPrefs = ContextUtils.getAppSharedPreferences();
         // Clean up unused shared prefs. TODO(qinmin): remove this after M61.
@@ -855,6 +867,10 @@
      */
     public void enqueueDownloadManagerRequest(
             final DownloadItem item, boolean notifyCompleted) {
+        if (mDownloadManagerRequestInterceptor != null) {
+            mDownloadManagerRequestInterceptor.interceptDownloadRequest(item, notifyCompleted);
+            return;
+        }
         EnqueueDownloadRequestTask task = new EnqueueDownloadRequestTask(item);
         task.execute(notifyCompleted);
     }
@@ -891,10 +907,12 @@
             request.setMimeType(info.getMimeType());
             try {
                 if (notifyCompleted) {
-                    // Set downloaded file destination to /sdcard/Download or, should it be
-                    // set to one of several Environment.DIRECTORY* dirs depending on mimetype?
-                    request.setDestinationInExternalPublicDir(
-                            Environment.DIRECTORY_DOWNLOADS, info.getFileName());
+                    if (info.getFileName() != null) {
+                        // Set downloaded file destination to /sdcard/Download or, should it be
+                        // set to one of several Environment.DIRECTORY* dirs depending on mimetype?
+                        request.setDestinationInExternalPublicDir(
+                                Environment.DIRECTORY_DOWNLOADS, info.getFileName());
+                    }
                 } else {
                     File dir = new File(mContext.getExternalFilesDir(null), DOWNLOAD_DIRECTORY);
                     if (dir.mkdir() || dir.isDirectory()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
index 19658cf9..4e6c623 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -171,7 +171,7 @@
             return false;
         }
 
-        new SearchEnginePromoDialog(context, this).show();
+        new SogouPromoDialog(context, this).show();
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/SogouPromoDialog.java
similarity index 72%
rename from chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java
rename to chrome/android/java/src/org/chromium/chrome/browser/locale/SogouPromoDialog.java
index ced1b25e..cddcab9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/SogouPromoDialog.java
@@ -4,10 +4,8 @@
 
 package org.chromium.chrome.browser.locale;
 
-import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.annotation.IntDef;
@@ -23,6 +21,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.preferences.SearchEnginePreference;
+import org.chromium.chrome.browser.widget.PromoDialog;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
@@ -33,8 +32,7 @@
 /**
  * A promotion dialog showing that the default search provider will be set to Sogou.
  */
-public class SearchEnginePromoDialog extends Dialog
-        implements View.OnClickListener, OnDismissListener {
+public class SogouPromoDialog extends PromoDialog {
     // These constants are here to back a uma histogram. Append new constants at the end of this
     // list (do not rearrange) and don't forget to update CHOICE_ENUM_COUNT.
     @Retention(RetentionPolicy.SOURCE)
@@ -52,53 +50,61 @@
         @Override
         public void onClick(View widget) {
             mChoice = CHOICE_SETTINGS;
-            Intent intent = PreferencesLauncher.createIntentForSettingsPage(getContext(),
-                    SearchEnginePreference.class.getName());
+            Intent intent = PreferencesLauncher.createIntentForSettingsPage(
+                    getContext(), SearchEnginePreference.class.getName());
             getContext().startActivity(intent);
             dismiss();
         }
     };
 
-    @UserChoice private int mChoice = CHOICE_BACK_KEY;
+    @UserChoice
+    private int mChoice = CHOICE_BACK_KEY;
 
     /**
      * Creates an instance of the dialog.
      */
-    public SearchEnginePromoDialog(Context context, LocaleManager localeManager) {
-        super(context, R.style.SimpleDialog);
+    public SogouPromoDialog(Context context, LocaleManager localeManager) {
+        super(context);
         mLocaleManager = localeManager;
         setOnDismissListener(this);
         setCanceledOnTouchOutside(false);
     }
 
     @Override
+    protected DialogParams getDialogParams() {
+        PromoDialog.DialogParams params = new PromoDialog.DialogParams();
+        params.drawableResource = R.drawable.search_sogou;
+        params.headerStringResource = R.string.search_with_sogou;
+        params.subheaderStringResource = R.string.sogou_explanation;
+        params.primaryButtonStringResource = R.string.ok;
+        params.secondaryButtonStringResource = R.string.keep_google;
+        return params;
+    }
+
+    @Override
     protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
         // Do not allow this dialog to be reconstructed because it requires native side loaded.
         if (savedInstanceState != null) {
             dismiss();
             return;
         }
-        setContentView(R.layout.search_engine_promo);
 
-        View keepGoogleButton = findViewById(R.id.keep_google_button);
-        View okButton = findViewById(R.id.ok_button);
-        keepGoogleButton.setOnClickListener(this);
-        okButton.setOnClickListener(this);
-
-        TextView textView = (TextView) findViewById(R.id.description);
+        StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
+        TextView textView = (TextView) findViewById(R.id.subheader);
         SpannableString description = SpanApplier.applySpans(
                 getContext().getString(R.string.sogou_explanation),
-                new SpanInfo("<link>", "</link>", mSpan),
-                new SpanInfo("<b>", "</b>", new StyleSpan(android.graphics.Typeface.BOLD)));
+                new SpanInfo("<link>", "</link>", mSpan), new SpanInfo("<b>", "</b>", boldSpan));
         textView.setText(description);
         textView.setMovementMethod(LinkMovementMethod.getInstance());
     }
 
     @Override
     public void onClick(View view) {
-        if (view.getId() == R.id.keep_google_button) {
+        if (view.getId() == R.id.button_secondary) {
             mChoice = CHOICE_KEEP_GOOGLE;
-        } else if (view.getId() == R.id.ok_button) {
+        } else if (view.getId() == R.id.button_primary) {
             mChoice = CHOICE_USE_SOGOU;
         } else {
             assert false : "Not handled click.";
@@ -131,9 +137,11 @@
             default:
                 assert false : "Unexpected choice";
         }
-        ContextUtils.getAppSharedPreferences().edit()
-                .putBoolean(LocaleManager.PREF_PROMO_SHOWN, true).apply();
-        RecordHistogram.recordEnumeratedHistogram("SpecialLocale.PromotionDialog", mChoice,
-                CHOICE_ENUM_COUNT);
+        ContextUtils.getAppSharedPreferences()
+                .edit()
+                .putBoolean(LocaleManager.PREF_PROMO_SHOWN, true)
+                .apply();
+        RecordHistogram.recordEnumeratedHistogram(
+                "SpecialLocale.PromotionDialog", mChoice, CHOICE_ENUM_COUNT);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index 491e92e0..a6e4df9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -1441,9 +1441,9 @@
             Resources resources = parent.getContext().getResources();
             setBackgroundColor(ApiCompatibilityUtils.getColor(
                     resources, R.color.payments_section_separator));
-            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
-                    LayoutParams.MATCH_PARENT,
-                    resources.getDimensionPixelSize(R.dimen.payments_section_separator_height));
+            LinearLayout.LayoutParams params =
+                    new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
+                            resources.getDimensionPixelSize(R.dimen.separator_height));
 
             int margin = resources.getDimensionPixelSize(R.dimen.payments_section_large_spacing);
             ApiCompatibilityUtils.setMarginStart(params, margin);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 3e17036..39363f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -427,8 +427,8 @@
         // requires exploration of how interactions would work when the dialog can be sent back and
         // forth between the peeking and expanded state.
         mFullContainer = new FrameLayout(mContext);
-        mFullContainer.setBackgroundColor(
-                ApiCompatibilityUtils.getColor(mContext.getResources(), R.color.payments_ui_scrim));
+        mFullContainer.setBackgroundColor(ApiCompatibilityUtils.getColor(
+                mContext.getResources(), R.color.modal_dialog_scrim_color));
         FrameLayout.LayoutParams bottomSheetParams = new FrameLayout.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
         bottomSheetParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
@@ -1229,7 +1229,7 @@
             mRequestView.removeOnLayoutChangeListener(this);
 
             Animator scrimFader = ObjectAnimator.ofInt(mFullContainer.getBackground(),
-                    AnimatorProperties.DRAWABLE_ALPHA_PROPERTY, 0, 127);
+                    AnimatorProperties.DRAWABLE_ALPHA_PROPERTY, 0, 255);
             Animator alphaAnimator = ObjectAnimator.ofFloat(mFullContainer, View.ALPHA, 0f, 1f);
 
             AnimatorSet alphaSet = new AnimatorSet();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
index 0c10d0b8..818e58e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java
@@ -5,35 +5,22 @@
 package org.chromium.chrome.browser.preferences.datareduction;
 
 import android.app.Activity;
-import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.widget.PromoDialog;
 import org.chromium.ui.widget.Toast;
 
 /**
  * The promo screen encouraging users to enable Data Saver.
  */
-public class DataReductionPromoScreen extends Dialog implements View.OnClickListener,
-        DialogInterface.OnDismissListener {
+public class DataReductionPromoScreen extends PromoDialog {
     private int mState;
 
-    private static View getContentView(Context context) {
-        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
-                Context.LAYOUT_INFLATER_SERVICE);
-        return inflater.inflate(R.layout.data_reduction_promo_screen, null);
-    }
-
     /**
      * Launch the data reduction promo, if it needs to be displayed.
      */
@@ -58,53 +45,30 @@
      * @param context An Android context.
      */
     public DataReductionPromoScreen(Context context) {
-        super(context, R.style.DataReductionPromoScreenDialog);
-        setContentView(getContentView(context), new LinearLayout.LayoutParams(
-                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
-
-        // Remove the shadow from the enable button.
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            Button enableButton = (Button) findViewById(R.id.enable_button);
-            enableButton.setStateListAnimator(null);
-        }
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // Keep the window full screen otherwise the flip animation will frame-skip.
-        getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-
-        addListenerOnButton();
-
+        super(context);
         mState = DataReductionProxyUma.ACTION_DISMISSED;
     }
 
-    private void addListenerOnButton() {
-        int [] interactiveViewIds = new int[] {
-            R.id.no_thanks_button,
-            R.id.enable_button,
-            R.id.close_button
-        };
-
-        for (int interactiveViewId : interactiveViewIds) {
-            findViewById(interactiveViewId).setOnClickListener(this);
-        }
+    @Override
+    protected DialogParams getDialogParams() {
+        PromoDialog.DialogParams params = new PromoDialog.DialogParams();
+        params.drawableResource = R.drawable.data_reduction_illustration;
+        params.headerStringResource = R.string.data_reduction_promo_title;
+        params.subheaderStringResource = R.string.data_reduction_promo_summary;
+        params.primaryButtonStringResource = R.string.data_reduction_enable_button;
+        params.secondaryButtonStringResource = R.string.no_thanks;
+        return params;
     }
 
-
     @Override
     public void onClick(View v) {
         int id = v.getId();
 
-        if (id == R.id.no_thanks_button) {
-            handleCloseButtonPressed();
-        } else if (id == R.id.enable_button) {
+        if (id == R.id.button_secondary) {
+            dismiss();
+        } else if (id == R.id.button_primary) {
             mState = DataReductionProxyUma.ACTION_ENABLED;
             handleEnableButtonPressed();
-        } else if (id == R.id.close_button) {
-            handleCloseButtonPressed();
         } else {
             assert false : "Unhandled onClick event";
         }
@@ -123,10 +87,6 @@
                 Toast.LENGTH_LONG).show();
     }
 
-    private void handleCloseButtonPressed() {
-        dismiss();
-    }
-
     @Override
     public void dismiss() {
         if (mState < DataReductionProxyUma.ACTION_INDEX_BOUNDARY) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoView.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoView.java
deleted file mode 100644
index 093d455..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoView.java
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.preferences.datareduction;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.LinearLayout;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.widget.PaddedFrameLayout;
-
-/**
- * View that handles orientation changes for the Data Reduction Proxy promo. When the width is
- * greater than the height, switches the promo content view from vertical to horizontal and moves
- * the illustration from the top of the text to the side of the text.
- */
-public class DataReductionPromoView extends PaddedFrameLayout {
-
-    private static final int ILLUSTRATION_HORIZONTAL_PADDING_DP = 24;
-    private static final int FRAME_HEIGHT_MARGIN_DP = 30;
-
-    private View mIllustration;
-    private LinearLayout mPromoContent;
-    private int mMaxChildWidth;
-    private int mMaxChildWidthHorizontal;
-    private int mIllustrationPaddingBottom;
-    private int mIllustrationPaddingSide;
-    private int mFrameHeightMargin;
-
-    public DataReductionPromoView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mMaxChildWidth = getResources()
-                    .getDimensionPixelSize(R.dimen.data_reduction_promo_screen_width);
-        mMaxChildWidthHorizontal = getResources()
-                    .getDimensionPixelSize(R.dimen.data_reduction_promo_screen_width_horizontal);
-        mIllustrationPaddingBottom = getResources()
-                    .getDimensionPixelSize(R.dimen.data_reduction_promo_illustration_margin_bottom);
-        float density = getResources().getDisplayMetrics().density;
-        mIllustrationPaddingSide = (int) (ILLUSTRATION_HORIZONTAL_PADDING_DP * density + 0.5f);
-        mFrameHeightMargin = (int) (FRAME_HEIGHT_MARGIN_DP * density + 0.5f);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mIllustration = findViewById(R.id.data_reduction_illustration);
-        mPromoContent = (LinearLayout) findViewById(R.id.data_reduction_promo_content);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int width = MeasureSpec.getSize(widthMeasureSpec);
-        int height = MeasureSpec.getSize(heightMeasureSpec);
-
-        if (width >= 2 * mIllustration.getWidth() && width > height) {
-            mPromoContent.setOrientation(LinearLayout.HORIZONTAL);
-            setMaxChildWidth(mMaxChildWidthHorizontal);
-            ApiCompatibilityUtils.setPaddingRelative(
-                    mIllustration, 0, 0, mIllustrationPaddingSide, 0);
-        } else {
-            mPromoContent.setOrientation(LinearLayout.VERTICAL);
-            setMaxChildWidth(mMaxChildWidth);
-            mIllustration.setPadding(0, 0, 0, mIllustrationPaddingBottom);
-        }
-
-        setMaxChildHeight(height - mFrameHeightMargin);
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
index 6d46e5f..f7d8f73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/BarcodeDetectionImpl.java
@@ -20,11 +20,10 @@
 import org.chromium.gfx.mojom.PointF;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
-import org.chromium.mojo.system.SharedBufferHandle;
-import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.services.service_manager.InterfaceFactory;
 import org.chromium.shape_detection.mojom.BarcodeDetection;
 import org.chromium.shape_detection.mojom.BarcodeDetectionResult;
+import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -43,8 +42,7 @@
     }
 
     @Override
-    public void detect(
-            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
+    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
         if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices(
                     mContext, new UserRecoverableErrorHandler.Silent())) {
             Log.e(TAG, "Google Play Services not available");
@@ -61,9 +59,21 @@
             return;
         }
 
+        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
+        // https://crbug.com/684921.
+        if (bitmapData.colorType != ColorType.RGBA_8888
+                && bitmapData.colorType != ColorType.BGRA_8888) {
+            Log.e(TAG, "Unsupported bitmap pixel format");
+            callback.call(new BarcodeDetectionResult[0]);
+            return;
+        }
+
+        int width = bitmapData.width;
+        int height = bitmapData.height;
         final long numPixels = (long) width * height;
         // TODO(mcasas): https://crbug.com/670028 homogeneize overflow checking.
-        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
+        if (bitmapData.pixelData == null || width <= 0 || height <= 0
+                || numPixels > (Long.MAX_VALUE / 4)) {
             callback.call(new BarcodeDetectionResult[0]);
             return;
         }
@@ -71,7 +81,7 @@
         // Mapping |frameData| will fail if the intended mapped size is larger
         // than its actual capacity, which is limited by the appropriate
         // mojo::edk::Configuration entry.
-        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
+        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
         if (imageBuffer.capacity() <= 0) {
             callback.call(new BarcodeDetectionResult[0]);
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
index 2f4fab0..6af95153 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/shapedetection/TextDetectionImpl.java
@@ -18,11 +18,10 @@
 import org.chromium.chrome.browser.externalauth.UserRecoverableErrorHandler;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
-import org.chromium.mojo.system.SharedBufferHandle;
-import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.services.service_manager.InterfaceFactory;
 import org.chromium.shape_detection.mojom.TextDetection;
 import org.chromium.shape_detection.mojom.TextDetectionResult;
+import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -41,8 +40,7 @@
     }
 
     @Override
-    public void detect(
-            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
+    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
         if (!ExternalAuthUtils.getInstance().canUseGooglePlayServices(
                     mContext, new UserRecoverableErrorHandler.Silent())) {
             Log.e(TAG, "Google Play Services not available");
@@ -59,9 +57,21 @@
             return;
         }
 
+        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
+        // https://crbug.com/684921.
+        if (bitmapData.colorType != ColorType.RGBA_8888
+                && bitmapData.colorType != ColorType.BGRA_8888) {
+            Log.e(TAG, "Unsupported bitmap pixel format");
+            callback.call(new TextDetectionResult[0]);
+            return;
+        }
+
+        int width = bitmapData.width;
+        int height = bitmapData.height;
         final long numPixels = (long) width * height;
         // TODO(xianglu): https://crbug.com/670028 homogeneize overflow checking.
-        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
+        if (bitmapData.pixelData == null || width <= 0 || height <= 0
+                || numPixels > (Long.MAX_VALUE / 4)) {
             callback.call(new TextDetectionResult[0]);
             return;
         }
@@ -69,7 +79,7 @@
         // Mapping |frameData| will fail if the intended mapped size is larger
         // than its actual capacity, which is limited by the appropriate
         // mojo::edk::Configuration entry.
-        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
+        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
         if (imageBuffer.capacity() <= 0) {
             callback.call(new TextDetectionResult[0]);
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
index ab7b35181..653d42a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabUma.java
@@ -94,10 +94,10 @@
         mTabCreationState = creationState;
 
         mLastTabStateChangeMillis = System.currentTimeMillis();
-        if (mTabCreationState == TabCreationState.LIVE_IN_FOREGROUND
-                || mTabCreationState == TabCreationState.FROZEN_ON_RESTORE) {
+        if (mTabCreationState == TabCreationState.LIVE_IN_FOREGROUND) {
             updateTabState(TAB_STATE_ACTIVE);
         } else if (mTabCreationState == TabCreationState.LIVE_IN_BACKGROUND
+                || mTabCreationState == TabCreationState.FROZEN_ON_RESTORE
                 || mTabCreationState == TabCreationState.FROZEN_FOR_LAZY_LOAD) {
             updateTabState(TAB_STATE_INACTIVE);
         } else if (mTabCreationState == TabCreationState.FROZEN_ON_RESTORE_FAILED) {
@@ -196,6 +196,9 @@
      * @param newState New state of the tab.
      */
     void updateTabState(int newState) {
+        if (mLastTabState == newState) {
+            return;
+        }
         long now = System.currentTimeMillis();
         recordTabStateTransition(mLastTabState, newState, now - mLastTabStateChangeMillis);
         mLastTabStateChangeMillis = now;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
new file mode 100644
index 0000000..f1abf4f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialog.java
@@ -0,0 +1,79 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.widget;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.R;
+
+/**
+ * Generic builder for promo dialogs.
+ */
+public abstract class PromoDialog
+        extends Dialog implements View.OnClickListener, DialogInterface.OnDismissListener {
+    /** Parameters that can be used to create a new PromoDialog. */
+    public static class DialogParams {
+        /** Optional: Resource ID of the Drawable to use for the promo illustration. */
+        public int drawableResource;
+
+        /** Resource ID of the String to show as the promo title. */
+        public int headerStringResource;
+
+        /** Optional: Resource ID of the String to show as descriptive text. */
+        public int subheaderStringResource;
+
+        /** Optional: Resource ID of the String to show on the primary/ok button. */
+        public int primaryButtonStringResource;
+
+        /** Optional: Resource ID of the String to show on the secondary/cancel button. */
+        public int secondaryButtonStringResource;
+    }
+
+    private static final int[] CLICKABLE_BUTTON_IDS = {R.id.button_primary, R.id.button_secondary};
+
+    private final FrameLayout mScrimView;
+    private final PromoDialogLayout mDialogLayout;
+
+    protected PromoDialog(Context context) {
+        super(context, R.style.PromoDialog);
+
+        mScrimView = new FrameLayout(context);
+        mScrimView.setBackgroundColor(ApiCompatibilityUtils.getColor(
+                context.getResources(), R.color.modal_dialog_scrim_color));
+        LayoutInflater.from(context).inflate(R.layout.promo_dialog_layout, mScrimView, true);
+
+        mDialogLayout = (PromoDialogLayout) mScrimView.findViewById(R.id.promo_dialog_layout);
+        mDialogLayout.initialize(getDialogParams());
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(mScrimView);
+
+        // Force the window to allow the dialog contents be as wide as necessary.
+        getWindow().setLayout(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+        // Connect all the buttons to this class.
+        for (int interactiveViewId : CLICKABLE_BUTTON_IDS) {
+            View view = findViewById(interactiveViewId);
+            if (view != null) view.setOnClickListener(this);
+        }
+    }
+
+    @Override
+    public void onClick(View view) {}
+
+    /** Returns a set of {@link DialogParams} that define what is shown in the promo dialog. */
+    protected abstract DialogParams getDialogParams();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java
new file mode 100644
index 0000000..41243fb1
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java
@@ -0,0 +1,102 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.widget.PromoDialog.DialogParams;
+
+/**
+ * View that handles orientation changes for the promo dialogs. When the width is greater than the
+ * height, the promo content switches from vertical to horizontal and moves the illustration from
+ * the top of the text to the side of the text.
+ */
+public final class PromoDialogLayout extends BoundedLinearLayout {
+    /** Content in the dialog that can be scrolled. */
+    private LinearLayout mScrollableContent;
+
+    /** Illustration that teases the thing being promoted. */
+    private ImageView mIllustrationView;
+
+    /** View containing the header of the promo. */
+    private TextView mHeaderView;
+
+    /** View containing text explaining the promo. */
+    private TextView mSubheaderView;
+
+    /** Paramters used to build the promo. */
+    private DialogParams mParams;
+
+    public PromoDialogLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        mScrollableContent = (LinearLayout) findViewById(R.id.promo_content);
+        mIllustrationView = (ImageView) findViewById(R.id.illustration);
+        mHeaderView = (TextView) findViewById(R.id.header);
+        mSubheaderView = (TextView) findViewById(R.id.subheader);
+
+        super.onFinishInflate();
+    }
+
+    /** Initializes the dialog contents using the given params.  Should only be called once. */
+    void initialize(DialogParams params) {
+        assert mParams == null && params != null;
+        mParams = params;
+
+        if (mParams.drawableResource == 0) {
+            ((ViewGroup) mIllustrationView.getParent()).removeView(mIllustrationView);
+        } else {
+            mIllustrationView.setImageResource(mParams.drawableResource);
+        }
+
+        // TODO(dfalcantara): Lock the title in place, if requested by the DialogParams.
+        mHeaderView.setText(mParams.headerStringResource);
+
+        if (mParams.subheaderStringResource == 0) {
+            ((ViewGroup) mSubheaderView.getParent()).removeView(mSubheaderView);
+        } else {
+            mSubheaderView.setText(mParams.subheaderStringResource);
+        }
+
+        DualControlLayout buttonBar = (DualControlLayout) findViewById(R.id.button_bar);
+        if (mParams.primaryButtonStringResource != 0) {
+            String primaryString = getResources().getString(mParams.primaryButtonStringResource);
+            buttonBar.addView(DualControlLayout.createButtonForLayout(
+                    getContext(), true, primaryString, null));
+
+            if (mParams.secondaryButtonStringResource != 0) {
+                String secondaryString =
+                        getResources().getString(mParams.secondaryButtonStringResource);
+                buttonBar.addView(DualControlLayout.createButtonForLayout(
+                        getContext(), false, secondaryString, null));
+            }
+        } else {
+            assert mParams.secondaryButtonStringResource == 0;
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int availableWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int availableHeight = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (availableWidth > availableHeight * 1.5) {
+            mScrollableContent.setOrientation(LinearLayout.HORIZONTAL);
+        } else {
+            mScrollableContent.setOrientation(LinearLayout.VERTICAL);
+        }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+}
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index b4a9e21..53ea8bba 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -487,7 +487,7 @@
   "java/src/org/chromium/chrome/browser/invalidation/InvalidationServiceFactory.java",
   "java/src/org/chromium/chrome/browser/invalidation/UniqueIdInvalidationClientNameGenerator.java",
   "java/src/org/chromium/chrome/browser/locale/LocaleManager.java",
-  "java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java",
+  "java/src/org/chromium/chrome/browser/locale/SogouPromoDialog.java",
   "java/src/org/chromium/chrome/browser/locale/SpecialLocaleHandler.java",
   "java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java",
   "java/src/org/chromium/chrome/browser/media/VideoPersister.java",
@@ -836,7 +836,6 @@
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPreferences.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoScreen.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoUtils.java",
-  "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionPromoView.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionProxyUma.java",
   "java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java",
   "java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java",
@@ -1154,6 +1153,8 @@
   "java/src/org/chromium/chrome/browser/widget/ProgressAnimationFastStart.java",
   "java/src/org/chromium/chrome/browser/widget/ProgressAnimationLinear.java",
   "java/src/org/chromium/chrome/browser/widget/ProgressAnimationSmooth.java",
+  "java/src/org/chromium/chrome/browser/widget/PromoDialog.java",
+  "java/src/org/chromium/chrome/browser/widget/PromoDialogLayout.java",
   "java/src/org/chromium/chrome/browser/widget/RadioButtonWithDescription.java",
   "java/src/org/chromium/chrome/browser/widget/RoundedIconGenerator.java",
   "java/src/org/chromium/chrome/browser/widget/TextBubble.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
index 3a368bf..7883000 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -6,13 +6,16 @@
 
 import android.os.Environment;
 import android.support.test.filters.MediumTest;
+import android.util.Pair;
 import android.view.View;
 
 import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.FlakyTest;
 import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
@@ -23,10 +26,14 @@
 import org.chromium.chrome.test.util.InfoBarUtil;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.browser.test.util.TouchCommon;
 import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.net.test.util.TestWebServer;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.Callable;
 
 /**
@@ -53,6 +60,17 @@
         FILENAME_GZIP
     };
 
+    static class DownloadManagerRequestInterceptorForTest
+            implements DownloadManagerService.DownloadManagerRequestInterceptor {
+        public DownloadItem mDownloadItem;
+
+        @Override
+        public void interceptDownloadRequest(DownloadItem item, boolean notifyComplete) {
+            mDownloadItem = item;
+            assertTrue(notifyComplete);
+        }
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -374,6 +392,43 @@
         assertTrue(hasDownload(FILENAME_WALLPAPER, null));
     }
 
+    @MediumTest
+    @Feature({"Navigation"})
+    public void testOMADownloadInterception() throws Exception {
+        TestWebServer webServer = TestWebServer.start();
+        try {
+            final DownloadManagerRequestInterceptorForTest interceptor =
+                    new DownloadManagerRequestInterceptorForTest();
+            ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+                @Override
+                public void run() {
+                    DownloadManagerService
+                            .getDownloadManagerService(getInstrumentation().getContext())
+                            .setDownloadManagerRequestInterceptor(interceptor);
+                }
+            });
+            List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
+            headers.add(Pair.create("Content-Type", "application/vnd.oma.drm.message"));
+            final String url = webServer.setResponse("/test.dm", "testdata", headers);
+            loadUrl(UrlUtils.encodeHtmlDataUri("<script>"
+                    + "  function download() {"
+                    + "    window.open( '" + url + "')"
+                    + "  }"
+                    + "</script>"
+                    + "<body id='body' onclick='download()'></body>"));
+            DOMUtils.clickNode(getActivity().getCurrentContentViewCore(), "body");
+            CriteriaHelper.pollUiThread(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return interceptor.mDownloadItem != null
+                            && url.equals(interceptor.mDownloadItem.getDownloadInfo().getUrl());
+                }
+            });
+        } finally {
+            webServer.shutdown();
+        }
+    }
+
     private void waitForFocus() {
         View currentView = getActivity().getActivityTab().getView();
         if (!currentView.hasFocus()) {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0cede831..8f8689b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -15044,6 +15044,15 @@
     <message name="IDS_FLAGS_MOJO_LOADING_DESCRIPTION" desc="Description for the flag to enable Mojo IPC for resource loading" translateable="false">
       Use Mojo IPC instead of traditional Chrome IPC for resource loading.
     </message>
+
+    <if expr="is_android">
+      <message name="IDS_FLAGS_USE_NEW_DOODLE_API_NAME" desc="Name for the flag to enable the new Doodle API" translateable="false">
+        Use new Doodle API
+      </message>
+      <message name="IDS_FLAGS_USE_NEW_DOODLE_API_DESCRIPTION" desc="Description for the flag to enable the new Doodle API" translateable="false">
+        Enables the new API to fetch Doodles for the NTP.
+      </message>
+    </if>
   </messages>
  </release>
 </grit>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 1410962..72549bd 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2408,6 +2408,12 @@
      MULTI_VALUE_TYPE(kForceTabletModeChoices)},
 #endif  // OS_CHROMEOS
 
+#if defined(OS_ANDROID)
+    {"use-new-doodle-api", IDS_FLAGS_USE_NEW_DOODLE_API_NAME,
+     IDS_FLAGS_USE_NEW_DOODLE_API_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kUseNewDoodleApi)},
+#endif  // OS_ANDROID
+
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index e313b4f7..4d6b2a3 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -180,6 +180,9 @@
 const base::Feature kUploadCrashReportsUsingJobScheduler{
     "UploadCrashReportsUsingJobScheduler", base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kUseNewDoodleApi{"UseNewDoodleApi",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kUserMediaScreenCapturing{
     "UserMediaScreenCapturing", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 54aa8161..3651662e 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -41,6 +41,7 @@
 extern const base::Feature kTabsInCBD;
 extern const base::Feature kTabReparenting;
 extern const base::Feature kUploadCrashReportsUsingJobScheduler;
+extern const base::Feature kUseNewDoodleApi;
 extern const base::Feature kUserMediaScreenCapturing;
 extern const base::Feature kWebPaymentsModifiers;
 extern const base::Feature kWebPaymentsSingleAppUiSkip;
diff --git a/chrome/browser/android/logo_bridge.cc b/chrome/browser/android/logo_bridge.cc
index 26c8b1a..cd6284ac 100644
--- a/chrome/browser/android/logo_bridge.cc
+++ b/chrome/browser/android/logo_bridge.cc
@@ -14,6 +14,7 @@
 #include "base/bind.h"
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
+#include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/android/logo_service.h"
 #include "chrome/browser/doodle/doodle_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -39,9 +40,6 @@
 
 namespace {
 
-const base::Feature kUseNewDoodleApi{"UseNewDoodleApi",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
-
 ScopedJavaLocalRef<jobject> MakeJavaLogo(JNIEnv* env,
                                          const SkBitmap* bitmap,
                                          const GURL& on_click_url,
@@ -198,7 +196,7 @@
   Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
   DCHECK(profile);
 
-  if (base::FeatureList::IsEnabled(kUseNewDoodleApi)) {
+  if (base::FeatureList::IsEnabled(chrome::android::kUseNewDoodleApi)) {
     doodle_service_ = DoodleServiceFactory::GetForProfile(profile);
     image_fetcher_ = base::MakeUnique<image_fetcher::ImageFetcherImpl>(
         base::MakeUnique<suggestions::ImageDecoderImpl>(),
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 19d6551c..736341f 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -263,6 +263,8 @@
         <include name="IDR_MD_BOOKMARKS_APP_JS" file="resources\md_bookmarks\app.js" type="BINDATA" />
         <include name="IDR_MD_BOOKMARKS_BOOKMARKS_HTML" file="resources\md_bookmarks\bookmarks.html" type="BINDATA" />
         <include name="IDR_MD_BOOKMARKS_BOOKMARKS_STORE_JS" file="resources\md_bookmarks\bookmarks_store.js" type="BINDATA" />
+        <include name="IDR_MD_BOOKMARKS_EDIT_DIALOG_HTML" file="resources\md_bookmarks\edit_dialog.html" type="BINDATA" />
+        <include name="IDR_MD_BOOKMARKS_EDIT_DIALOG_JS" file="resources\md_bookmarks\edit_dialog.js" type="BINDATA" />
         <include name="IDR_MD_BOOKMARKS_FOLDER_NODE_HTML" file="resources\md_bookmarks\folder_node.html" type="BINDATA" />
         <include name="IDR_MD_BOOKMARKS_FOLDER_NODE_JS" file="resources\md_bookmarks\folder_node.js" type="BINDATA" />
         <include name="IDR_MD_BOOKMARKS_ICONS_HTML" file="resources\md_bookmarks\icons.html" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 528148a0..938c3015 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -2306,7 +2306,7 @@
         callback) {
   DCHECK(web_contents);
   if (resource_type != content::RESOURCE_TYPE_MAIN_FRAME) {
-    // A sub-resource has a certificate error.  The user doesn't really
+    // A sub-resource has a certificate error. The user doesn't really
     // have a context for making the right decision, so block the
     // request hard, without an info bar to allow showing the insecure
     // content.
diff --git a/chrome/browser/extensions/process_manager_browsertest.cc b/chrome/browser/extensions/process_manager_browsertest.cc
index 5453150..0625ae20 100644
--- a/chrome/browser/extensions/process_manager_browsertest.cc
+++ b/chrome/browser/extensions/process_manager_browsertest.cc
@@ -44,6 +44,11 @@
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
+#if defined(CHROMEOS)
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chromeos/chromeos_switches.h"
+#endif
+
 namespace extensions {
 
 namespace {
@@ -123,8 +128,6 @@
   EXPECT_EQ("foo", result);
 }
 
-}  // namespace
-
 // Takes a snapshot of all frames upon construction. When Wait() is called, a
 // MessageLoop is created and Quit when all previously recorded frames are
 // either present in the tab, or deleted. If a navigation happens between the
@@ -270,6 +273,50 @@
   std::vector<std::unique_ptr<TestExtensionDir>> temp_dirs_;
 };
 
+class DefaultProfileExtensionBrowserTest : public ExtensionBrowserTest {
+ protected:
+  DefaultProfileExtensionBrowserTest() {
+#if defined(OS_CHROMEOS)
+    // We want signin profile on ChromeOS, not logged in user profile.
+    set_chromeos_user_ = false;
+#endif
+  }
+
+ private:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ExtensionBrowserTest::SetUpCommandLine(command_line);
+#if defined(OS_CHROMEOS)
+    command_line->AppendSwitch(chromeos::switches::kLoginManager);
+    command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+#endif
+  }
+};
+
+}  // namespace
+
+// By default, no extension hosts should be present in the profile;
+// they should only be present if non-component extensions are loaded
+// or if the user takes some action to trigger a component extension.
+// TODO(achuith): Expand this testing to include more in-depth
+// testing for the signin profile, where we explicitly disallow all
+// extension hosts unless it's the off-the-record profile.
+IN_PROC_BROWSER_TEST_F(DefaultProfileExtensionBrowserTest, NoExtensionHosts) {
+  // Explicitly get the original and off-the-record-profiles, since on CrOS,
+  // the signin profile (profile()) is the off-the-record version.
+  Profile* original = profile()->GetOriginalProfile();
+  Profile* otr = original->GetOffTheRecordProfile();
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(profile(), otr);
+  EXPECT_TRUE(chromeos::ProfileHelper::IsSigninProfile(original));
+#endif
+
+  ProcessManager* pm = ProcessManager::Get(original);
+  EXPECT_EQ(0u, pm->background_hosts().size());
+
+  pm = ProcessManager::Get(otr);
+  EXPECT_EQ(0u, pm->background_hosts().size());
+}
+
 // Test that basic extension loading creates the appropriate ExtensionHosts
 // and background pages.
 IN_PROC_BROWSER_TEST_F(ProcessManagerBrowserTest,
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 0ddcbdb..ecc07c0 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -562,14 +562,21 @@
                                     content::RESOURCE_TYPE_MAIN_FRAME,
                                     throttles);
 #if defined(OS_ANDROID)
-    throttles->push_back(
-        base::MakeUnique<InterceptDownloadResourceThrottle>(
-            request, info->GetWebContentsGetterForRequest()));
     // On Android, forward text/html downloads to OfflinePages backend.
     throttles->push_back(
         base::MakeUnique<offline_pages::downloads::ResourceThrottle>(request));
 #endif
   }
+
+#if defined(OS_ANDROID)
+  // Add the InterceptDownloadResourceThrottle after calling
+  // AppendStandardResourceThrottles so the download will not bypass
+  // safebrowsing checks.
+  if (is_content_initiated) {
+    throttles->push_back(base::MakeUnique<InterceptDownloadResourceThrottle>(
+        request, info->GetWebContentsGetterForRequest()));
+  }
+#endif
 }
 
 ResourceDispatcherHostLoginDelegate*
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
index f281ac36..b2e1a70 100644
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
@@ -46,6 +46,16 @@
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
     },
     {
+      'target_name': 'edit_dialog',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(EXTERNS_GYP):chrome_extensions',
+        'types',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi']
+    },
+    {
       'target_name': 'folder_node',
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
       'dependencies': [
@@ -72,6 +82,7 @@
         '<(EXTERNS_GYP):bookmark_manager_private',
         '<(EXTERNS_GYP):chrome_extensions',
         'actions',
+        'edit_dialog',
         'item',
         'store_client',
       ],
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.html b/chrome/browser/resources/md_bookmarks/edit_dialog.html
new file mode 100644
index 0000000..7361e15
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.html
@@ -0,0 +1,37 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
+<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+
+<dom-module id="bookmarks-edit-dialog">
+  <template>
+    <style include="cr-shared-style"></style>
+    <dialog is="cr-dialog" id="dialog">
+      <div class="title">[[getDialogTitle_(isFolder_)]]</div>
+      <div class="body">
+        <paper-input always-float-label id="name"
+            label="$i18n{editDialogNameInput}"
+            value="{{titleValue_}}"
+            autofocus>
+        </paper-input>
+        <paper-input always-float-label id="url"
+            label="$i18n{editDialogUrlInput}"
+            value="{{urlValue_}}"
+            hidden$="[[isFolder_]]">
+        </paper-input>
+      </div>
+      <div class="button-container">
+        <paper-button class="cancel-button" on-tap="onCancelButtonTap_">
+          $i18n{cancelEdit}
+        </paper-button>
+        <paper-button id="saveButton" class="action-button"
+            on-tap="onSaveButtonTap_">
+          $i18n{saveEdit}
+        </paper-button>
+      </div>
+    </dialog>
+  </template>
+  <script src="chrome://bookmarks/edit_dialog.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/md_bookmarks/edit_dialog.js b/chrome/browser/resources/md_bookmarks/edit_dialog.js
new file mode 100644
index 0000000..c2a4873c
--- /dev/null
+++ b/chrome/browser/resources/md_bookmarks/edit_dialog.js
@@ -0,0 +1,60 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Polymer({
+  is: 'bookmarks-edit-dialog',
+
+  properties: {
+    /** @private {BookmarkNode} */
+    editItem_: Object,
+
+    /** @private */
+    isFolder_: Boolean,
+
+    /** @private */
+    titleValue_: String,
+
+    /** @private */
+    urlValue_: String,
+  },
+
+  /** @param {BookmarkNode} editItem */
+  showEditDialog: function(editItem) {
+    this.editItem_ = editItem;
+    this.isFolder_ = !editItem.url;
+
+    this.titleValue_ = editItem.title;
+    if (!this.isFolder_)
+      this.urlValue_ = assert(editItem.url);
+
+    this.$.dialog.showModal();
+  },
+
+  /**
+   * @param {boolean} isFolder
+   * @return {string}
+   * @private
+   */
+  getDialogTitle_: function(isFolder) {
+    return loadTimeData.getString(
+        isFolder ? 'renameFolderTitle' : 'editBookmarkTitle');
+  },
+
+  /** @private */
+  onSaveButtonTap_: function() {
+    // TODO(tsergeant): Save changes when enter is pressed.
+    // TODO(tsergeant): Verify values.
+    var edit = {'title': this.titleValue_};
+    if (!this.isFolder_)
+      edit['url'] = this.urlValue_;
+
+    chrome.bookmarks.update(this.editItem_.id, edit);
+    this.$.dialog.close();
+  },
+
+  /** @private */
+  onCancelButtonTap_: function() {
+    this.$.dialog.cancel();
+  },
+});
diff --git a/chrome/browser/resources/md_bookmarks/list.html b/chrome/browser/resources/md_bookmarks/list.html
index d36a1f4..05bb411 100644
--- a/chrome/browser/resources/md_bookmarks/list.html
+++ b/chrome/browser/resources/md_bookmarks/list.html
@@ -1,11 +1,9 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html">
+<link rel="import" href="chrome://bookmarks/edit_dialog.html">
 <link rel="import" href="chrome://bookmarks/item.html">
 <link rel="import" href="chrome://bookmarks/shared_style.html">
 <link rel="import" href="chrome://bookmarks/store_client.html">
@@ -13,7 +11,7 @@
 
 <dom-module id="bookmarks-list">
   <template>
-    <style include="shared-style cr-shared-style">
+    <style include="shared-style">
       :host {
         overflow-y: auto;
         padding: 20px 32px 20px calc(32px - var(--splitter-width));
@@ -49,29 +47,6 @@
          $i18n{menuDelete}
       </button>
     </dialog>
-    <dialog is="cr-dialog" id="editBookmark">
-      <div class="title">[[getEditorTitle_(menuItem_)]]</div>
-      <div class="body">
-        <paper-input always-float-label id="name"
-            label="$i18n{editDialogNameInput}"
-            value="{{menuItem_.title}}">
-        </paper-input>
-        <paper-input always-float-label id="url"
-            label="$i18n{editDialogUrlInput}"
-            value="{{menuItem_.url}}"
-            hidden$="[[!menuItem_.url]]">
-        </paper-input>
-      </div>
-      <div class="button-container">
-        <paper-button class="cancel-button" on-tap="onCancelEditTap_">
-          $i18n{cancelEdit}
-        </paper-button>
-        <paper-button class="action-button" on-tap="onSaveEditTap_"
-            id='saveButton'>
-          $i18n{saveEdit}
-        </paper-button>
-      </div>
-    </dialog>
     <div id="bookmarksCard" hidden$="[[isEmptyList_(displayedList_.length)]]">
       <template is="dom-repeat" items="[[displayedList_]]" as="id">
         <bookmarks-item item-id="[[id]]">
@@ -82,6 +57,9 @@
         hidden$="[[!isEmptyList_(displayedList_.length)]]">
       [[emptyListMessage_(searchTerm_)]]
     </div>
+    <template is="cr-lazy-render" id="editDialog">
+      <bookmarks-edit-dialog></bookmarks-edit-dialog>
+    </template>
   </template>
   <script src="chrome://bookmarks/list.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/md_bookmarks/list.js b/chrome/browser/resources/md_bookmarks/list.js
index 296620b..0edfcbb 100644
--- a/chrome/browser/resources/md_bookmarks/list.js
+++ b/chrome/browser/resources/md_bookmarks/list.js
@@ -55,7 +55,8 @@
   /** @private */
   onEditTap_: function() {
     this.closeDropdownMenu_();
-    this.$.editBookmark.showModal();
+    /** @type {BookmarksEditDialogElement} */ (this.$.editDialog.get())
+        .showEditDialog(this.menuItem_);
   },
 
   /** @private */
@@ -82,21 +83,6 @@
   },
 
   /** @private */
-  onSaveEditTap_: function() {
-    var edit = {'title': this.menuItem_.title};
-    if (this.menuItem_.url)
-      edit['url'] = this.menuItem_.url;
-
-    chrome.bookmarks.update(this.menuItem_.id, edit);
-    this.$.editBookmark.close();
-  },
-
-  /** @private */
-  onCancelEditTap_: function() {
-    this.$.editBookmark.cancel();
-  },
-
-  /** @private */
   closeDropdownMenu_: function() {
     var menu = /** @type {!CrActionMenuElement} */ (
         this.$.dropdown);
@@ -110,12 +96,6 @@
   },
 
   /** @private */
-  getEditorTitle_: function() {
-    var title = this.menuItem_.url ? 'editBookmarkTitle' : 'renameFolderTitle';
-    return loadTimeData.getString(title);
-  },
-
-  /** @private */
   emptyListMessage_: function() {
     var emptyListMessage = this.searchTerm_ ? 'noSearchResults' : 'emptyList';
     return loadTimeData.getString(emptyListMessage);
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
index 5be1073c..9c65ca31 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_browsertest.cc
@@ -346,27 +346,25 @@
 }
 
 // Verify that when you unblock popup, the popup shows in history and omnibox.
-// TODO(crbug.com/663333) Flaky on Linux.
-#if defined(OS_LINUX)
-#define MAYBE_UnblockedPopupShowsInHistoryAndOmnibox \
-  DISABLED_UnblockedPopupShowsInHistoryAndOmnibox
-#else
-#define MAYBE_UnblockedPopupShowsInHistoryAndOmnibox \
-  UnblockedPopupShowsInHistoryAndOmnibox
-#endif
 IN_PROC_BROWSER_TEST_F(PopupBlockerBrowserTest,
-                       MAYBE_UnblockedPopupShowsInHistoryAndOmnibox) {
+                       UnblockedPopupShowsInHistoryAndOmnibox) {
   base::CommandLine::ForCurrentProcess()->AppendSwitch(
       switches::kDisablePopupBlocking);
   GURL url(embedded_test_server()->GetURL(
       "/popup_blocker/popup-blocked-to-post-blank.html"));
   NavigateAndCheckPopupShown(url, ExpectTab);
 
+  // Make sure the navigation in the new tab actually finished.
+  WebContents* web_contents = browser()->tab_strip_model()->GetWebContentsAt(1);
+  base::string16 expected_title(base::ASCIIToUTF16("Popup Success!"));
+  content::TitleWatcher title_watcher(web_contents, expected_title);
+  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+  WaitForHistoryBackendToRun(browser()->profile());
+
   std::string search_string =
       "data:text/html,<title>Popup Success!</title>you should not see this "
       "message if popup blocker is enabled";
 
-  WaitForHistoryBackendToRun(browser()->profile());
   ui_test_utils::HistoryEnumerator history(browser()->profile());
   std::vector<GURL>& history_urls = history.urls();
   ASSERT_EQ(2u, history_urls.size());
diff --git a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
index 9d6836d2..e370ea20 100644
--- a/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
+++ b/chrome/browser/ui/webui/md_bookmarks/md_bookmarks_ui.cc
@@ -75,6 +75,9 @@
   source->AddResourcePath("app.js", IDR_MD_BOOKMARKS_APP_JS);
   source->AddResourcePath("bookmarks_store.js",
                           IDR_MD_BOOKMARKS_BOOKMARKS_STORE_JS);
+  source->AddResourcePath("edit_dialog.html",
+                          IDR_MD_BOOKMARKS_EDIT_DIALOG_HTML);
+  source->AddResourcePath("edit_dialog.js", IDR_MD_BOOKMARKS_EDIT_DIALOG_JS);
   source->AddResourcePath("folder_node.html",
                           IDR_MD_BOOKMARKS_FOLDER_NODE_HTML);
   source->AddResourcePath("folder_node.js",
diff --git a/chrome/install_static/chromium_install_modes.cc b/chrome/install_static/chromium_install_modes.cc
index 997aa4b..8e6068c 100644
--- a/chrome/install_static/chromium_install_modes.cc
+++ b/chrome/install_static/chromium_install_modes.cc
@@ -33,7 +33,10 @@
         L"",  // No logo suffix for the primary install mode.
         L"",  // Empty app_guid since no integraion with Google Update.
         L"Chromium",  // A distinct base_app_id.
-        L"",  // Empty default channel name as above.
+        L"ChromiumHTM",  // ProgID prefix.
+        L"Chromium HTML Document",  // ProgID description.
+        L"{7D2B3E1D-D096-4594-9D8F-A6667F12E0AC}",  // Active Setup GUID.
+        L"",  // Empty default channel name since no update integration.
         ChannelStrategy::UNSUPPORTED,
         true,  // Supports system-level installs.
         true,  // Supported multi-install.
diff --git a/chrome/install_static/google_chrome_install_modes.cc b/chrome/install_static/google_chrome_install_modes.cc
index a4906845..b5c3ce37 100644
--- a/chrome/install_static/google_chrome_install_modes.cc
+++ b/chrome/install_static/google_chrome_install_modes.cc
@@ -33,6 +33,9 @@
         L"",  // No logo suffix for the primary install mode.
         L"{8A69D345-D564-463c-AFF1-A69D9E530F96}",
         L"Chrome",  // A distinct base_app_id.
+        L"ChromeHTML",  // ProgID prefix.
+        L"Chrome HTML Document",  // ProgID description.
+        L"{8A69D345-D564-463c-AFF1-A69D9E530F96}",  // Active Setup GUID.
         L"",  // The empty string means "stable".
         ChannelStrategy::ADDITIONAL_PARAMETERS,
         true,  // Supports system-level installs.
@@ -48,6 +51,9 @@
         L"Canary",
         L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}",
         L"ChromeCanary",  // A distinct base_app_id.
+        L"ChromeSSHTM",  // ProgID prefix.
+        L"Chrome Canary HTML Document",  // ProgID description.
+        L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}",  // Active Setup GUID.
         L"canary",
         ChannelStrategy::FIXED,
         false,  // Does not support system-level installs.
diff --git a/chrome/install_static/install_constants.h b/chrome/install_static/install_constants.h
index b5e4a86..504fd57 100644
--- a/chrome/install_static/install_constants.h
+++ b/chrome/install_static/install_constants.h
@@ -68,6 +68,20 @@
   // directly.
   const wchar_t* base_app_id;
 
+  // The prefix for the browser's ProgID. This prefix may be no more than 11
+  // characters long; see ShellUtil::GetBrowserProgId and
+  // https://msdn.microsoft.com/library/windows/desktop/dd542719.aspx.
+  const wchar_t* prog_id_prefix;
+
+  // A human-readable description of the browser, used when registering with
+  // Windows.
+  const wchar_t* prog_id_description;
+
+  // The GUID to be used when registering this install mode for Active Setup.
+  // Active Setup is used to perform certain operations in a user's context for
+  // system-level installs.
+  const wchar_t* active_setup_guid;
+
   // The default name for this mode's update channel.
   const wchar_t* default_channel_name;
 
diff --git a/chrome/install_static/install_modes_unittest.cc b/chrome/install_static/install_modes_unittest.cc
index e4593633..3e0f01b 100644
--- a/chrome/install_static/install_modes_unittest.cc
+++ b/chrome/install_static/install_modes_unittest.cc
@@ -4,17 +4,40 @@
 
 #include "chrome/install_static/install_modes.h"
 
+#include <windows.h>
+
+#include <ctype.h>
+
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::Eq;
 using ::testing::Gt;
+using ::testing::Le;
 using ::testing::Ne;
+using ::testing::Not;
+using ::testing::ResultOf;
 using ::testing::StrEq;
 using ::testing::StrNe;
 
 namespace install_static {
 
+namespace {
+
+// A matcher that returns true if |arg| contains a character that is neither
+// alpha-numeric nor a period.
+MATCHER(ContainsIllegalProgIdChar, "") {
+  const wchar_t* scan = arg;
+  wint_t c;
+  while ((c = *scan++) != 0) {
+    if (!iswalnum(c) && c != L'.')
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
 TEST(InstallModes, VerifyModes) {
   ASSERT_THAT(NUM_INSTALL_MODES, Gt(0));
   for (int i = 0; i < NUM_INSTALL_MODES; ++i) {
@@ -47,6 +70,20 @@
     else
       ASSERT_THAT(mode.app_guid, StrEq(L""));
 
+    // The ProgID prefix must not be empty, must be no greater than 11
+    // characters long, must contain no punctuation, and may not start with a
+    // digit (https://msdn.microsoft.com/library/windows/desktop/dd542719.aspx).
+    ASSERT_THAT(mode.prog_id_prefix, StrNe(L""));
+    ASSERT_THAT(lstrlen(mode.prog_id_prefix), Le(11));
+    ASSERT_THAT(mode.prog_id_prefix, Not(ContainsIllegalProgIdChar()));
+    ASSERT_THAT(*mode.prog_id_prefix, ResultOf(iswdigit, Eq(0)));
+
+    // The ProgID description must not be empty.
+    ASSERT_THAT(mode.prog_id_description, StrNe(L""));
+
+    // Every mode must have an Active Setup GUID.
+    ASSERT_THAT(mode.active_setup_guid, StrNe(L""));
+
     // UNSUPPORTED and kUseGoogleUpdateIntegration are mutually exclusive.
     if (kUseGoogleUpdateIntegration)
       ASSERT_THAT(mode.channel_strategy, Ne(ChannelStrategy::UNSUPPORTED));
diff --git a/chrome/install_static/install_util.cc b/chrome/install_static/install_util.cc
index 9ff2bcd..ffb6147 100644
--- a/chrome/install_static/install_util.cc
+++ b/chrome/install_static/install_util.cc
@@ -324,6 +324,20 @@
   return InstallDetails::Get().base_app_id();
 }
 
+const wchar_t* GetProgIdPrefix() {
+  return InstallDetails::Get().mode().prog_id_prefix;
+}
+
+const wchar_t* GetProgIdDescription() {
+  return InstallDetails::Get().mode().prog_id_description;
+}
+
+std::wstring GetActiveSetupPath() {
+  return std::wstring(
+             L"Software\\Microsoft\\Active Setup\\Installed Components\\")
+      .append(InstallDetails::Get().mode().active_setup_guid);
+}
+
 bool GetCollectStatsConsent() {
   bool enabled = true;
 
diff --git a/chrome/install_static/install_util.h b/chrome/install_static/install_util.h
index a66554e5..20060890 100644
--- a/chrome/install_static/install_util.h
+++ b/chrome/install_static/install_util.h
@@ -80,6 +80,22 @@
 // directly.
 const wchar_t* GetBaseAppId();
 
+// Returns the browser's ProgID prefix (e.g., ChromeHTML or ChromiumHTM). The
+// full id is of the form |prefix|.|suffix| and is limited to a maximum length
+// of 39 characters including null-terminator; see
+// https://msdn.microsoft.com/library/windows/desktop/dd542719.aspx for details.
+// We define |suffix| as a fixed-length 26-character alphanumeric identifier,
+// therefore the return value of this function must have a maximum length of
+// 39 - 1(null-term) - 26(|suffix|) - 1(dot separator) = 11 characters.
+const wchar_t* GetProgIdPrefix();
+
+// Returns the browser's ProgId description.
+const wchar_t* GetProgIdDescription();
+
+// Returns the path to the Active Setup registry entries
+// (e.g., Software\Microsoft\Active Setup\Installed Components\[guid]).
+std::wstring GetActiveSetupPath();
+
 // Returns true if usage stats collecting is enabled for this user for the
 // current executable.
 bool GetCollectStatsConsent();
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index e1e121a..85ff23a31 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -22,6 +22,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/shortcut.h"
 #include "chrome/install_static/install_details.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/setup/install_worker.h"
 #include "chrome/installer/setup/installer_crash_reporting.h"
 #include "chrome/installer/setup/installer_state.h"
@@ -649,7 +650,7 @@
     UpdateDefaultBrowserBeaconForPath(chrome_exe);
   } else {
     UpdateActiveSetupVersionWorkItem active_setup_work_item(
-        InstallUtil::GetActiveSetupPath(chrome.distribution()),
+        install_static::GetActiveSetupPath(),
         UpdateActiveSetupVersionWorkItem::
             UPDATE_AND_BUMP_OS_UPGRADES_COMPONENT);
     if (active_setup_work_item.Do())
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index 342983bd0..ec50d24 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -807,7 +807,7 @@
   DCHECK(installer_state.RequiresActiveSetup());
 
   const HKEY root = HKEY_LOCAL_MACHINE;
-  const base::string16 active_setup_path(InstallUtil::GetActiveSetupPath(dist));
+  const base::string16 active_setup_path(install_static::GetActiveSetupPath());
 
   VLOG(1) << "Adding registration items for Active Setup.";
   list->AddCreateRegKeyWorkItem(
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index d012207..6d14e7c 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -440,9 +440,8 @@
   base::string16 classes_path(ShellUtil::kRegClasses);
   classes_path.push_back(base::FilePath::kSeparators[0]);
 
-  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
-  const base::string16 prog_id(
-      distribution->GetBrowserProgIdPrefix() + browser_entry_suffix);
+  const base::string16 prog_id(install_static::GetProgIdPrefix() +
+                               browser_entry_suffix);
 
   // Delete each filetype association if it references this Chrome.  Take care
   // not to delete the association if it references a system-level install of
@@ -521,19 +520,15 @@
 // but otherwise respects the no rollback/best effort uninstall mentality.
 // This will only apply for system-level installs of Chrome/Chromium and will be
 // a no-op for all other types of installs.
-void UninstallActiveSetupEntries(const InstallerState& installer_state,
-                                 const Product& product) {
+void UninstallActiveSetupEntries(const InstallerState& installer_state) {
   VLOG(1) << "Uninstalling registry entries for Active Setup.";
-  BrowserDistribution* distribution = product.distribution();
 
   if (!installer_state.system_install()) {
-    VLOG(1) << "No Active Setup processing to do for user-level "
-            << distribution->GetDisplayName();
+    VLOG(1) << "No Active Setup processing to do for user-level install.";
     return;
   }
 
-  const base::string16 active_setup_path(
-      InstallUtil::GetActiveSetupPath(distribution));
+  const base::string16 active_setup_path(install_static::GetActiveSetupPath());
   InstallUtil::DeleteRegistryKey(HKEY_LOCAL_MACHINE, active_setup_path,
                                  WorkItem::kWow64Default);
 
@@ -639,8 +634,9 @@
   base::FilePath chrome_exe(installer_state.target_path().Append(kChromeExe));
 
   // Delete Software\Classes\ChromeHTML.
-  const base::string16 prog_id(
-      dist->GetBrowserProgIdPrefix() + browser_entry_suffix);
+  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
+  const base::string16 prog_id(install_static::GetProgIdPrefix() +
+                               browser_entry_suffix);
   base::string16 reg_prog_id(ShellUtil::kRegClasses);
   reg_prog_id.push_back(base::FilePath::kSeparators[0]);
   reg_prog_id.append(prog_id);
@@ -651,7 +647,6 @@
   reg_app_id.push_back(base::FilePath::kSeparators[0]);
   // Append the requested suffix manually here (as ShellUtil::GetBrowserModelId
   // would otherwise try to figure out the currently installed suffix).
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   reg_app_id.append(install_static::GetBaseAppId() + browser_entry_suffix);
   InstallUtil::DeleteRegistryKey(root, reg_app_id, WorkItem::kWow64Default);
 
@@ -972,7 +967,7 @@
 
     ProcessChromeWorkItems(installer_state, product);
 
-    UninstallActiveSetupEntries(installer_state, product);
+    UninstallActiveSetupEntries(installer_state);
 
     UninstallFirewallRules(browser_dist, chrome_exe);
 
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index d5ed7b2..51d8f71 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -33,9 +33,6 @@
 
 namespace {
 
-const wchar_t kChromiumActiveSetupGuid[] =
-    L"{7D2B3E1D-D096-4594-9D8F-A6667F12E0AC}";
-
 const wchar_t kCommandExecuteImplUuid[] =
     L"{A2DF06F9-A21A-44A8-8A99-8B9C84F29160}";
 
@@ -109,10 +106,6 @@
     const base::string16& distribution_data) {
 }
 
-base::string16 BrowserDistribution::GetActiveSetupGuid() {
-  return kChromiumActiveSetupGuid;
-}
-
 base::string16 BrowserDistribution::GetBaseAppName() {
   return L"Chromium";
 }
@@ -144,18 +137,6 @@
   }
 }
 
-base::string16 BrowserDistribution::GetBrowserProgIdPrefix() {
-  // This used to be "ChromiumHTML", but was forced to become "ChromiumHTM"
-  // because of http://crbug.com/153349.  See the declaration of this function
-  // in the header file for more details.
-  return L"ChromiumHTM";
-}
-
-base::string16 BrowserDistribution::GetBrowserProgIdDesc() {
-  return L"Chromium HTML Document";
-}
-
-
 base::string16 BrowserDistribution::GetPublisherName() {
   return L"Chromium";
 }
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index f3e0ce7e..237e2343 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -51,9 +51,6 @@
       const base::FilePath& local_data_path,
       const base::string16& distribution_data);
 
-  // Returns the GUID to be used when registering for Active Setup.
-  virtual base::string16 GetActiveSetupGuid();
-
   // Returns the unsuffixed application name of this program.
   // This is the base of the name registered with Default Programs on Windows.
   // IMPORTANT: This should only be called by the installer which needs to make
@@ -80,18 +77,6 @@
   virtual base::string16 GetStartMenuShortcutSubfolder(
       Subfolder subfolder_type);
 
-  // Returns the Browser ProgId prefix (e.g. ChromeHTML, ChromiumHTM, etc...).
-  // The full id is of the form |prefix|.|suffix| and is limited to a maximum
-  // length of 39 characters including null-terminator.  See
-  // http://msdn.microsoft.com/library/aa911706.aspx for details.  We define
-  // |suffix| as a fixed-length 26-character alphanumeric identifier, therefore
-  // the return value of this function must have a maximum length of
-  // 39 - 1(null-term) - 26(|suffix|) - 1(dot separator) = 11 characters.
-  virtual base::string16 GetBrowserProgIdPrefix();
-
-  // Returns the Browser ProgId description.
-  virtual base::string16 GetBrowserProgIdDesc();
-
   virtual base::string16 GetPublisherName();
 
   virtual base::string16 GetAppDescription();
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index 11d2af1..48e74091 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -41,8 +41,6 @@
 namespace {
 
 const wchar_t kChromeGuid[] = L"{8A69D345-D564-463c-AFF1-A69D9E530F96}";
-const wchar_t kBrowserProgIdPrefix[] = L"ChromeHTML";
-const wchar_t kBrowserProgIdDesc[] = L"Chrome HTML Document";
 const wchar_t kCommandExecuteImplUuid[] =
     L"{5C65F4B0-3651-4514-B207-D10CB699B14B}";
 
@@ -146,10 +144,6 @@
   NavigateToUrlWithIExplore(url);
 }
 
-base::string16 GoogleChromeDistribution::GetActiveSetupGuid() {
-  return install_static::GetAppGuid();
-}
-
 base::string16 GoogleChromeDistribution::GetBaseAppName() {
   // I'd really like to return L ## PRODUCT_FULLNAME_STRING; but that's no good
   // since it'd be "Chromium" in a non-Chrome build, which isn't at all what I
@@ -165,14 +159,6 @@
   return icon_resources::kApplicationIndex;
 }
 
-base::string16 GoogleChromeDistribution::GetBrowserProgIdPrefix() {
-  return kBrowserProgIdPrefix;
-}
-
-base::string16 GoogleChromeDistribution::GetBrowserProgIdDesc() {
-  return kBrowserProgIdDesc;
-}
-
 base::string16 GoogleChromeDistribution::GetPublisherName() {
   const base::string16& publisher_name =
       installer::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE);
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index b84a6e59..f3cecd6 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -35,8 +35,6 @@
       const base::FilePath& local_data_path,
       const base::string16& distribution_data) override;
 
-  base::string16 GetActiveSetupGuid() override;
-
   base::string16 GetShortcutName() override;
 
   base::string16 GetIconFilename() override;
@@ -45,10 +43,6 @@
 
   base::string16 GetBaseAppName() override;
 
-  base::string16 GetBrowserProgIdPrefix() override;
-
-  base::string16 GetBrowserProgIdDesc() override;
-
   base::string16 GetPublisherName() override;
 
   base::string16 GetAppDescription() override;
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index 3e6eab3..c65892c 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -36,10 +36,6 @@
     const base::string16& distribution_data) {
 }
 
-base::string16 GoogleChromeDistribution::GetActiveSetupGuid() {
-  return base::string16();
-}
-
 base::string16 GoogleChromeDistribution::GetBaseAppName() {
   return base::string16();
 }
@@ -52,14 +48,6 @@
   return 0;
 }
 
-base::string16 GoogleChromeDistribution::GetBrowserProgIdPrefix() {
-  return base::string16();
-}
-
-base::string16 GoogleChromeDistribution::GetBrowserProgIdDesc() {
-  return base::string16();
-}
-
 base::string16 GoogleChromeDistribution::GetPublisherName() {
   return base::string16();
 }
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 4a2186fc..66f272f 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -15,8 +15,6 @@
 namespace {
 
 const wchar_t kChromeSxSGuid[] = L"{4ea16ac7-fd5a-47c3-875b-dbf4a2008c20}";
-const wchar_t kBrowserProgIdPrefix[] = L"ChromeSSHTM";
-const wchar_t kBrowserProgIdDesc[] = L"Chrome Canary HTML Document";
 const wchar_t kCommandExecuteImplUuid[] =
     L"{1BEAC3E3-B852-44F4-B468-8906C062422E}";
 
@@ -46,14 +44,6 @@
   }
 }
 
-base::string16 GoogleChromeSxSDistribution::GetBrowserProgIdPrefix() {
-  return kBrowserProgIdPrefix;
-}
-
-base::string16 GoogleChromeSxSDistribution::GetBrowserProgIdDesc() {
-  return kBrowserProgIdDesc;
-}
-
 base::string16 GoogleChromeSxSDistribution::GetUninstallRegPath() {
   return GoogleChromeDistribution::GetUninstallRegPath().append(
       installer::kSxSSuffix);
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.h b/chrome/installer/util/google_chrome_sxs_distribution.h
index ea98696..69e285f9 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.h
+++ b/chrome/installer/util/google_chrome_sxs_distribution.h
@@ -24,8 +24,6 @@
   int GetIconIndex() override;
   base::string16 GetStartMenuShortcutSubfolder(
       Subfolder subfolder_type) override;
-  base::string16 GetBrowserProgIdPrefix() override;
-  base::string16 GetBrowserProgIdDesc() override;
   base::string16 GetUninstallRegPath() override;
   DefaultBrowserControlPolicy GetDefaultBrowserControlPolicy() override;
   base::string16 GetCommandExecuteImplClsid() override;
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index a1446fa..181fbd63 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -28,6 +28,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/installation_state.h"
@@ -80,15 +81,8 @@
 
 }  // namespace
 
-base::string16 InstallUtil::GetActiveSetupPath(BrowserDistribution* dist) {
-  static const wchar_t kInstalledComponentsPath[] =
-      L"Software\\Microsoft\\Active Setup\\Installed Components\\";
-  return kInstalledComponentsPath + dist->GetActiveSetupGuid();
-}
-
 void InstallUtil::TriggerActiveSetupCommand() {
-  base::string16 active_setup_reg(
-      GetActiveSetupPath(BrowserDistribution::GetDistribution()));
+  base::string16 active_setup_reg(install_static::GetActiveSetupPath());
   base::win::RegKey active_setup_key(
       HKEY_LOCAL_MACHINE, active_setup_reg.c_str(), KEY_QUERY_VALUE);
   base::string16 cmd_str;
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index 1ce2356..70c7498 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -32,10 +32,6 @@
 // independently.
 class InstallUtil {
  public:
-  // Get the path to this distribution's Active Setup registry entries.
-  // e.g. Software\Microsoft\Active Setup\Installed Components\<dist_guid>
-  static base::string16 GetActiveSetupPath(BrowserDistribution* dist);
-
   // Attempts to trigger the command that would be run by Active Setup for a
   // system-level Chrome. For use only when system-level Chrome is installed.
   static void TriggerActiveSetupCommand();
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 335d1c2..81311fb 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -88,8 +88,7 @@
 // "ChromeHTML|suffix|").
 // |suffix| can be the empty string.
 base::string16 GetBrowserProgId(const base::string16& suffix) {
-  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  base::string16 chrome_html(dist->GetBrowserProgIdPrefix());
+  base::string16 chrome_html(install_static::GetProgIdPrefix());
   chrome_html.append(suffix);
 
   // ProgIds cannot be longer than 39 characters.
@@ -350,18 +349,20 @@
                             const base::FilePath& chrome_exe,
                             const base::string16& suffix,
                             ScopedVector<RegistryEntry>* entries) {
+  // Assert that this is only called with the one relevant distribution.
+  // TODO(grt): Remove this when BrowserDistribution goes away.
+  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   int chrome_icon_index = dist->GetIconIndex();
 
   ApplicationInfo app_info;
   app_info.prog_id = GetBrowserProgId(suffix);
-  app_info.file_type_name = dist->GetBrowserProgIdDesc();
+  app_info.file_type_name = install_static::GetProgIdDescription();
   // File types associated with Chrome are just given the Chrome icon.
   app_info.file_type_icon_path = chrome_exe;
   app_info.file_type_icon_index = chrome_icon_index;
   app_info.command_line = ShellUtil::GetChromeShellOpenCmd(chrome_exe);
   // For user-level installs: entries for the app id will be in HKCU; thus we
   // do not need a suffix on those entries.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   app_info.app_id =
       ShellUtil::GetBrowserModelId(InstallUtil::IsPerUserInstall());
 
@@ -795,6 +796,9 @@
                              const base::FilePath& chrome_exe,
                              const base::string16& suffix,
                              RegistrationConfirmationLevel confirmation_level) {
+  // Assert that this is only called with the one relevant distribution.
+  // TODO(grt): Remove this when BrowserDistribution goes away.
+  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   // Get the appropriate key to look for based on the level desired.
   base::string16 reg_key;
   switch (confirmation_level) {
@@ -802,7 +806,7 @@
       // Software\Classes\ChromeHTML|suffix|
       reg_key = ShellUtil::kRegClasses;
       reg_key.push_back(base::FilePath::kSeparators[0]);
-      reg_key.append(dist->GetBrowserProgIdPrefix());
+      reg_key.append(install_static::GetProgIdPrefix());
       reg_key.append(suffix);
       break;
     case CONFIRM_SHELL_REGISTRATION:
@@ -1036,8 +1040,8 @@
   if (FAILED(hr))
     return ShellUtil::UNKNOWN_DEFAULT;
 
+  base::string16 prog_id(install_static::GetProgIdPrefix());
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  base::string16 prog_id(dist->GetBrowserProgIdPrefix());
   prog_id += ShellUtil::GetCurrentInstallationSuffix(dist, chrome_exe);
 
   for (size_t i = 0; i < num_protocols; ++i) {
diff --git a/chrome/renderer/autofill/password_generation_agent_browsertest.cc b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
index 59873dc2..8860d48 100644
--- a/chrome/renderer/autofill/password_generation_agent_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_agent_browsertest.cc
@@ -797,4 +797,20 @@
   }
 }
 
+TEST_F(PasswordGenerationAgentTest, JavascriptClearedTheField) {
+  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
+  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
+  SetAccountCreationFormsDetectedMessage(password_generation_,
+                                         GetMainFrame()->document(), 0, 1);
+
+  const char kGenerationElementId[] = "first_password";
+  ExpectGenerationAvailable(kGenerationElementId, true);
+  password_generation_->GeneratedPasswordAccepted(base::ASCIIToUTF16("pwd"));
+  ExecuteJavaScriptForTests(
+      "document.getElementById('first_password').value = '';");
+  FocusField(kGenerationElementId);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(fake_driver_.called_password_no_longer_generated());
+}
+
 }  // namespace autofill
diff --git a/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js b/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js
new file mode 100644
index 0000000..5bc4269
--- /dev/null
+++ b/chrome/test/data/webui/md_bookmarks/edit_dialog_test.js
@@ -0,0 +1,58 @@
+// 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.
+
+suite('<bookmarks-edit-dialog>', function() {
+  var dialog;
+  var lastUpdate;
+
+  suiteSetup(function() {
+    chrome.bookmarks.update = function(id, edit) {
+      lastUpdate.id = id;
+      lastUpdate.edit = edit;
+    }
+  });
+
+  setup(function() {
+    lastUpdate = {};
+    dialog = document.createElement('bookmarks-edit-dialog');
+    replaceBody(dialog);
+  });
+
+  test('editing an item shows the url field', function() {
+    var item = createItem('0');
+    dialog.showEditDialog(item);
+
+    assertFalse(dialog.$.url.hidden);
+  });
+
+  test('editing a folder hides the url field', function() {
+    var folder = createFolder('0', []);
+    dialog.showEditDialog(folder);
+
+    assertTrue(dialog.$.url.hidden);
+  });
+
+  test('editing passes the correct details to the update', function() {
+    // Editing an item without changing anything.
+    var item = createItem('1', {url: 'www.website.com', title: 'website'});
+    dialog.showEditDialog(item);
+
+    MockInteractions.tap(dialog.$.saveButton);
+
+    assertEquals(item.id, lastUpdate.id);
+    assertEquals(item.url, lastUpdate.edit.url);
+    assertEquals(item.title, lastUpdate.edit.title);
+
+    // Editing a folder, changing the title.
+    var folder = createFolder('2', [], {title: 'Cool Sites'});
+    dialog.showEditDialog(folder);
+    dialog.titleValue_ = 'Awesome websites';
+
+    MockInteractions.tap(dialog.$.saveButton);
+
+    assertEquals(folder.id, lastUpdate.id);
+    assertEquals(undefined, lastUpdate.edit.url);
+    assertEquals('Awesome websites', lastUpdate.edit.title);
+  });
+});
diff --git a/chrome/test/data/webui/md_bookmarks/list_test.js b/chrome/test/data/webui/md_bookmarks/list_test.js
index a2cd6f9..155f2776 100644
--- a/chrome/test/data/webui/md_bookmarks/list_test.js
+++ b/chrome/test/data/webui/md_bookmarks/list_test.js
@@ -25,40 +25,6 @@
     Polymer.dom.flush();
   });
 
-  test('folder menu item hides the url field', function() {
-    // Bookmark editor shows the url field.
-    list.menuItem_ = store.data.nodes['1'];
-    assertFalse(list.$['url'].hidden);
-
-    // Folder editor hides the url field.
-    list.menuItem_ = store.data.nodes['3'];
-    assertTrue(list.$['url'].hidden);
-  });
-
-  test('saving edit passes correct details to the update', function() {
-    // Saving bookmark edit.
-    var menuItem = store.data.nodes['1'];
-    chrome.bookmarks.update = function(id, edit) {
-      assertEquals(menuItem.id, id);
-      assertEquals(menuItem.url, edit.url);
-      assertEquals(menuItem.title, edit.title);
-    };
-    list.menuItem_ = menuItem;
-    list.$.editBookmark.showModal();
-    MockInteractions.tap(list.$.saveButton);
-
-    // Saving folder rename.
-    menuItem = store.data.nodes['3'];
-    chrome.bookmarks.update = function(id, edit) {
-      assertEquals(menuItem.id, id);
-      assertEquals(menuItem.title, edit.title);
-      assertEquals(undefined, edit.url);
-    };
-    list.menuItem_ = menuItem;
-    list.$.editBookmark.showModal();
-    MockInteractions.tap(list.$.saveButton);
-  });
-
   test('renders correct <bookmark-item> elements', function() {
     var items = list.root.querySelectorAll('bookmarks-item');
     var ids = Array.from(items).map((item) => item.itemId);
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
index 02f230a..8205db5 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_browsertest.js
@@ -55,6 +55,20 @@
   mocha.run();
 });
 
+function MaterialBookmarksEditDialogTest() {}
+
+MaterialBookmarksEditDialogTest.prototype = {
+  __proto__: MaterialBookmarksBrowserTest.prototype,
+
+  extraLibraries: MaterialBookmarksBrowserTest.prototype.extraLibraries.concat([
+    'edit_dialog_test.js',
+  ]),
+};
+
+TEST_F('MaterialBookmarksEditDialogTest', 'All', function() {
+  mocha.run();
+});
+
 function MaterialBookmarksItemTest() {}
 
 MaterialBookmarksItemTest.prototype = {
diff --git a/components/autofill/content/renderer/password_generation_agent.cc b/components/autofill/content/renderer/password_generation_agent.cc
index 868e950..6e3fc67 100644
--- a/components/autofill/content/renderer/password_generation_agent.cc
+++ b/components/autofill/content/renderer/password_generation_agent.cc
@@ -452,8 +452,12 @@
     return false;
 
   if (password_is_generated_) {
-    generation_element_.setShouldRevealPassword(true);
-    ShowEditingPopup();
+    if (generation_element_.value().isEmpty()) {
+      PasswordNoLongerGenerated();
+    } else {
+      generation_element_.setShouldRevealPassword(true);
+      ShowEditingPopup();
+    }
     return true;
   }
 
@@ -478,21 +482,9 @@
   if (element.value().isEmpty()) {
     if (password_is_generated_) {
       // User generated a password and then deleted it.
-      password_generation::LogPasswordGenerationEvent(
-          password_generation::PASSWORD_DELETED);
-      CopyElementValueToOtherInputElements(&element,
-          &generation_form_data_->password_elements);
-      std::unique_ptr<PasswordForm> presaved_form(
-          CreatePasswordFormToPresave());
-      if (presaved_form) {
-        GetPasswordManagerDriver()->PasswordNoLongerGenerated(*presaved_form);
-      }
+      PasswordNoLongerGenerated();
     }
 
-    // Do not treat the password as generated, either here or in the browser.
-    password_is_generated_ = false;
-    generation_element_.setShouldRevealPassword(false);
-
     // Offer generation again.
     ShowGenerationPopup();
   } else if (password_is_generated_) {
@@ -544,6 +536,22 @@
   GetPasswordManagerClient()->HidePasswordGenerationPopup();
 }
 
+void PasswordGenerationAgent::PasswordNoLongerGenerated() {
+  // Do not treat the password as generated, either here or in the browser.
+  password_is_generated_ = false;
+  generation_element_.setShouldRevealPassword(false);
+  for (blink::WebInputElement& password :
+       generation_form_data_->password_elements)
+    password.setAutofilled(false);
+  password_generation::LogPasswordGenerationEvent(
+      password_generation::PASSWORD_DELETED);
+  CopyElementValueToOtherInputElements(
+      &generation_element_, &generation_form_data_->password_elements);
+  std::unique_ptr<PasswordForm> presaved_form(CreatePasswordFormToPresave());
+  if (presaved_form)
+    GetPasswordManagerDriver()->PasswordNoLongerGenerated(*presaved_form);
+}
+
 void PasswordGenerationAgent::UserTriggeredGeneratePassword() {
   if (last_focused_password_element_.isNull() || !render_frame())
     return;
diff --git a/components/autofill/content/renderer/password_generation_agent.h b/components/autofill/content/renderer/password_generation_agent.h
index c7cb5fb2..2af6282 100644
--- a/components/autofill/content/renderer/password_generation_agent.h
+++ b/components/autofill/content/renderer/password_generation_agent.h
@@ -113,6 +113,9 @@
   // Hides a password generation popup if one exists.
   void HidePopup();
 
+  // Stops treating a password as generated.
+  void PasswordNoLongerGenerated();
+
   // Runs HTML parsing based classifier and saves its outcome to proto.
   // TODO(crbug.com/621442): Remove client-side form classifier when server-side
   // classifier is ready.
diff --git a/components/ntp_snippets/BUILD.gn b/components/ntp_snippets/BUILD.gn
index d642c3f6..a99765e 100644
--- a/components/ntp_snippets/BUILD.gn
+++ b/components/ntp_snippets/BUILD.gn
@@ -152,6 +152,7 @@
     "remote/test_utils.h",
     "sessions/foreign_sessions_suggestions_provider_unittest.cc",
     "sessions/tab_delegate_sync_adapter_unittest.cc",
+    "user_classifier_unittest.cc",
   ]
 
   deps = [
diff --git a/components/ntp_snippets/user_classifier_unittest.cc b/components/ntp_snippets/user_classifier_unittest.cc
new file mode 100644
index 0000000..f8f3a43
--- /dev/null
+++ b/components/ntp_snippets/user_classifier_unittest.cc
@@ -0,0 +1,317 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ntp_snippets/user_classifier.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/simple_test_clock.h"
+#include "base/time/time.h"
+#include "components/ntp_snippets/features.h"
+#include "components/ntp_snippets/ntp_snippets_constants.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_params_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::DoubleNear;
+using testing::Eq;
+using testing::Gt;
+using testing::Lt;
+using testing::SizeIs;
+
+namespace ntp_snippets {
+namespace {
+
+char kNowString[] = "2017-03-01 10:45";
+
+class UserClassifierTest : public testing::Test {
+ public:
+  UserClassifierTest() {
+    UserClassifier::RegisterProfilePrefs(test_prefs_.registry());
+  }
+
+  UserClassifier* CreateUserClassifier() {
+    auto test_clock = base::MakeUnique<base::SimpleTestClock>();
+    test_clock_ = test_clock.get();
+
+    base::Time now;
+    CHECK(base::Time::FromUTCString(kNowString, &now));
+    test_clock_->SetNow(now);
+
+    user_classifier_ =
+        base::MakeUnique<UserClassifier>(&test_prefs_, std::move(test_clock));
+    return user_classifier_.get();
+  }
+
+  base::SimpleTestClock* test_clock() { return test_clock_; }
+
+ private:
+  TestingPrefServiceSimple test_prefs_;
+  std::unique_ptr<UserClassifier> user_classifier_;
+
+  // Owned by the UserClassifier.
+  base::SimpleTestClock* test_clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserClassifierTest);
+};
+
+TEST_F(UserClassifierTest, ShouldBeActiveNtpUserInitially) {
+  UserClassifier* user_classifier = CreateUserClassifier();
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+}
+
+TEST_F(UserClassifierTest,
+       ShouldBecomeActiveSuggestionsConsumerByClickingOften) {
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // After one click still only an active user.
+  user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+  // After a few more clicks, become an active consumer.
+  for (int i = 0; i < 5; i++) {
+    test_clock()->Advance(base::TimeDelta::FromHours(1));
+    user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+  }
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER));
+}
+
+TEST_F(UserClassifierTest,
+       ShouldBecomeActiveSuggestionsConsumerByClickingOftenWithDecreasedParam) {
+  // Increase the param to one half.
+  variations::testing::VariationParamsManager variation_params(
+      kStudyName,
+      {{"user_classifier_active_consumer_clicks_at_least_once_per_hours",
+        "36"}},
+      {kArticleSuggestionsFeature.name});
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // After two clicks still only an active user.
+  user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+  test_clock()->Advance(base::TimeDelta::FromHours(1));
+  user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+  // One more click to become an active consumer.
+  test_clock()->Advance(base::TimeDelta::FromHours(1));
+  user_classifier->OnEvent(UserClassifier::Metric::SUGGESTIONS_USED);
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER));
+}
+
+TEST_F(UserClassifierTest, ShouldBecomeRareNtpUserByNoActivity) {
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // After two days of waiting still an active user.
+  test_clock()->Advance(base::TimeDelta::FromDays(2));
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+  // Two more days to become a rare user.
+  test_clock()->Advance(base::TimeDelta::FromDays(2));
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::RARE_NTP_USER));
+}
+
+TEST_F(UserClassifierTest,
+       ShouldBecomeRareNtpUserByNoActivityWithDecreasedParam) {
+  // Decrease the param to one half.
+  variations::testing::VariationParamsManager variation_params(
+      kStudyName,
+      {{"user_classifier_rare_user_opens_ntp_at_most_once_per_hours", "48"}},
+      {kArticleSuggestionsFeature.name});
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // After one days of waiting still an active user.
+  test_clock()->Advance(base::TimeDelta::FromDays(1));
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::ACTIVE_NTP_USER));
+
+  // One more day to become a rare user.
+  test_clock()->Advance(base::TimeDelta::FromDays(1));
+  EXPECT_THAT(user_classifier->GetUserClass(),
+              Eq(UserClassifier::UserClass::RARE_NTP_USER));
+}
+
+class UserClassifierMetricTest
+    : public UserClassifierTest,
+      public ::testing::WithParamInterface<
+          std::pair<UserClassifier::Metric, std::string>> {
+ public:
+  UserClassifierMetricTest() : UserClassifierTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UserClassifierMetricTest);
+};
+
+TEST_P(UserClassifierMetricTest, ShouldDecreaseEstimateAfterEvent) {
+  UserClassifier::Metric metric = GetParam().first;
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // The initial event does not decrease the estimate.
+  user_classifier->OnEvent(metric);
+
+  for (int i = 0; i < 10; i++) {
+    test_clock()->Advance(base::TimeDelta::FromHours(1));
+    double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+    user_classifier->OnEvent(metric);
+    EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+  }
+}
+
+TEST_P(UserClassifierMetricTest, ShouldReportToUmaOnEvent) {
+  UserClassifier::Metric metric = GetParam().first;
+  const std::string& histogram_name = GetParam().second;
+  base::HistogramTester histogram_tester;
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  user_classifier->OnEvent(metric);
+  EXPECT_THAT(histogram_tester.GetAllSamples(histogram_name), SizeIs(1));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldConvergeTowardsPattern) {
+  UserClassifier::Metric metric = GetParam().first;
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // Have the pattern of an event every five hours and start changing it towards
+  // an event every 10 hours.
+  for (int i = 0; i < 100; i++) {
+    test_clock()->Advance(base::TimeDelta::FromHours(5));
+    user_classifier->OnEvent(metric);
+  }
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+              DoubleNear(5.0, 0.1));
+  for (int i = 0; i < 3; i++) {
+    test_clock()->Advance(base::TimeDelta::FromHours(10));
+    user_classifier->OnEvent(metric);
+  }
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Gt(5.5));
+  for (int i = 0; i < 100; i++) {
+    test_clock()->Advance(base::TimeDelta::FromHours(10));
+    user_classifier->OnEvent(metric);
+  }
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+              DoubleNear(10.0, 0.1));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldIgnoreSubsequentEventsForHalfAnHour) {
+  UserClassifier::Metric metric = GetParam().first;
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // The initial event
+  user_classifier->OnEvent(metric);
+  // Subsequent events get ignored for the next 30 minutes.
+  for (int i = 0; i < 5; i++) {
+    test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+    double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+    user_classifier->OnEvent(metric);
+    EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Eq(old_metric));
+  }
+  // An event 30 minutes after the initial event is finally not ignored.
+  test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+  double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+  user_classifier->OnEvent(metric);
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+}
+
+TEST_P(UserClassifierMetricTest,
+       ShouldIgnoreSubsequentEventsWithIncreasedLimit) {
+  UserClassifier::Metric metric = GetParam().first;
+  // Increase the min_hours to 1.0, i.e. 60 minutes.
+  variations::testing::VariationParamsManager variation_params(
+      kStudyName, {{"user_classifier_min_hours", "1.0"}},
+      {kArticleSuggestionsFeature.name});
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // The initial event
+  user_classifier->OnEvent(metric);
+  // Subsequent events get ignored for the next 60 minutes.
+  for (int i = 0; i < 11; i++) {
+    test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+    double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+    user_classifier->OnEvent(metric);
+    EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Eq(old_metric));
+  }
+  // An event 60 minutes after the initial event is finally not ignored.
+  test_clock()->Advance(base::TimeDelta::FromMinutes(5));
+  double old_metric = user_classifier->GetEstimatedAvgTime(metric);
+  user_classifier->OnEvent(metric);
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric), Lt(old_metric));
+}
+
+TEST_P(UserClassifierMetricTest, ShouldCapDelayBetweenEvents) {
+  UserClassifier::Metric metric = GetParam().first;
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // The initial event
+  user_classifier->OnEvent(metric);
+  // Wait for an insane amount of time
+  test_clock()->Advance(base::TimeDelta::FromDays(365));
+  user_classifier->OnEvent(metric);
+  double metric_after_a_year = user_classifier->GetEstimatedAvgTime(metric);
+
+  // Now repeat the same with s/one year/one week.
+  user_classifier->ClearClassificationForDebugging();
+  user_classifier->OnEvent(metric);
+  test_clock()->Advance(base::TimeDelta::FromDays(7));
+  user_classifier->OnEvent(metric);
+
+  // The results should be the same.
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+              Eq(metric_after_a_year));
+}
+
+TEST_P(UserClassifierMetricTest,
+       ShouldCapDelayBetweenEventsWithDecreasedLimit) {
+  UserClassifier::Metric metric = GetParam().first;
+  // Decrease the max_hours to 72, i.e. 3 days.
+  variations::testing::VariationParamsManager variation_params(
+      kStudyName, {{"user_classifier_max_hours", "72"}},
+      {kArticleSuggestionsFeature.name});
+  UserClassifier* user_classifier = CreateUserClassifier();
+
+  // The initial event
+  user_classifier->OnEvent(metric);
+  // Wait for an insane amount of time
+  test_clock()->Advance(base::TimeDelta::FromDays(365));
+  user_classifier->OnEvent(metric);
+  double metric_after_a_year = user_classifier->GetEstimatedAvgTime(metric);
+
+  // Now repeat the same with s/one year/two days.
+  user_classifier->ClearClassificationForDebugging();
+  user_classifier->OnEvent(metric);
+  test_clock()->Advance(base::TimeDelta::FromDays(3));
+  user_classifier->OnEvent(metric);
+
+  // The results should be the same.
+  EXPECT_THAT(user_classifier->GetEstimatedAvgTime(metric),
+              Eq(metric_after_a_year));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    ,  // An empty prefix for the parametrized tests names (no need to
+       // distinguish the only instance we make here).
+    UserClassifierMetricTest,
+    testing::Values(
+        std::make_pair(UserClassifier::Metric::NTP_OPENED,
+                       "NewTabPage.UserClassifier.AverageHoursToOpenNTP"),
+        std::make_pair(
+            UserClassifier::Metric::SUGGESTIONS_SHOWN,
+            "NewTabPage.UserClassifier.AverageHoursToShowSuggestions"),
+        std::make_pair(
+            UserClassifier::Metric::SUGGESTIONS_USED,
+            "NewTabPage.UserClassifier.AverageHoursToUseSuggestions")));
+
+}  // namespace
+}  // namespace ntp_snippets
diff --git a/components/subresource_filter/content/browser/BUILD.gn b/components/subresource_filter/content/browser/BUILD.gn
index 426fd6e..6a6acd9 100644
--- a/components/subresource_filter/content/browser/BUILD.gn
+++ b/components/subresource_filter/content/browser/BUILD.gn
@@ -8,6 +8,8 @@
     "activation_state_computing_navigation_throttle.h",
     "async_document_subresource_filter.cc",
     "async_document_subresource_filter.h",
+    "content_activation_list_utils.cc",
+    "content_activation_list_utils.h",
     "content_ruleset_service.cc",
     "content_ruleset_service.h",
     "content_subresource_filter_driver_factory.cc",
diff --git a/components/subresource_filter/content/browser/content_activation_list_utils.cc b/components/subresource_filter/content/browser/content_activation_list_utils.cc
new file mode 100644
index 0000000..6689d60
--- /dev/null
+++ b/components/subresource_filter/content/browser/content_activation_list_utils.cc
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/content/browser/content_activation_list_utils.h"
+
+namespace subresource_filter {
+
+ActivationList GetListForThreatTypeAndMetadata(
+    safe_browsing::SBThreatType threat_type,
+    safe_browsing::ThreatPatternType threat_type_metadata) {
+  bool is_phishing_interstitial =
+      (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
+  bool is_soc_engineering_ads_interstitial =
+      threat_type_metadata ==
+      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS;
+  if (is_phishing_interstitial) {
+    if (is_soc_engineering_ads_interstitial) {
+      return ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL;
+    }
+    return ActivationList::PHISHING_INTERSTITIAL;
+  }
+  return ActivationList::NONE;
+}
+
+}  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/content_activation_list_utils.h b/components/subresource_filter/content/browser/content_activation_list_utils.h
new file mode 100644
index 0000000..dc23a48
--- /dev/null
+++ b/components/subresource_filter/content/browser/content_activation_list_utils.h
@@ -0,0 +1,19 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
+
+#include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+
+namespace subresource_filter {
+
+ActivationList GetListForThreatTypeAndMetadata(
+    safe_browsing::SBThreatType threat_type,
+    safe_browsing::ThreatPatternType threat_type_metadata);
+
+}  // namespace subresource_filter
+
+#endif  // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_CONTENT_ACTIVATION_LIST_UTILS_H_
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index b9c7d1c..bce50cd 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -7,6 +7,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
 #include "base/time/time.h"
+#include "components/subresource_filter/content/browser/content_activation_list_utils.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
@@ -41,6 +42,17 @@
   return rate == 1 || (rate > 0 && base::RandDouble() < rate);
 }
 
+// Records histograms about the length of redirect chains, and about the pattern
+// of whether each URL in the chain matched the activation list.
+#define REPORT_REDIRECT_PATTERN_FOR_SUFFIX(suffix, hits_pattern, chain_size)   \
+  do {                                                                         \
+    UMA_HISTOGRAM_ENUMERATION(                                                 \
+        "SubresourceFilter.PageLoad.RedirectChainMatchPattern." suffix,        \
+        hits_pattern, 0x10);                                                   \
+    UMA_HISTOGRAM_COUNTS(                                                      \
+        "SubresourceFilter.PageLoad.RedirectChainLength." suffix, chain_size); \
+  } while (0)
+
 }  // namespace
 
 // static
@@ -120,18 +132,8 @@
         const std::vector<GURL>& redirect_urls,
         safe_browsing::SBThreatType threat_type,
         safe_browsing::ThreatPatternType threat_type_metadata) {
-  bool is_phishing_interstitial =
-      (threat_type == safe_browsing::SB_THREAT_TYPE_URL_PHISHING);
-  bool is_soc_engineering_ads_interstitial =
-      threat_type_metadata ==
-      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS;
-
-  if (is_phishing_interstitial) {
-    if (is_soc_engineering_ads_interstitial) {
-      AddActivationListMatch(url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
-    }
-    AddActivationListMatch(url, ActivationList::PHISHING_INTERSTITIAL);
-  }
+  AddActivationListMatch(
+      url, GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata));
 }
 
 void ContentSubresourceFilterDriverFactory::AddHostOfURLToWhitelistSet(
@@ -158,15 +160,23 @@
   switch (scope) {
     case ActivationScope::ALL_SITES:
       return ActivationDecision::ACTIVATED;
-    case ActivationScope::ACTIVATION_LIST:
+    case ActivationScope::ACTIVATION_LIST: {
       // The logic to ensure only http/https URLs are activated lives in
       // AddActivationListMatch to ensure the activation list only has relevant
       // entries.
       DCHECK(url.SchemeIsHTTPOrHTTPS() ||
-             !DidURLMatchCurrentActivationList(url));
-      return DidURLMatchCurrentActivationList(url)
-                 ? ActivationDecision::ACTIVATED
-                 : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED;
+             !DidURLMatchActivationList(url, GetCurrentActivationList()));
+      bool should_activate =
+          DidURLMatchActivationList(url, GetCurrentActivationList());
+      if (GetCurrentActivationList() == ActivationList::PHISHING_INTERSTITIAL) {
+        // Handling special case, where activation on the phishing sites also
+        // mean the activation on the sites with social engineering metadata.
+        should_activate |= DidURLMatchActivationList(
+            url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
+      }
+      return should_activate ? ActivationDecision::ACTIVATED
+                             : ActivationDecision::ACTIVATION_LIST_NOT_MATCHED;
+    }
     default:
       return ActivationDecision::ACTIVATION_DISABLED;
   }
@@ -321,54 +331,79 @@
   ActivateForFrameHostIfNeeded(render_frame_host, url);
 }
 
-bool ContentSubresourceFilterDriverFactory::DidURLMatchCurrentActivationList(
-    const GURL& url) const {
+bool ContentSubresourceFilterDriverFactory::DidURLMatchActivationList(
+    const GURL& url,
+    ActivationList activation_list) const {
   auto match_types =
       activation_list_matches_.find(DistillURLToHostAndPath(url));
   return match_types != activation_list_matches_.end() &&
-         match_types->second.find(GetCurrentActivationList()) !=
-             match_types->second.end();
+         match_types->second.find(activation_list) != match_types->second.end();
 }
 
 void ContentSubresourceFilterDriverFactory::AddActivationListMatch(
     const GURL& url,
     ActivationList match_type) {
+  if (match_type == ActivationList::NONE)
+    return;
   if (url.has_host() && url.SchemeIsHTTPOrHTTPS())
     activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type);
 }
 
-void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern()
-    const {
+int ContentSubresourceFilterDriverFactory::CalculateHitPatternForActivationList(
+    ActivationList activation_list) const {
   int hits_pattern = 0;
   const int kInitialURLHitMask = 0x4;
   const int kRedirectURLHitMask = 0x2;
   const int kFinalURLHitMask = 0x1;
   if (navigation_chain_.size() > 1) {
-    if (DidURLMatchCurrentActivationList(navigation_chain_.back()))
+    if (DidURLMatchActivationList(navigation_chain_.back(), activation_list))
       hits_pattern |= kFinalURLHitMask;
-    if (DidURLMatchCurrentActivationList(navigation_chain_.front()))
+    if (DidURLMatchActivationList(navigation_chain_.front(), activation_list))
       hits_pattern |= kInitialURLHitMask;
 
     // Examine redirects.
     for (size_t i = 1; i < navigation_chain_.size() - 1; ++i) {
-      if (DidURLMatchCurrentActivationList(navigation_chain_[i])) {
+      if (DidURLMatchActivationList(navigation_chain_[i], activation_list)) {
         hits_pattern |= kRedirectURLHitMask;
         break;
       }
     }
   } else {
     if (navigation_chain_.size() &&
-        DidURLMatchCurrentActivationList(navigation_chain_.front())) {
+        DidURLMatchActivationList(navigation_chain_.front(), activation_list)) {
       hits_pattern = 0x8;  // One url hit.
     }
   }
+  return hits_pattern;
+}
+
+void ContentSubresourceFilterDriverFactory::RecordRedirectChainMatchPattern()
+    const {
+  RecordRedirectChainMatchPatternForList(
+      ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL);
+  RecordRedirectChainMatchPatternForList(ActivationList::PHISHING_INTERSTITIAL);
+}
+
+void ContentSubresourceFilterDriverFactory::
+    RecordRedirectChainMatchPatternForList(
+        ActivationList activation_list) const {
+  int hits_pattern = CalculateHitPatternForActivationList(activation_list);
   if (!hits_pattern)
     return;
-  UMA_HISTOGRAM_ENUMERATION(
-      "SubresourceFilter.PageLoad.RedirectChainMatchPattern", hits_pattern,
-      0x10 /* max value */);
-  UMA_HISTOGRAM_COUNTS("SubresourceFilter.PageLoad.RedirectChainLength",
-                       navigation_chain_.size());
+  size_t chain_size = navigation_chain_.size();
+  switch (activation_list) {
+    case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
+      REPORT_REDIRECT_PATTERN_FOR_SUFFIX("SocialEngineeringAdsInterstitial",
+                                         hits_pattern, chain_size);
+      break;
+    case ActivationList::PHISHING_INTERSTITIAL:
+      REPORT_REDIRECT_PATTERN_FOR_SUFFIX("PhishingInterstital", hits_pattern,
+                                         chain_size);
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
 }
 
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index ee1abda..658f6261 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -152,11 +152,17 @@
       const content::Referrer& referrer,
       ui::PageTransition page_transition);
 
-  bool DidURLMatchCurrentActivationList(const GURL& url) const;
+  bool DidURLMatchActivationList(const GURL& url,
+                                 ActivationList activation_list) const;
 
   void AddActivationListMatch(const GURL& url, ActivationList match_type);
+  int CalculateHitPatternForActivationList(
+      ActivationList activation_list) const;
   void RecordRedirectChainMatchPattern() const;
 
+  void RecordRedirectChainMatchPatternForList(
+      ActivationList activation_list) const;
+
   std::unique_ptr<SubresourceFilterClient> client_;
 
   HostPathSet whitelisted_hosts_;
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
index 2c1e34e..f02b9d6 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_driver_factory_unittest.cc
@@ -9,10 +9,12 @@
 #include "base/metrics/field_trial.h"
 #include "base/test/histogram_tester.h"
 #include "components/safe_browsing_db/util.h"
+#include "components/subresource_filter/content/browser/content_activation_list_utils.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+#include "components/subresource_filter/core/common/activation_list.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
@@ -61,6 +63,18 @@
   NUM_HIT_PATTERNS,
 };
 
+std::string GetSuffixForList(const ActivationList& type) {
+  switch (type) {
+    case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
+      return ".SocialEngineeringAdsInterstitial";
+    case ActivationList::PHISHING_INTERSTITIAL:
+      return ".PhishingInterstital";
+    case ActivationList::NONE:
+      return std::string();
+  }
+  return std::string();
+}
+
 struct ActivationListTestData {
   ActivationDecision expected_activation_decision;
   const char* const activation_list;
@@ -124,6 +138,10 @@
      subresource_filter::kActivationListSocialEngineeringAdsInterstitial,
      safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
      safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
+    {ActivationDecision::ACTIVATED,
+     subresource_filter::kActivationListPhishingInterstitial,
+     safe_browsing::SB_THREAT_TYPE_URL_PHISHING,
+     safe_browsing::ThreatPatternType::SOCIAL_ENGINEERING_ADS},
 };
 
 struct ActivationScopeTestData {
@@ -268,18 +286,20 @@
     content::RenderFrameHostTester* rfh_tester =
         content::RenderFrameHostTester::For(main_rfh());
     rfh_tester->AppendChild(kSubframeName);
+    ActivationList activation_list =
+        GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata);
 
+    const std::string suffix(GetSuffixForList(activation_list));
     if (expected_pattern != EMPTY) {
-      EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName),
+      EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName + suffix),
                   ::testing::ElementsAre(base::Bucket(expected_pattern, 1)));
       EXPECT_THAT(
-          tester.GetAllSamples(kNavigationChainSize),
+          tester.GetAllSamples(kNavigationChainSize + suffix),
           ::testing::ElementsAre(base::Bucket(navigation_chain.size(), 1)));
-
     } else {
-      EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName),
+      EXPECT_THAT(tester.GetAllSamples(kMatchesPatternHistogramName + suffix),
                   ::testing::IsEmpty());
-      EXPECT_THAT(tester.GetAllSamples(kNavigationChainSize),
+      EXPECT_THAT(tester.GetAllSamples(kNavigationChainSize + suffix),
                   ::testing::IsEmpty());
     }
   }
@@ -426,10 +446,10 @@
       kActivationScopeAllSites,
       kActivationListSocialEngineeringAdsInterstitial);
   const GURL url(kExampleUrlWithParams);
-  NavigateAndExpectActivation({true}, {url}, EMPTY,
+  NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
                               ActivationDecision::ACTIVATION_DISABLED);
   factory()->AddHostOfURLToWhitelistSet(url);
-  NavigateAndExpectActivation({true}, {url}, EMPTY,
+  NavigateAndExpectActivation({true}, {url}, NO_REDIRECTS_HIT,
                               ActivationDecision::ACTIVATION_DISABLED);
 }
 
@@ -488,6 +508,8 @@
   EmulateFailedNavigationAndExpectNoActivation(url);
 }
 
+// TODO(melandory): refactor the test so it no longer require the current
+// activation list to be matching.
 TEST_F(ContentSubresourceFilterDriverFactoryTest, RedirectPatternTest) {
   base::FieldTrialList field_trial_list(nullptr);
   testing::ScopedSubresourceFilterFeatureToggle scoped_feature_toggle(
@@ -675,13 +697,14 @@
   const GURL test_url("https://example.com/nonsoceng?q=engsocnon");
   std::vector<GURL> navigation_chain;
 
-  const bool expected_activation =
-      test_data.expected_activation_decision == ActivationDecision::ACTIVATED;
+  ActivationList effective_list = GetListForThreatTypeAndMetadata(
+      test_data.threat_type, test_data.threat_type_metadata);
   NavigateAndExpectActivation(
       {false, false, false, true},
       {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), test_url}, test_data.threat_type,
       test_data.threat_type_metadata, content::Referrer(),
-      ui::PAGE_TRANSITION_LINK, expected_activation ? F0M0L1 : EMPTY,
+      ui::PAGE_TRANSITION_LINK,
+      effective_list != ActivationList::NONE ? F0M0L1 : EMPTY,
       test_data.expected_activation_decision);
 };
 
diff --git a/components/subresource_filter/core/browser/BUILD.gn b/components/subresource_filter/core/browser/BUILD.gn
index 4dbd01a..88b446da 100644
--- a/components/subresource_filter/core/browser/BUILD.gn
+++ b/components/subresource_filter/core/browser/BUILD.gn
@@ -33,6 +33,7 @@
     "//base/test:test_support",
     "//components/variations",
     "//testing/gtest",
+    "//third_party/protobuf:protobuf_lite",
   ]
 }
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 9166cfe3..20d5c188 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -584,8 +584,8 @@
 
   DCHECK(gfx::SkIRectToRect(actual_bmp.bounds()).Contains(matching_mask));
 
-  for (int x = matching_mask.x(); x < matching_mask.width(); ++x) {
-    for (int y = matching_mask.y(); y < matching_mask.height(); ++y) {
+  for (int x = matching_mask.x(); x < matching_mask.right(); ++x) {
+    for (int y = matching_mask.y(); y < matching_mask.bottom(); ++y) {
       SkColor actual_color = actual_bmp.getColor(x, y);
       SkColor expected_color = expected_bmp.getColor(x, y);
       if (!ColorsMatchWithinLimit(actual_color, expected_color, error_limit)) {
@@ -613,10 +613,12 @@
  protected:
   enum ScreenshotEncoding { ENCODING_PNG, ENCODING_JPEG };
   void CaptureScreenshotAndCompareTo(const SkBitmap& expected_bitmap,
-                                     ScreenshotEncoding encoding) {
+                                     ScreenshotEncoding encoding,
+                                     bool fromSurface) {
     std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue());
     params->SetString("format", encoding == ENCODING_PNG ? "png" : "jpeg");
     params->SetInteger("quality", 100);
+    params->SetBoolean("fromSurface", fromSurface);
     SendCommand("Page.captureScreenshot", std::move(params));
 
     std::string base64;
@@ -701,7 +703,7 @@
     expected_bitmap.allocN32Pixels(scaled_box_size.width(),
                                    scaled_box_size.height());
     expected_bitmap.eraseColor(SkColorSetRGB(0x00, 0x00, 0xff));
-    CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG);
+    CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG, true);
 
     // Reset for next screenshot.
     SendCommand("Emulation.resetViewport", nullptr);
@@ -735,7 +737,7 @@
                             ->GetPhysicalBackingSize();
   expected_bitmap.allocN32Pixels(view_size.width(), view_size.height());
   expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56));
-  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG);
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_PNG, false);
 }
 
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshotJpeg) {
@@ -758,7 +760,7 @@
                             ->GetPhysicalBackingSize();
   expected_bitmap.allocN32Pixels(view_size.width(), view_size.height());
   expected_bitmap.eraseColor(SkColorSetRGB(0x12, 0x34, 0x56));
-  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_JPEG);
+  CaptureScreenshotAndCompareTo(expected_bitmap, ENCODING_JPEG, false);
 }
 
 // Setting frame size (through RWHV) is not supported on Android.
@@ -1414,6 +1416,121 @@
   EXPECT_EQ(transient_entry->GetSSL().certificate, last_shown_certificate());
 }
 
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, CertificateError) {
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+  https_server.ServeFilesFromSourceDirectory("content/test/data");
+  ASSERT_TRUE(https_server.Start());
+  GURL test_url = https_server.GetURL("/devtools/navigation.html");
+  std::unique_ptr<base::DictionaryValue> params;
+  std::unique_ptr<base::DictionaryValue> command_params;
+  int eventId;
+
+  shell()->LoadURL(GURL("about:blank"));
+  WaitForLoadStop(shell()->web_contents());
+
+  Attach();
+  SendCommand("Network.enable", nullptr, true);
+  SendCommand("Security.enable", nullptr, false);
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetBoolean("override", true);
+  SendCommand("Security.setOverrideCertificateErrors",
+              std::move(command_params), true);
+
+  // Test cancel.
+  SendCommand("Network.clearBrowserCache", nullptr, true);
+  SendCommand("Network.clearBrowserCookies", nullptr, true);
+  TestNavigationObserver cancel_observer(shell()->web_contents(), 1);
+  shell()->LoadURL(test_url);
+  params = WaitForNotification("Security.certificateError", false);
+  EXPECT_TRUE(shell()->web_contents()->GetController().GetPendingEntry());
+  EXPECT_EQ(
+      test_url,
+      shell()->web_contents()->GetController().GetPendingEntry()->GetURL());
+  EXPECT_TRUE(params->GetInteger("eventId", &eventId));
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetInteger("eventId", eventId);
+  command_params->SetString("action", "cancel");
+  SendCommand("Security.handleCertificateError", std::move(command_params),
+              false);
+  cancel_observer.Wait();
+  EXPECT_FALSE(shell()->web_contents()->GetController().GetPendingEntry());
+  EXPECT_EQ(GURL("about:blank"), shell()
+                                     ->web_contents()
+                                     ->GetController()
+                                     .GetLastCommittedEntry()
+                                     ->GetURL());
+
+  // Test continue.
+  SendCommand("Network.clearBrowserCache", nullptr, true);
+  SendCommand("Network.clearBrowserCookies", nullptr, true);
+  TestNavigationObserver continue_observer(shell()->web_contents(), 1);
+  shell()->LoadURL(test_url);
+  params = WaitForNotification("Security.certificateError", false);
+  EXPECT_TRUE(params->GetInteger("eventId", &eventId));
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetInteger("eventId", eventId);
+  command_params->SetString("action", "continue");
+  SendCommand("Security.handleCertificateError", std::move(command_params),
+              false);
+  WaitForNotification("Network.loadingFinished", true);
+  continue_observer.Wait();
+  EXPECT_EQ(test_url, shell()
+                          ->web_contents()
+                          ->GetController()
+                          .GetLastCommittedEntry()
+                          ->GetURL());
+}
+
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SubresourceWithCertificateError) {
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+  https_server.ServeFilesFromSourceDirectory("content/test/data/devtools");
+  ASSERT_TRUE(https_server.Start());
+  GURL test_url = https_server.GetURL("/image.html");
+  std::unique_ptr<base::DictionaryValue> params;
+  std::unique_ptr<base::DictionaryValue> command_params;
+  int eventId;
+
+  shell()->LoadURL(GURL("about:blank"));
+  WaitForLoadStop(shell()->web_contents());
+
+  Attach();
+  SendCommand("Security.enable", nullptr, false);
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetBoolean("override", true);
+  SendCommand("Security.setOverrideCertificateErrors",
+              std::move(command_params), true);
+
+  TestNavigationObserver observer(shell()->web_contents(), 1);
+  shell()->LoadURL(test_url);
+
+  // Expect certificateError event for main frame.
+  params = WaitForNotification("Security.certificateError", false);
+  EXPECT_TRUE(params->GetInteger("eventId", &eventId));
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetInteger("eventId", eventId);
+  command_params->SetString("action", "continue");
+  SendCommand("Security.handleCertificateError", std::move(command_params),
+              false);
+
+  // Expect certificateError event for image.
+  params = WaitForNotification("Security.certificateError", false);
+  EXPECT_TRUE(params->GetInteger("eventId", &eventId));
+  command_params.reset(new base::DictionaryValue());
+  command_params->SetInteger("eventId", eventId);
+  command_params->SetString("action", "continue");
+  SendCommand("Security.handleCertificateError", std::move(command_params),
+              false);
+
+  observer.Wait();
+  EXPECT_EQ(test_url, shell()
+                          ->web_contents()
+                          ->GetController()
+                          .GetLastCommittedEntry()
+                          ->GetURL());
+}
+
 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, TargetDiscovery) {
   std::string temp;
   std::set<std::string> ids;
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index 6b6808e..f3468b4 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -146,6 +146,32 @@
       Maybe<std::string>(security_style_explanations.summary));
 }
 
+void SecurityHandler::DidFinishNavigation(NavigationHandle* navigation_handle) {
+  if (certificate_errors_overriden_)
+    FlushPendingCertificateErrorNotifications();
+}
+
+void SecurityHandler::FlushPendingCertificateErrorNotifications() {
+  for (auto callback : cert_error_callbacks_)
+    callback.second.Run(content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
+  cert_error_callbacks_.clear();
+}
+
+bool SecurityHandler::NotifyCertificateError(int cert_error,
+                                             const GURL& request_url,
+                                             CertErrorCallback handler) {
+  if (!enabled_)
+    return false;
+  frontend_->CertificateError(++last_cert_error_id_,
+                              net::ErrorToShortString(cert_error),
+                              request_url.spec());
+  if (!certificate_errors_overriden_) {
+    return false;
+  }
+  cert_error_callbacks_[last_cert_error_id_] = handler;
+  return true;
+}
+
 Response SecurityHandler::Enable() {
   enabled_ = true;
   if (host_)
@@ -156,7 +182,9 @@
 
 Response SecurityHandler::Disable() {
   enabled_ = false;
+  certificate_errors_overriden_ = false;
   WebContentsObserver::Observe(nullptr);
+  FlushPendingCertificateErrorNotifications();
   return Response::OK();
 }
 
@@ -173,5 +201,36 @@
   return Response::OK();
 }
 
+Response SecurityHandler::HandleCertificateError(int event_id,
+                                                 const String& action) {
+  if (cert_error_callbacks_.find(event_id) == cert_error_callbacks_.end()) {
+    return Response::Error(
+        String("Unknown event id: " + std::to_string(event_id)));
+  }
+  content::CertificateRequestResultType type =
+      content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
+  Response response = Response::OK();
+  if (action == Security::CertificateErrorActionEnum::Continue) {
+    type = content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE;
+  } else if (action == Security::CertificateErrorActionEnum::Cancel) {
+    type = content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL;
+  } else {
+    response =
+        Response::Error(String("Unknown Certificate Error Action: " + action));
+  }
+  cert_error_callbacks_[event_id].Run(type);
+  cert_error_callbacks_.erase(event_id);
+  return response;
+}
+
+Response SecurityHandler::SetOverrideCertificateErrors(bool override) {
+  if (override && !enabled_)
+    return Response::Error("Security domain not enabled");
+  certificate_errors_overriden_ = override;
+  if (!override)
+    FlushPendingCertificateErrorNotifications();
+  return Response::OK();
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/security_handler.h b/content/browser/devtools/protocol/security_handler.h
index 136811a5..e9085699 100644
--- a/content/browser/devtools/protocol/security_handler.h
+++ b/content/browser/devtools/protocol/security_handler.h
@@ -5,9 +5,12 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
 
+#include <unordered_map>
+
 #include "base/macros.h"
 #include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/security.h"
+#include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
@@ -21,27 +24,48 @@
                         public Security::Backend,
                         public WebContentsObserver {
  public:
+  using CertErrorCallback =
+      base::Callback<void(content::CertificateRequestResultType)>;
+
   SecurityHandler();
   ~SecurityHandler() override;
 
+  static SecurityHandler* FromAgentHost(DevToolsAgentHostImpl* host);
+
+  // DevToolsDomainHandler overrides
   void Wire(UberDispatcher* dispatcher) override;
   void SetRenderFrameHost(RenderFrameHostImpl* host) override;
 
-  static SecurityHandler* FromAgentHost(DevToolsAgentHostImpl* host);
-
+  // Security::Backend overrides.
   Response Enable() override;
   Response Disable() override;
   Response ShowCertificateViewer() override;
+  Response HandleCertificateError(int event_id, const String& action) override;
+  Response SetOverrideCertificateErrors(bool override) override;
+
+  // NotifyCertificateError will send a CertificateError event. Returns true if
+  // the error is expected to be handled by a corresponding
+  // HandleCertificateError command, and false otherwise.
+  bool NotifyCertificateError(int cert_error,
+                              const GURL& request_url,
+                              CertErrorCallback callback);
 
  private:
+  using CertErrorCallbackMap = std::unordered_map<int, CertErrorCallback>;
+
   void AttachToRenderFrameHost();
+  void FlushPendingCertificateErrorNotifications();
 
   // WebContentsObserver overrides
   void DidChangeVisibleSecurityState() override;
+  void DidFinishNavigation(NavigationHandle* navigation_handle) override;
 
   std::unique_ptr<Security::Frontend> frontend_;
   bool enabled_;
   RenderFrameHostImpl* host_;
+  int last_cert_error_id_ = 0;
+  CertErrorCallbackMap cert_error_callbacks_;
+  bool certificate_errors_overriden_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(SecurityHandler);
 };
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 7c2a2063..399409d6 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -71,7 +71,7 @@
 
   FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
 
-  // DevTooolsAgentHost overrides.
+  // DevToolsAgentHost overrides.
   void DisconnectWebContents() override;
   void ConnectWebContents(WebContents* web_contents) override;
   BrowserContext* GetBrowserContext() override;
diff --git a/content/browser/pointer_lock_browsertest.cc b/content/browser/pointer_lock_browsertest.cc
index 07dd093..cf1a792e 100644
--- a/content/browser/pointer_lock_browsertest.cc
+++ b/content/browser/pointer_lock_browsertest.cc
@@ -272,4 +272,47 @@
   EXPECT_EQ(17, movementY);
 }
 
+// Flaky on Mac. See comment on https://codereview.chromium.org/2760343002.
+#if defined(OS_MACOSX)
+#define MAYBE_PointerLockChildFrameDetached \
+  DISABLED_PointerLockChildFrameDetached
+#else
+#define MAYBE_PointerLockChildFrameDetached PointerLockChildFrameDetached
+#endif
+// Tests that the browser will not unlock the pointer if a RenderWidgetHostView
+// that doesn't hold the pointer lock is destroyed.
+IN_PROC_BROWSER_TEST_F(PointerLockBrowserTest,
+                       MAYBE_PointerLockChildFrameDetached) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = web_contents()->GetFrameTree()->root();
+
+  // Request a pointer lock on the root frame's body.
+  EXPECT_TRUE(ExecuteScript(root, "document.body.requestPointerLock()"));
+
+  // Root frame should have been granted pointer lock.
+  bool locked = false;
+  EXPECT_TRUE(ExecuteScriptAndExtractBool(root,
+                                          "window.domAutomationController.send("
+                                          "document.pointerLockElement == "
+                                          "document.body);",
+                                          &locked));
+  EXPECT_TRUE(locked);
+
+  // Root (platform) RenderWidgetHostView should have the pointer locked.
+  EXPECT_TRUE(root->current_frame_host()->GetView()->IsMouseLocked());
+  EXPECT_EQ(root->current_frame_host()->GetRenderWidgetHost(),
+            web_contents()->GetMouseLockWidget());
+
+  // Detach the child frame.
+  EXPECT_TRUE(ExecuteScript(root, "document.querySelector('iframe').remove()"));
+
+  // Root (platform) RenderWidgetHostView should still have the pointer locked.
+  EXPECT_TRUE(root->current_frame_host()->GetView()->IsMouseLocked());
+  EXPECT_EQ(root->current_frame_host()->GetRenderWidgetHost(),
+            web_contents()->GetMouseLockWidget());
+}
+
 }  // namespace content
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc
index df2e757..c9341eb 100644
--- a/content/browser/ssl/ssl_manager.cc
+++ b/content/browser/ssl/ssl_manager.cc
@@ -11,6 +11,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/supports_user_data.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
+#include "content/browser/devtools/protocol/security_handler.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/loader/resource_request_info_impl.h"
@@ -20,6 +22,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/ssl_host_state_delegate.h"
 #include "net/url_request/url_request.h"
@@ -37,8 +40,17 @@
   SSL_GOOD_CERT_SEEN_EVENT_MAX = 2
 };
 
+void OnAllowCertificateWithRecordDecision(
+    bool record_decision,
+    const base::Callback<void(bool, content::CertificateRequestResultType)>&
+        callback,
+    CertificateRequestResultType decision) {
+  callback.Run(record_decision, decision);
+}
+
 void OnAllowCertificate(SSLErrorHandler* handler,
                         SSLHostStateDelegate* state_delegate,
+                        bool record_decision,
                         CertificateRequestResultType decision) {
   DCHECK(handler->ssl_info().is_valid());
   switch (decision) {
@@ -53,7 +65,7 @@
       // While AllowCert() executes synchronously on this thread,
       // ContinueRequest() gets posted to a different thread. Calling
       // AllowCert() first ensures deterministic ordering.
-      if (state_delegate) {
+      if (record_decision && state_delegate) {
         state_delegate->AllowCert(handler->request_url().host(),
                                   *handler->ssl_info().cert.get(),
                                   handler->cert_error());
@@ -356,11 +368,24 @@
   const net::SSLInfo& ssl_info = handler->ssl_info();
   const GURL& request_url = handler->request_url();
   ResourceType resource_type = handler->resource_type();
-  GetContentClient()->browser()->AllowCertificateError(
-      web_contents, cert_error, ssl_info, request_url, resource_type,
-      overridable, strict_enforcement, expired_previous_decision,
+
+  base::Callback<void(bool, content::CertificateRequestResultType)> callback =
       base::Bind(&OnAllowCertificate, base::Owned(handler.release()),
-                 ssl_host_state_delegate_));
+                 ssl_host_state_delegate_);
+
+  DevToolsAgentHostImpl* agent_host = static_cast<DevToolsAgentHostImpl*>(
+      DevToolsAgentHost::GetOrCreateFor(web_contents).get());
+  protocol::SecurityHandler* security_handler =
+      protocol::SecurityHandler::FromAgentHost(agent_host);
+  if (!security_handler ||
+      !security_handler->NotifyCertificateError(
+          cert_error, request_url,
+          base::Bind(&OnAllowCertificateWithRecordDecision, false, callback))) {
+    GetContentClient()->browser()->AllowCertificateError(
+        web_contents, cert_error, ssl_info, request_url, resource_type,
+        overridable, strict_enforcement, expired_previous_decision,
+        base::Bind(&OnAllowCertificateWithRecordDecision, true, callback));
+  }
 }
 
 void SSLManager::UpdateEntry(NavigationEntryImpl* entry,
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 093f1f22..b165369 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1739,7 +1739,7 @@
       view_->RestoreFocus();
   }
 
-  if (mouse_lock_widget_)
+  if (render_widget_host == mouse_lock_widget_)
     LostMouseLock(mouse_lock_widget_);
 }
 
diff --git a/content/common/service_worker/service_worker_utils_unittest.cc b/content/common/service_worker/service_worker_utils_unittest.cc
index 96564a2..f75f04c7 100644
--- a/content/common/service_worker/service_worker_utils_unittest.cc
+++ b/content/common/service_worker/service_worker_utils_unittest.cc
@@ -91,6 +91,10 @@
   // URLs canonicalize \ to / so this is equivalent to "...//x"
   ASSERT_TRUE(ServiceWorkerUtils::ScopeMatches(
       GURL("http://www.example.com/\\x"), GURL("http://www.example.com//x")));
+
+  // URLs that are in different origin shouldn't match.
+  ASSERT_FALSE(ServiceWorkerUtils::ScopeMatches(
+      GURL("https://evil.com"), GURL("https://evil.com.example.com")));
 }
 
 TEST(ServiceWorkerUtilsTest, FindLongestScopeMatch) {
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index f7dce75..ad87adc 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -60,6 +60,7 @@
     "//services/service_manager/public/interfaces:interfaces_java",
     "//services/service_manager/public/java:service_manager_java",
     "//services/shape_detection/public/interfaces:interfaces_java",
+    "//skia/public/interfaces:interfaces_java",
     "//third_party/WebKit/public:blink_headers_java",
     "//third_party/WebKit/public:mojo_bindings_java",
     "//third_party/android_tools:android_support_annotations_java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
index 17ff5506..50bc619 100644
--- a/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/FaceDetectionImpl.java
@@ -12,11 +12,10 @@
 import org.chromium.base.Log;
 import org.chromium.gfx.mojom.RectF;
 import org.chromium.mojo.system.MojoException;
-import org.chromium.mojo.system.SharedBufferHandle;
-import org.chromium.mojo.system.SharedBufferHandle.MapFlags;
 import org.chromium.shape_detection.mojom.FaceDetection;
 import org.chromium.shape_detection.mojom.FaceDetectionResult;
 import org.chromium.shape_detection.mojom.FaceDetectorOptions;
+import org.chromium.skia.mojom.ColorType;
 
 import java.nio.ByteBuffer;
 
@@ -36,29 +35,42 @@
     }
 
     @Override
-    public void detect(
-            SharedBufferHandle frameData, int width, int height, DetectResponse callback) {
+    public void detect(org.chromium.skia.mojom.Bitmap bitmapData, DetectResponse callback) {
+        int width = bitmapData.width;
+        int height = bitmapData.height;
         final long numPixels = (long) width * height;
         // TODO(xianglu): https://crbug.com/670028 homogeneize overflow checking.
-        if (!frameData.isValid() || width <= 0 || height <= 0 || numPixels > (Long.MAX_VALUE / 4)) {
+        if (bitmapData.pixelData == null || width <= 0 || height <= 0
+                || numPixels > (Long.MAX_VALUE / 4)) {
             Log.d(TAG, "Invalid argument(s).");
             callback.call(new FaceDetectionResult());
             return;
         }
 
-        ByteBuffer imageBuffer = frameData.map(0, numPixels * 4, MapFlags.none());
-        if (imageBuffer.capacity() <= 0) {
-            Log.d(TAG, "Failed to map from SharedBufferHandle.");
+        // TODO(junwei.fu): Consider supporting other bitmap pixel formats,
+        // https://crbug.com/684921.
+        if (bitmapData.colorType != ColorType.RGBA_8888
+                && bitmapData.colorType != ColorType.BGRA_8888) {
+            Log.e(TAG, "Unsupported bitmap pixel format");
             callback.call(new FaceDetectionResult());
             return;
         }
 
+        ByteBuffer imageBuffer = ByteBuffer.wrap(bitmapData.pixelData);
+        if (imageBuffer.capacity() <= 0) {
+            Log.d(TAG, "Failed to wrap from Bitmap.");
+            callback.call(new FaceDetectionResult());
+            return;
+        }
+
+        // TODO(junwei.fu): Use |bitmapData| directly for |unPremultipliedBitmap| to spare a copy
+        // if the bitmap pixel format is RGB_565, the ARGB_8888 Bitmap doesn't need to be created
+        // in this case, https://crbug.com/684930.
         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 
         // An int array is needed to construct a Bitmap. However the Bytebuffer
-        // we get from |sharedBufferHandle| is directly allocated and does not
-        // have a supporting array. Therefore we need to copy from |imageBuffer|
-        // to create this intermediate Bitmap.
+        // we get from |bitmapData| is directly allocated and does not have a supporting array.
+        // Therefore we need to copy from |imageBuffer| to create this intermediate Bitmap.
         // TODO(xianglu): Consider worker pool as appropriate threads.
         // http://crbug.com/655814
         bitmap.copyPixelsFromBuffer(imageBuffer);
diff --git a/content/test/data/devtools/image.html b/content/test/data/devtools/image.html
new file mode 100644
index 0000000..19e6ef61
--- /dev/null
+++ b/content/test/data/devtools/image.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+Image page.
+<img src="test.jpg">
+</body>
+</html>
diff --git a/content/test/data/devtools/test.jpg b/content/test/data/devtools/test.jpg
new file mode 100644
index 0000000..be004c9
--- /dev/null
+++ b/content/test/data/devtools/test.jpg
Binary files differ
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc
index e305b4ce..e35a3af 100644
--- a/courgette/disassembler_elf_32.cc
+++ b/courgette/disassembler_elf_32.cc
@@ -181,13 +181,6 @@
     return false;
   }
 
-  // Finally sort rel32 locations.
-  std::sort(rel32_locations_.begin(),
-            rel32_locations_.end(),
-            TypedRVA::IsLessThanByRVA);
-  DCHECK(rel32_locations_.empty() ||
-         rel32_locations_.back()->rva() != kUnassignedRVA);
-
   program->DefaultAssignIndexes();
   return true;
 }
@@ -384,6 +377,11 @@
   if (!found_rel32)
     VLOG(1) << "Warning: Found no rel32 addresses. Missing .text section?";
 
+  std::sort(rel32_locations_.begin(), rel32_locations_.end(),
+            TypedRVA::IsLessThanByRVA);
+  DCHECK(rel32_locations_.empty() ||
+         rel32_locations_.back()->rva() != kUnassignedRVA);
+
   return true;
 }
 
@@ -418,15 +416,18 @@
   // Walk all the bytes in the file, whether or not in a section.
   FileOffset file_offset = 0;
 
-  std::vector<FileOffset> abs_offsets;
-
   // File parsing follows file offset order, and we visit abs32 and rel32
   // locations in lockstep. Therefore we need to extract and sort file offsets
-  // of all abs32 and rel32 locations.
+  // of all abs32 and rel32 locations. For abs32, we copy the offsets to a new
+  // array.
+  std::vector<FileOffset> abs_offsets;
   if (!RVAsToFileOffsets(abs32_locations_, &abs_offsets))
     return false;
-  std::sort(abs32_locations_.begin(), abs32_locations_.end());
+  std::sort(abs_offsets.begin(), abs_offsets.end());
 
+  // For rel32, TypedRVA (rather than raw offset) is stored, so sort-by-offset
+  // is performed in place to save memory. At the end of function we will
+  // sort-by-RVA.
   if (!RVAsToFileOffsets(&rel32_locations_))
     return false;
   std::sort(rel32_locations_.begin(),
@@ -496,6 +497,10 @@
   if (!ParseSimpleRegion(file_offset, length(), receptor))
     return false;
 
+  // Restore original rel32 location order and sort by RVA order.
+  std::sort(rel32_locations_.begin(), rel32_locations_.end(),
+            TypedRVA::IsLessThanByRVA);
+
   // Make certain we consume all of the relocations as expected
   return (current_abs_offset == end_abs_offset);
 }
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm
index f33d7929..667bbd6 100644
--- a/device/bluetooth/bluetooth_adapter_mac.mm
+++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -519,14 +519,16 @@
   // otherwise update the existing device.
   const bool is_new_device = device_mac == nullptr;
   if (is_new_device) {
-    VLOG(1) << "LowEnergyDeviceUpdated new device";
     // A new device has been found.
     device_mac = new BluetoothLowEnergyDeviceMac(this, peripheral);
+    VLOG(1) << *device_mac << ": New Device.";
   } else if (DoesCollideWithKnownDevice(peripheral, device_mac)) {
     return;
   }
 
   DCHECK(device_mac);
+  VLOG(3) << *device_mac << ": Device updated with "
+          << base::SysNSStringToUTF8([advertisement_data description]);
 
   // Get Advertised UUIDs
   BluetoothDevice::UUIDList advertised_uuids;
@@ -576,7 +578,10 @@
 }
 
 // TODO(krstnmnlsn): Implement. crbug.com/511025
-void BluetoothAdapterMac::LowEnergyCentralManagerUpdatedState() {}
+void BluetoothAdapterMac::LowEnergyCentralManagerUpdatedState() {
+  VLOG(1) << "Central manager state updated: "
+          << [low_energy_central_manager_ state];
+}
 
 void BluetoothAdapterMac::AddPairedDevices() {
   // Add any new paired devices.
@@ -594,6 +599,7 @@
     const BluetoothUUID* uuid) {
   NSArray* cbUUIDs = nil;
   if (!uuid) {
+    VLOG(1) << "Retrieving all connected devices.";
     // It is not possible to ask for all connected peripherals with
     // -[CBCentralManager retrieveConnectedPeripheralsWithServices:] by passing
     // nil. To try to get most of the peripherals, the search is done with
@@ -601,6 +607,8 @@
     CBUUID* genericAccessServiceUUID = [CBUUID UUIDWithString:@"1800"];
     cbUUIDs = @[ genericAccessServiceUUID ];
   } else {
+    VLOG(1) << "Retrieving connected devices with UUID: "
+            << uuid->canonical_value();
     NSString* uuidString =
         base::SysUTF8ToNSString(uuid->canonical_value().c_str());
     cbUUIDs = @[ [CBUUID UUIDWithString:uuidString] ];
@@ -626,6 +634,7 @@
       }
     }
     connected_devices.push_back(device_mac);
+    VLOG(1) << *device_mac << ": New connected device.";
   }
   return connected_devices;
 }
@@ -661,15 +670,15 @@
     [low_energy_central_manager_ cancelPeripheralConnection:peripheral];
     return;
   }
-  VLOG(1) << "Failed to connect to peripheral";
   BluetoothDevice::ConnectErrorCode error_code =
       BluetoothDevice::ConnectErrorCode::ERROR_UNKNOWN;
   if (error) {
     error_code = BluetoothDeviceMac::GetConnectErrorCodeFromNSError(error);
-    VLOG(1) << "Bluetooth error, domain: " << error.domain.UTF8String
-            << ", error code: " << error.code
-            << ", converted into: " << error_code;
+    VLOG(1) << "Converting Bluetooth error, domain: " << error.domain.UTF8String
+            << ", error code: " << error.code << ", to: " << error_code;
   }
+  VLOG(1) << *device_mac << ": Failed to connect to peripheral with error "
+          << error;
   device_mac->DidFailToConnectGatt(error_code);
 }
 
@@ -681,11 +690,6 @@
     [low_energy_central_manager_ cancelPeripheralConnection:peripheral];
     return;
   }
-  VLOG(1) << "Disconnected from peripheral.";
-  if (error) {
-    VLOG(1) << "Bluetooth error, domain: " << error.domain.UTF8String
-            << ", error code: " << error.code;
-  }
   device_mac->DidDisconnectPeripheral(error);
 }
 
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.h b/device/bluetooth/bluetooth_low_energy_device_mac.h
index b25bfff5..0b1aafd 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.h
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.h
@@ -151,6 +151,11 @@
   DISALLOW_COPY_AND_ASSIGN(BluetoothLowEnergyDeviceMac);
 };
 
+// Stream operator for logging.
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothLowEnergyDeviceMac& device);
+
 }  // namespace device
 
 #endif  // DEVICE_BLUETOOTH_BLUETOOTH_LOW_ENERGY_DEVICE_MAC_H_
diff --git a/device/bluetooth/bluetooth_low_energy_device_mac.mm b/device/bluetooth/bluetooth_low_energy_device_mac.mm
index 6fa8927..4693e3f 100644
--- a/device/bluetooth/bluetooth_low_energy_device_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_device_mac.mm
@@ -176,11 +176,13 @@
 
 void BluetoothLowEnergyDeviceMac::CreateGattConnectionImpl() {
   if (!IsGattConnected()) {
+    VLOG(1) << *this << ": CreateGattConnection.";
     GetMacAdapter()->CreateGattConnection(this);
   }
 }
 
 void BluetoothLowEnergyDeviceMac::DisconnectGatt() {
+  VLOG(1) << *this << ": Disconnect.";
   GetMacAdapter()->DisconnectGatt(this);
 }
 
@@ -189,7 +191,7 @@
   if (discovery_pending_count_ < 0) {
     // This should never happens, just in case it happens with a device,
     // discovery_pending_count_ is set back to 0.
-    VLOG(1) << GetName()->c_str()
+    VLOG(1) << *this
             << ": BluetoothLowEnergyDeviceMac::discovery_pending_count_ "
             << discovery_pending_count_;
     discovery_pending_count_ = 0;
@@ -199,18 +201,19 @@
     // TODO(http://crbug.com/609320): Need to pass the error.
     // TODO(http://crbug.com/609844): Decide what to do if discover failed
     // a device services.
-    VLOG(1) << "Can't discover primary services: "
+    VLOG(1) << *this << ": Can't discover primary services: "
             << error.localizedDescription.UTF8String << " (" << error.domain
-            << ": " << error.code << ")";
+            << ": " << error.code << ").";
     return;
   }
-  VLOG(1) << "DidDiscoverPrimaryServices, pending count: "
-          << discovery_pending_count_;
 
   if (!IsGattConnected()) {
     // Don't create services if the device disconnected.
+    VLOG(1) << *this << ": DidDiscoverPrimaryServices, gatt not connected.";
     return;
   }
+  VLOG(1) << *this << ": DidDiscoverPrimaryServices, pending count: "
+          << discovery_pending_count_;
 
   for (CBService* cb_service in GetPeripheral().services) {
     BluetoothRemoteGattServiceMac* gatt_service =
@@ -221,7 +224,10 @@
       auto result_iter = gatt_services_.insert(std::make_pair(
           gatt_service->GetIdentifier(), base::WrapUnique(gatt_service)));
       DCHECK(result_iter.second);
+      VLOG(1) << *gatt_service << ": New service.";
       adapter_->NotifyGattServiceAdded(gatt_service);
+    } else {
+      VLOG(1) << *gatt_service << ": Known service.";
     }
   }
   if (discovery_pending_count_ == 0) {
@@ -241,14 +247,14 @@
   if (error) {
     // TODO(http://crbug.com/609320): Need to pass the error.
     // TODO(http://crbug.com/609844): Decide what to do if discover failed
-    VLOG(1) << "Can't discover characteristics: "
+    VLOG(1) << *this << ": Can't discover characteristics: "
             << error.localizedDescription.UTF8String << " (" << error.domain
-            << ": " << error.code << ")";
+            << ": " << error.code << ").";
     return;
   }
-  VLOG(1) << "DidDiscoverCharacteristics.";
 
   if (!IsGattConnected()) {
+    VLOG(1) << *this << ": DidDiscoverCharacteristics, gatt disconnected.";
     // Don't create characteristics if the device disconnected.
     return;
   }
@@ -262,7 +268,9 @@
 
 void BluetoothLowEnergyDeviceMac::DidModifyServices(
     NSArray* invalidatedServices) {
-  VLOG(1) << "DidModifyServices: ";
+  VLOG(1) << *this << ": DidModifyServices: "
+          << " invalidated services "
+          << base::SysNSStringToUTF8([invalidatedServices description]);
   for (CBService* cb_service in invalidatedServices) {
     BluetoothRemoteGattServiceMac* gatt_service =
         GetBluetoothRemoteGattService(cb_service);
@@ -282,7 +290,6 @@
 void BluetoothLowEnergyDeviceMac::DidUpdateValue(
     CBCharacteristic* characteristic,
     NSError* error) {
-  VLOG(1) << "DidUpdateValue.";
   BluetoothRemoteGattServiceMac* gatt_service =
       GetBluetoothRemoteGattService(characteristic.service);
   DCHECK(gatt_service);
@@ -292,7 +299,6 @@
 void BluetoothLowEnergyDeviceMac::DidWriteValue(
     CBCharacteristic* characteristic,
     NSError* error) {
-  VLOG(1) << "DidWriteValue.";
   BluetoothRemoteGattServiceMac* gatt_service =
       GetBluetoothRemoteGattService(characteristic.service);
   DCHECK(gatt_service);
@@ -302,7 +308,6 @@
 void BluetoothLowEnergyDeviceMac::DidUpdateNotificationState(
     CBCharacteristic* characteristic,
     NSError* error) {
-  VLOG(1) << "DidUpdateNotificationState";
   BluetoothRemoteGattServiceMac* gatt_service =
       GetBluetoothRemoteGattService(characteristic.service);
   DCHECK(gatt_service);
@@ -315,13 +320,13 @@
   if (error) {
     // TODO(http://crbug.com/609320): Need to pass the error.
     // TODO(http://crbug.com/609844): Decide what to do if discover failed
-    VLOG(1) << "Can't discover descriptors: "
+    VLOG(1) << *this << ": Can't discover descriptors: "
             << error.localizedDescription.UTF8String << " (" << error.domain
-            << ": " << error.code << ")";
+            << ": " << error.code << ").";
     return;
   }
-  VLOG(1) << "DidDiscoverDescriptors.";
   if (!IsGattConnected()) {
+    VLOG(1) << *this << ": DidDiscoverDescriptors, disconnected.";
     // Don't discover descriptors if the device disconnected.
     return;
   }
@@ -353,7 +358,8 @@
 }
 
 void BluetoothLowEnergyDeviceMac::DiscoverPrimaryServices() {
-  VLOG(1) << "DidDiscoverDescriptors pending count" << discovery_pending_count_;
+  VLOG(1) << *this << ": DiscoverPrimaryServices, pending count "
+          << discovery_pending_count_;
   ++discovery_pending_count_;
   [GetPeripheral() discoverServices:nil];
 }
@@ -370,6 +376,7 @@
                 ->IsDiscoveryComplete();
           }) == gatt_services_.end();
   if (discovery_complete) {
+    VLOG(1) << *this << ": Discovery complete.";
     device_uuids_.ReplaceServiceUUIDs(gatt_services_);
     SetGattServicesDiscoveryComplete(true);
     adapter_->NotifyGattServicesDiscovered(this);
@@ -399,6 +406,11 @@
 }
 
 void BluetoothLowEnergyDeviceMac::DidDisconnectPeripheral(NSError* error) {
+  VLOG(1) << *this << ": Disconnected from peripheral.";
+  if (error) {
+    VLOG(1) << *this << ": Bluetooth error, domain: " << error.domain.UTF8String
+            << ", error code: " << error.code;
+  }
   SetGattServicesDiscoveryComplete(false);
   // Removing all services at once to ensure that calling GetGattService on
   // removed service in GattServiceRemoved returns null.
@@ -419,3 +431,16 @@
   // TODO(http://crbug.com/585897): Need to pass the error.
   DidFailToConnectGatt(BluetoothDevice::ConnectErrorCode::ERROR_FAILED);
 }
+
+namespace device {
+
+std::ostream& operator<<(std::ostream& out,
+                         const BluetoothLowEnergyDeviceMac& device) {
+  // TODO(crbug.com/703878): Should use
+  // BluetoothLowEnergyDeviceMac::GetNameForDisplay() instead.
+  base::Optional<std::string> name = device.GetName();
+  const char* name_cstr = name ? name->c_str() : "";
+  return out << "<BluetoothLowEnergyDeviceMac " << device.GetAddress() << "/"
+             << &device << ", \"" << name_cstr << "\">";
+}
+}  // namespace device
diff --git a/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm b/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
index f4f13ee..609186b 100644
--- a/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
+++ b/device/bluetooth/bluetooth_low_energy_discovery_manager_mac.mm
@@ -93,7 +93,6 @@
     CBPeripheral* peripheral,
     NSDictionary* advertisementData,
     int rssi) {
-  VLOG(3) << "DiscoveredPeripheral";
   observer_->LowEnergyDeviceUpdated(peripheral, advertisementData, rssi);
 }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
index 4b628c6..229daff6 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
@@ -135,6 +135,11 @@
       gatt_descriptor_macs_;
 };
 
+// Stream operator for logging.
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattCharacteristicMac& characteristic);
+
 }  // namespace device
 
 #endif  // DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_MAC_H_
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
index 2e2da4e6..0e860b5 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -152,6 +152,7 @@
     const ValueCallback& callback,
     const ErrorCallback& error_callback) {
   if (!IsReadable()) {
+    VLOG(1) << *this << ": Characteristic not readable.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback,
@@ -159,12 +160,14 @@
     return;
   }
   if (characteristic_value_read_or_write_in_progress_) {
+    VLOG(1) << *this << ": Characteristic read already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback,
                    BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
+  VLOG(1) << *this << ": Read characteristic.";
   characteristic_value_read_or_write_in_progress_ = true;
   read_characteristic_value_callbacks_ =
       std::make_pair(callback, error_callback);
@@ -176,6 +179,7 @@
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
   if (!IsWritable()) {
+    VLOG(1) << *this << ": Characteristic not writable.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback,
@@ -183,12 +187,14 @@
     return;
   }
   if (characteristic_value_read_or_write_in_progress_) {
+    VLOG(1) << *this << ": Characteristic write already in progress.";
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
         base::Bind(error_callback,
                    BluetoothRemoteGattService::GATT_ERROR_IN_PROGRESS));
     return;
   }
+  VLOG(1) << *this << ": Write characteristic.";
   characteristic_value_read_or_write_in_progress_ = true;
   write_characteristic_value_callbacks_ =
       std::make_pair(callback, error_callback);
@@ -210,6 +216,7 @@
     BluetoothRemoteGattDescriptor* ccc_descriptor,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
+  VLOG(1) << *this << ": Subscribe to characteristic.";
   DCHECK(subscribe_to_notification_callbacks_.first.is_null());
   DCHECK(subscribe_to_notification_callbacks_.second.is_null());
   DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
@@ -224,6 +231,7 @@
     BluetoothRemoteGattDescriptor* ccc_descriptor,
     const base::Closure& callback,
     const ErrorCallback& error_callback) {
+  VLOG(1) << *this << ": Unsubscribe from characteristic.";
   DCHECK(subscribe_to_notification_callbacks_.first.is_null());
   DCHECK(subscribe_to_notification_callbacks_.second.is_null());
   DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
@@ -235,6 +243,7 @@
 }
 
 void BluetoothRemoteGattCharacteristicMac::DiscoverDescriptors() {
+  VLOG(1) << *this << ": Discover descriptors.";
   is_discovery_complete_ = false;
   [GetCBPeripheral()
       discoverDescriptorsForCharacteristic:cb_characteristic_.get()];
@@ -249,7 +258,8 @@
     callbacks.swap(read_characteristic_value_callbacks_);
     characteristic_value_read_or_write_in_progress_ = false;
     if (error) {
-      VLOG(1) << "Bluetooth error while reading for characteristic, domain: "
+      VLOG(1) << *this
+              << ": Bluetooth error while reading for characteristic, domain: "
               << base::SysNSStringToUTF8(error.domain)
               << ", error code: " << error.code;
       BluetoothGattService::GattErrorCode error_code =
@@ -257,17 +267,21 @@
       callbacks.second.Run(error_code);
       return;
     }
+    VLOG(1) << *this << ": Read request arrived.";
     UpdateValue();
     callbacks.first.Run(value_);
   } else if (IsNotifying()) {
+    VLOG(1) << *this << ": Notification arrived.";
     UpdateValue();
     gatt_service_->GetMacAdapter()->NotifyGattCharacteristicValueChanged(
         this, value_);
   } else {
     // In case of buggy device, nothing should be done if receiving extra
     // read confirmation.
-    VLOG(1) << "Characteristic value updated while having no pending read nor "
-               "notification.";
+    VLOG(1)
+        << *this
+        << ": Characteristic value updated while having no pending read nor "
+           "notification.";
   }
 }
 
@@ -282,14 +296,16 @@
   if (!characteristic_value_read_or_write_in_progress_) {
     // In case of buggy device, nothing should be done if receiving extra
     // write confirmation.
-    VLOG(1) << "Write notification while no write operation pending.";
+    VLOG(1) << *this
+            << ": Write notification while no write operation pending.";
     return;
   }
   std::pair<base::Closure, ErrorCallback> callbacks;
   callbacks.swap(write_characteristic_value_callbacks_);
   characteristic_value_read_or_write_in_progress_ = false;
   if (error) {
-    VLOG(1) << "Bluetooth error while writing for characteristic, domain: "
+    VLOG(1) << *this
+            << ": Bluetooth error while writing for characteristic, domain: "
             << base::SysNSStringToUTF8(error.domain)
             << ", error code: " << error.code;
     BluetoothGattService::GattErrorCode error_code =
@@ -297,6 +313,7 @@
     callbacks.second.Run(error_code);
     return;
   }
+  VLOG(1) << *this << ": Write value succeeded.";
   callbacks.first.Run();
 }
 
@@ -310,12 +327,12 @@
     DCHECK(![GetCBCharacteristic() isNotifying] || error);
     reentrant_safe_callbacks.swap(unsubscribe_from_notification_callbacks_);
   } else {
-    VLOG(1) << "No pending notification update for characteristic "
-            << GetUUID().value();
+    VLOG(1) << *this << ": No pending notification update for characteristic.";
     return;
   }
   if (error) {
-    VLOG(1) << "Bluetooth error while modifying notification state for "
+    VLOG(1) << *this
+            << ": Bluetooth error while modifying notification state for "
                "characteristic, domain: "
             << base::SysNSStringToUTF8(error.domain)
             << ", error code: " << error.code << ", localized description: "
@@ -330,6 +347,7 @@
 
 void BluetoothRemoteGattCharacteristicMac::DidDiscoverDescriptors() {
   DCHECK(!is_discovery_complete_);
+  VLOG(1) << *this << ": Did discover descriptors.";
   std::unordered_set<std::string> descriptor_identifier_to_remove;
   for (const auto& iter : gatt_descriptor_macs_) {
     descriptor_identifier_to_remove.insert(iter.first);
@@ -339,6 +357,7 @@
     BluetoothRemoteGattDescriptorMac* gatt_descriptor_mac =
         GetBluetoothRemoteGattDescriptorMac(cb_descriptor);
     if (gatt_descriptor_mac) {
+      VLOG(1) << *gatt_descriptor_mac << ": Known descriptor.";
       const std::string& identifier = gatt_descriptor_mac->GetIdentifier();
       descriptor_identifier_to_remove.erase(identifier);
       continue;
@@ -350,11 +369,13 @@
         {identifier, base::WrapUnique(gatt_descriptor_mac)});
     DCHECK(result_iter.second);
     GetMacAdapter()->NotifyGattDescriptorAdded(gatt_descriptor_mac);
+    VLOG(1) << *gatt_descriptor_mac << ": New descriptor.";
   }
 
   for (const std::string& identifier : descriptor_identifier_to_remove) {
     auto pair_to_remove = gatt_descriptor_macs_.find(identifier);
     std::unique_ptr<BluetoothRemoteGattDescriptorMac> descriptor_to_remove;
+    VLOG(1) << *descriptor_to_remove << ": Removed descriptor.";
     pair_to_remove->second.swap(descriptor_to_remove);
     gatt_descriptor_macs_.erase(pair_to_remove);
     GetMacAdapter()->NotifyGattDescriptorRemoved(descriptor_to_remove.get());
@@ -420,4 +441,17 @@
     return found->second.get();
   }
 }
+
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattCharacteristicMac& characteristic) {
+  const BluetoothRemoteGattServiceMac* service_mac =
+      static_cast<const BluetoothRemoteGattServiceMac*>(
+          characteristic.GetService());
+  return out << "<BluetoothRemoteGattCharacteristicMac "
+             << characteristic.GetUUID().canonical_value() << "/"
+             << &characteristic
+             << ", service: " << service_mac->GetUUID().canonical_value() << "/"
+             << service_mac << ">";
+}
 }  // namespace device.
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h
index 9749322..60d4062 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.h
@@ -60,6 +60,11 @@
   std::vector<uint8_t> value_;
 };
 
+// Stream operator for logging.
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattDescriptorMac& descriptor);
+
 }  // namespace device
 
 #endif  // DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_CHARACTERISTIC_MAC_H_
diff --git a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
index d867349ab..76cda0c 100644
--- a/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_descriptor_mac.mm
@@ -74,4 +74,17 @@
   return cb_descriptor_.get();
 }
 
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattDescriptorMac& descriptor) {
+  const BluetoothRemoteGattCharacteristicMac* characteristic_mac =
+      static_cast<const BluetoothRemoteGattCharacteristicMac*>(
+          descriptor.GetCharacteristic());
+  return out << "<BluetoothRemoteGattServiceMac "
+             << descriptor.GetUUID().canonical_value() << "/" << &descriptor
+             << ", characteristic: "
+             << characteristic_mac->GetUUID().canonical_value() << "/"
+             << characteristic_mac << ">";
+}
+
 }  // namespace device.
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_mac.h b/device/bluetooth/bluetooth_remote_gatt_service_mac.h
index 60d1f110..1c5d1c8 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_mac.h
+++ b/device/bluetooth/bluetooth_remote_gatt_service_mac.h
@@ -102,6 +102,11 @@
   DISALLOW_COPY_AND_ASSIGN(BluetoothRemoteGattServiceMac);
 };
 
+// Stream operator for logging.
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattServiceMac& service);
+
 }  // namespace device
 
 #endif  // DEVICE_BLUETOOTH_BLUETOOTH_REMOTE_GATT_SERVICE_MAC_H_
diff --git a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
index 505321e..5d2b736 100644
--- a/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_service_mac.mm
@@ -78,12 +78,14 @@
 }
 
 void BluetoothRemoteGattServiceMac::DiscoverCharacteristics() {
+  VLOG(1) << *this << ": DiscoverCharacteristics.";
   is_discovery_complete_ = false;
   [GetCBPeripheral() discoverCharacteristics:nil forService:GetService()];
 }
 
 void BluetoothRemoteGattServiceMac::DidDiscoverCharacteristics() {
   DCHECK(!is_discovery_complete_);
+  VLOG(1) << *this << ": DidDiscoverCharacteristics.";
   std::unordered_set<std::string> characteristic_identifier_to_remove;
   for (const auto& iter : gatt_characteristic_macs_) {
     characteristic_identifier_to_remove.insert(iter.first);
@@ -93,6 +95,9 @@
     BluetoothRemoteGattCharacteristicMac* gatt_characteristic_mac =
         GetBluetoothRemoteGattCharacteristicMac(cb_characteristic);
     if (gatt_characteristic_mac) {
+      VLOG(1) << *gatt_characteristic_mac
+              << ": Known characteristic, properties "
+              << gatt_characteristic_mac->GetProperties();
       const std::string& identifier = gatt_characteristic_mac->GetIdentifier();
       characteristic_identifier_to_remove.erase(identifier);
       gatt_characteristic_mac->DiscoverDescriptors();
@@ -104,6 +109,8 @@
     auto result_iter = gatt_characteristic_macs_.insert(
         {identifier, base::WrapUnique(gatt_characteristic_mac)});
     DCHECK(result_iter.second);
+    VLOG(1) << *gatt_characteristic_mac << ": New characteristic, properties "
+            << gatt_characteristic_mac->GetProperties();
     gatt_characteristic_mac->DiscoverDescriptors();
     GetMacAdapter()->NotifyGattCharacteristicAdded(gatt_characteristic_mac);
   }
@@ -113,6 +120,7 @@
     std::unique_ptr<BluetoothRemoteGattCharacteristicMac>
         characteristic_to_remove;
     pair_to_remove->second.swap(characteristic_to_remove);
+    VLOG(1) << *characteristic_to_remove << ": Removed characteristic.";
     gatt_characteristic_macs_.erase(pair_to_remove);
     GetMacAdapter()->NotifyGattCharacteristicRemoved(
         characteristic_to_remove.get());
@@ -142,6 +150,7 @@
             return pair.second->IsDiscoveryComplete();
           }) == gatt_characteristic_macs_.end();
   if (is_discovery_complete_) {
+    VLOG(1) << *this << ": Discovery complete.";
     GetMacAdapter()->NotifyGattServiceChanged(this);
   }
 }
@@ -207,4 +216,15 @@
   }
 }
 
+DEVICE_BLUETOOTH_EXPORT std::ostream& operator<<(
+    std::ostream& out,
+    const BluetoothRemoteGattServiceMac& service) {
+  const BluetoothLowEnergyDeviceMac* bluetooth_device_mac_ =
+      static_cast<const BluetoothLowEnergyDeviceMac*>(service.GetDevice());
+  return out << "<BluetoothRemoteGattServiceMac "
+             << service.GetUUID().canonical_value() << "/" << &service
+             << ", device: " << bluetooth_device_mac_->GetAddress() << "/"
+             << bluetooth_device_mac_ << ">";
+}
+
 }  // namespace device
diff --git a/extensions/browser/api/runtime/runtime_apitest.cc b/extensions/browser/api/runtime/runtime_apitest.cc
index 5c65d3d0..1bb7850 100644
--- a/extensions/browser/api/runtime/runtime_apitest.cc
+++ b/extensions/browser/api/runtime/runtime_apitest.cc
@@ -7,11 +7,10 @@
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/test_extension_dir.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/notification_service.h"
 #include "extensions/browser/api/runtime/runtime_api.h"
 #include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_registry.h"
-#include "extensions/browser/notification_types.h"
+#include "extensions/browser/test_extension_registry_observer.h"
 #include "extensions/test/result_catcher.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -106,22 +105,21 @@
   // to reload itself that often without being terminated, the test fails
   // anyway.
   for (int i = 0; i < 30; i++) {
-    content::WindowedNotificationObserver unload_observer(
-        extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
-        content::NotificationService::AllSources());
-    content::WindowedNotificationObserver load_observer(
-        extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
-        content::NotificationService::AllSources());
-
+    TestExtensionRegistryObserver unload_observer(registry, extension_id);
+    TestExtensionRegistryObserver load_observer(registry, extension_id);
     ASSERT_TRUE(ExecuteScriptInBackgroundPageNoWait(
         extension_id, "chrome.runtime.reload();"));
-    unload_observer.Wait();
+    unload_observer.WaitForExtensionUnloaded();
+    base::RunLoop().RunUntilIdle();
 
     if (registry->GetExtensionById(extension_id,
                                    ExtensionRegistry::TERMINATED)) {
       break;
     } else {
-      load_observer.Wait();
+      load_observer.WaitForExtensionLoaded();
+      // We need to let other registry observers handle the notification to
+      // finish initialization
+      base::RunLoop().RunUntilIdle();
       WaitForExtensionViewsToLoad();
     }
   }
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index 603acdc..b5114bd 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -388,5 +388,6 @@
 #define glSwapBuffersWithBoundsCHROMIUM \
   GLES2_GET_FUN(SwapBuffersWithBoundsCHROMIUM)
 #define glSetDrawRectangleCHROMIUM GLES2_GET_FUN(SetDrawRectangleCHROMIUM)
+#define glSetEnableDCLayersCHROMIUM GLES2_GET_FUN(SetEnableDCLayersCHROMIUM)
 
 #endif  // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index e5a13b1..d3836079 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -4548,6 +4548,10 @@
     'decoder_func': 'DoSetDrawRectangleCHROMIUM',
     'extension': 'CHROMIUM_set_draw_rectangle',
   },
+  'SetEnableDCLayersCHROMIUM': {
+    'decoder_func': 'DoSetEnableDCLayersCHROMIUM',
+    'extension': 'CHROMIUM_dc_layers',
+  },
 }
 
 
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index d8b3a2e..5940339 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1745,6 +1745,9 @@
                                                GLint height) {
   gles2::GetGLContext()->SetDrawRectangleCHROMIUM(x, y, width, height);
 }
+void GL_APIENTRY GLES2SetEnableDCLayersCHROMIUM(GLboolean enabled) {
+  gles2::GetGLContext()->SetEnableDCLayersCHROMIUM(enabled);
+}
 
 namespace gles2 {
 
@@ -3061,6 +3064,10 @@
         reinterpret_cast<GLES2FunctionPointer>(glSetDrawRectangleCHROMIUM),
     },
     {
+        "glSetEnableDCLayersCHROMIUM",
+        reinterpret_cast<GLES2FunctionPointer>(glSetEnableDCLayersCHROMIUM),
+    },
+    {
         NULL, NULL,
     },
 };
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index b3cba3c..5ff6a5f 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3230,4 +3230,12 @@
   }
 }
 
+void SetEnableDCLayersCHROMIUM(GLboolean enabled) {
+  gles2::cmds::SetEnableDCLayersCHROMIUM* c =
+      GetCmdSpace<gles2::cmds::SetEnableDCLayersCHROMIUM>();
+  if (c) {
+    c->Init(enabled);
+  }
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 7107004..47bea0c 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1225,4 +1225,6 @@
                               GLint width,
                               GLint height) override;
 
+void SetEnableDCLayersCHROMIUM(GLboolean enabled) override;
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 73a9676..562b12f 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3524,4 +3524,12 @@
   CheckGLError();
 }
 
+void GLES2Implementation::SetEnableDCLayersCHROMIUM(GLboolean enabled) {
+  GPU_CLIENT_SINGLE_THREAD_CHECK();
+  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSetEnableDCLayersCHROMIUM("
+                     << GLES2Util::GetStringBool(enabled) << ")");
+  helper_->SetEnableDCLayersCHROMIUM(enabled);
+  CheckGLError();
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 2e17662d..cee92feee 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -3058,4 +3058,15 @@
   gl_->SetDrawRectangleCHROMIUM(1, 2, 3, 4);
   EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
 }
+
+TEST_F(GLES2ImplementationTest, SetEnableDCLayersCHROMIUM) {
+  struct Cmds {
+    cmds::SetEnableDCLayersCHROMIUM cmd;
+  };
+  Cmds expected;
+  expected.cmd.Init(true);
+
+  gl_->SetEnableDCLayersCHROMIUM(true);
+  EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 291168e..c142d27 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -909,4 +909,5 @@
                                       GLint y,
                                       GLint width,
                                       GLint height) = 0;
+virtual void SetEnableDCLayersCHROMIUM(GLboolean enabled) = 0;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index cd95940..f987b73 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -882,4 +882,5 @@
                               GLint y,
                               GLint width,
                               GLint height) override;
+void SetEnableDCLayersCHROMIUM(GLboolean enabled) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 5a93370..ddf50bd 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1187,4 +1187,5 @@
                                                   GLint /* y */,
                                                   GLint /* width */,
                                                   GLint /* height */) {}
+void GLES2InterfaceStub::SetEnableDCLayersCHROMIUM(GLboolean /* enabled */) {}
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 160da4a..6ad358c 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -882,4 +882,5 @@
                               GLint y,
                               GLint width,
                               GLint height) override;
+void SetEnableDCLayersCHROMIUM(GLboolean enabled) override;
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index b7f304a..5516df7 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2536,4 +2536,9 @@
   gl_->SetDrawRectangleCHROMIUM(x, y, width, height);
 }
 
+void GLES2TraceImplementation::SetEnableDCLayersCHROMIUM(GLboolean enabled) {
+  TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SetEnableDCLayersCHROMIUM");
+  gl_->SetEnableDCLayersCHROMIUM(enabled);
+}
+
 #endif  // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 101aa5a..3c8dfcd2 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -368,3 +368,6 @@
 
 // Extension CHROMIUM_set_draw_rectangle
 GL_APICALL void         GL_APIENTRY glSetDrawRectangleCHROMIUM (GLint x, GLint y, GLint width, GLint height);
+
+// Extension CHROMIUM_dc_overlays
+GL_APICALL void         GL_APIENTRY glSetEnableDCLayersCHROMIUM (GLboolean enabled);
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index b6445c37..29d025f7 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -154,7 +154,8 @@
   bool disable_multisampling_color_mask_usage = false;
   bool disable_webgl_rgb_multisampling_usage = false;
   bool gpu_rasterization = false;
-  bool set_draw_rectangle = false;
+  // True if DirectComposition layers are enabled.
+  bool dc_layers = false;
 
   // When this parameter is true, a CHROMIUM image created with RGB format will
   // actually have RGBA format. The client is responsible for handling most of
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index ad6106c..f0ab255 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -15866,4 +15866,37 @@
 static_assert(offsetof(SetDrawRectangleCHROMIUM, height) == 16,
               "offset of SetDrawRectangleCHROMIUM height should be 16");
 
+struct SetEnableDCLayersCHROMIUM {
+  typedef SetEnableDCLayersCHROMIUM ValueType;
+  static const CommandId kCmdId = kSetEnableDCLayersCHROMIUM;
+  static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+  static const uint8_t cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+  static uint32_t ComputeSize() {
+    return static_cast<uint32_t>(sizeof(ValueType));  // NOLINT
+  }
+
+  void SetHeader() { header.SetCmd<ValueType>(); }
+
+  void Init(GLboolean _enabled) {
+    SetHeader();
+    enabled = _enabled;
+  }
+
+  void* Set(void* cmd, GLboolean _enabled) {
+    static_cast<ValueType*>(cmd)->Init(_enabled);
+    return NextCmdAddress<ValueType>(cmd);
+  }
+
+  gpu::CommandHeader header;
+  uint32_t enabled;
+};
+
+static_assert(sizeof(SetEnableDCLayersCHROMIUM) == 8,
+              "size of SetEnableDCLayersCHROMIUM should be 8");
+static_assert(offsetof(SetEnableDCLayersCHROMIUM, header) == 0,
+              "offset of SetEnableDCLayersCHROMIUM header should be 0");
+static_assert(offsetof(SetEnableDCLayersCHROMIUM, enabled) == 4,
+              "offset of SetEnableDCLayersCHROMIUM enabled should be 4");
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index c26cd229..d43cd509 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5313,4 +5313,15 @@
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
+TEST_F(GLES2FormatTest, SetEnableDCLayersCHROMIUM) {
+  cmds::SetEnableDCLayersCHROMIUM& cmd =
+      *GetBufferAs<cmds::SetEnableDCLayersCHROMIUM>();
+  void* next_cmd = cmd.Set(&cmd, static_cast<GLboolean>(11));
+  EXPECT_EQ(static_cast<uint32_t>(cmds::SetEnableDCLayersCHROMIUM::kCmdId),
+            cmd.header.command);
+  EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+  EXPECT_EQ(static_cast<GLboolean>(11), cmd.enabled);
+  CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
 #endif  // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 8dd3ab7..ffef2d5 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -332,7 +332,8 @@
   OP(UniformMatrix4fvStreamTextureMatrixCHROMIUMImmediate) /* 573 */ \
   OP(OverlayPromotionHintCHROMIUM)                         /* 574 */ \
   OP(SwapBuffersWithBoundsCHROMIUMImmediate)               /* 575 */ \
-  OP(SetDrawRectangleCHROMIUM)                             /* 576 */
+  OP(SetDrawRectangleCHROMIUM)                             /* 576 */ \
+  OP(SetEnableDCLayersCHROMIUM)                            /* 577 */
 
 enum CommandId {
   kOneBeforeStartPoint =
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index b119c7a..5b1b6e6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1704,6 +1704,8 @@
   // Wrapper for glSetDrawRectangleCHROMIUM
   void DoSetDrawRectangleCHROMIUM(GLint x, GLint y, GLint width, GLint height);
 
+  void DoSetEnableDCLayersCHROMIUM(GLboolean enable);
+
   // Wrapper for glReadBuffer
   void DoReadBuffer(GLenum src);
 
@@ -2369,7 +2371,7 @@
   bool supports_swap_buffers_with_bounds_;
   bool supports_commit_overlay_planes_;
   bool supports_async_swap_;
-  bool supports_set_draw_rectangle_ = false;
+  bool supports_dc_layers_ = false;
 
   // These flags are used to override the state of the shared feature_info_
   // member.  Because the same FeatureInfo instance may be shared among many
@@ -3594,8 +3596,7 @@
 
   supports_async_swap_ = surface->SupportsAsyncSwap();
 
-  supports_set_draw_rectangle_ =
-      !offscreen && surface->SupportsSetDrawRectangle();
+  supports_dc_layers_ = !offscreen && surface->SupportsDCLayers();
 
   if (workarounds().reverse_point_sprite_coord_origin) {
     glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
@@ -3771,7 +3772,7 @@
   bool is_offscreen = !!offscreen_target_frame_buffer_.get();
   caps.flips_vertically = !is_offscreen && surface_->FlipsVertically();
   caps.msaa_is_slow = workarounds().msaa_is_slow;
-  caps.set_draw_rectangle = supports_set_draw_rectangle_;
+  caps.dc_layers = supports_dc_layers_;
 
   caps.blend_equation_advanced =
       feature_info_->feature_flags().blend_equation_advanced;
@@ -5667,15 +5668,14 @@
     return;
   state_.fbo_binding_for_scissor_workaround_dirty = false;
 
-  if (supports_set_draw_rectangle_) {
+  if (supports_dc_layers_) {
     gfx::Vector2d draw_offset = GetBoundFramebufferDrawOffset();
     glViewport(state_.viewport_x + draw_offset.x(),
                state_.viewport_y + draw_offset.y(), state_.viewport_width,
                state_.viewport_height);
   }
 
-  if (workarounds().restore_scissor_on_fbo_change ||
-      supports_set_draw_rectangle_) {
+  if (workarounds().restore_scissor_on_fbo_change || supports_dc_layers_) {
     // The driver forgets the correct scissor when modifying the FBO binding.
     gfx::Vector2d scissor_offset = GetBoundFramebufferDrawOffset();
     glScissor(state_.scissor_x + scissor_offset.x(),
@@ -8741,7 +8741,7 @@
                        "framebuffer must not be bound");
     return;
   }
-  if (!supports_set_draw_rectangle_) {
+  if (!supports_dc_layers_) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glSetDrawRectangleCHROMIUM",
                        "surface doesn't support SetDrawRectangle");
     return;
@@ -8754,6 +8754,24 @@
   OnFboChanged();
 }
 
+void GLES2DecoderImpl::DoSetEnableDCLayersCHROMIUM(GLboolean enable) {
+  Framebuffer* framebuffer = GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER);
+  if (framebuffer) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glSetEnableDCLayersCHROMIUM",
+                       "framebuffer must not be bound");
+    return;
+  }
+  if (!supports_dc_layers_) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glSetEnableDCLayersCHROMIUM",
+                       "surface doesn't support SetDrawRectangle");
+    return;
+  }
+  if (!surface_->SetEnableDCLayers(!!enable)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glSetEnableDCLayersCHROMIUM",
+                       "failed on surface");
+  }
+}
+
 void GLES2DecoderImpl::DoReadBuffer(GLenum src) {
   Framebuffer* framebuffer = GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER);
   if (framebuffer) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index e4b62da..b0e70227 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5172,6 +5172,17 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderImpl::HandleSetEnableDCLayersCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::SetEnableDCLayersCHROMIUM& c =
+      *static_cast<const volatile gles2::cmds::SetEnableDCLayersCHROMIUM*>(
+          cmd_data);
+  GLboolean enabled = static_cast<GLboolean>(c.enabled);
+  DoSetEnableDCLayersCHROMIUM(enabled);
+  return error::kNoError;
+}
+
 bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) {
   switch (cap) {
     case GL_BLEND:
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
index 28d286c3..47b3ea86 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
@@ -968,3 +968,4 @@
                                         GLint y,
                                         GLint width,
                                         GLint height);
+error::Error DoSetEnableDCLayersCHROMIUM(GLboolean enable);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index 93b5050..85d3bc7 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -3529,5 +3529,11 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderPassthroughImpl::DoSetEnableDCLayersCHROMIUM(
+    GLboolean enable) {
+  NOTIMPLEMENTED();
+  return error::kNoError;
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 37639206..bc19ef16 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -4385,5 +4385,19 @@
   return error::kNoError;
 }
 
+error::Error GLES2DecoderPassthroughImpl::HandleSetEnableDCLayersCHROMIUM(
+    uint32_t immediate_data_size,
+    const volatile void* cmd_data) {
+  const volatile gles2::cmds::SetEnableDCLayersCHROMIUM& c =
+      *static_cast<const volatile gles2::cmds::SetEnableDCLayersCHROMIUM*>(
+          cmd_data);
+  GLboolean enabled = static_cast<GLboolean>(c.enabled);
+  error::Error error = DoSetEnableDCLayersCHROMIUM(enabled);
+  if (error != error::kNoError) {
+    return error;
+  }
+  return error::kNoError;
+}
+
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
index 264c667..671309d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_4_autogen.h
@@ -33,4 +33,13 @@
   EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
+
+TEST_P(GLES2DecoderTest4, SetEnableDCLayersCHROMIUMValidArgs) {
+  EXPECT_CALL(*gl_, SetEnableDCLayersCHROMIUM(true));
+  SpecializedSetup<cmds::SetEnableDCLayersCHROMIUM, 0>(true);
+  cmds::SetEnableDCLayersCHROMIUM cmd;
+  cmd.Init(true);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_4_AUTOGEN_H_
diff --git a/gpu/ipc/common/gpu_command_buffer_traits_multi.h b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
index 4dc28d1..87a3eb1 100644
--- a/gpu/ipc/common/gpu_command_buffer_traits_multi.h
+++ b/gpu/ipc/common/gpu_command_buffer_traits_multi.h
@@ -127,7 +127,7 @@
   IPC_STRUCT_TRAITS_MEMBER(gpu_rasterization)
   IPC_STRUCT_TRAITS_MEMBER(chromium_image_rgb_emulation)
   IPC_STRUCT_TRAITS_MEMBER(emulate_rgb_buffer_with_rgba)
-  IPC_STRUCT_TRAITS_MEMBER(set_draw_rectangle)
+  IPC_STRUCT_TRAITS_MEMBER(dc_layers)
 
   IPC_STRUCT_TRAITS_MEMBER(major_version)
   IPC_STRUCT_TRAITS_MEMBER(minor_version)
diff --git a/gpu/ipc/service/direct_composition_surface_win.cc b/gpu/ipc/service/direct_composition_surface_win.cc
index 48a8cd9..7f652134 100644
--- a/gpu/ipc/service/direct_composition_surface_win.cc
+++ b/gpu/ipc/service/direct_composition_surface_win.cc
@@ -5,6 +5,7 @@
 #include "gpu/ipc/service/direct_composition_surface_win.h"
 
 #include "base/optional.h"
+#include "base/synchronization/waitable_event.h"
 #include "gpu/ipc/service/gpu_channel_manager.h"
 #include "gpu/ipc/service/gpu_channel_manager_delegate.h"
 #include "gpu/ipc/service/switches.h"
@@ -154,32 +155,83 @@
       eglCreatePbufferSurface(display, GetConfig(), &pbuffer_attribs[0]);
   CHECK(!!default_surface_);
 
-  InitializeSurface();
-
   return true;
 }
 
-void DirectCompositionSurfaceWin::InitializeSurface() {
-  ScopedReleaseCurrent release_current(this);
-  ReleaseDrawTexture();
+void DirectCompositionSurfaceWin::ReleaseCurrentSurface() {
+  ReleaseDrawTexture(true);
   dcomp_surface_.Release();
-  HRESULT hr = dcomp_device_->CreateSurface(
-      size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
-      DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive());
-  has_been_rendered_to_ = false;
-
-  CHECK(SUCCEEDED(hr));
+  swap_chain_.Release();
 }
 
-void DirectCompositionSurfaceWin::ReleaseDrawTexture() {
+void DirectCompositionSurfaceWin::InitializeSurface() {
+  DCHECK(!dcomp_surface_);
+  DCHECK(!swap_chain_);
+  if (enable_dc_layers_) {
+    HRESULT hr = dcomp_device_->CreateSurface(
+        size_.width(), size_.height(), DXGI_FORMAT_B8G8R8A8_UNORM,
+        DXGI_ALPHA_MODE_PREMULTIPLIED, dcomp_surface_.Receive());
+    has_been_rendered_to_ = false;
+    CHECK(SUCCEEDED(hr));
+  } else {
+    base::win::ScopedComPtr<IDXGIDevice> dxgi_device;
+    d3d11_device_.QueryInterface(dxgi_device.Receive());
+    base::win::ScopedComPtr<IDXGIAdapter> dxgi_adapter;
+    dxgi_device->GetAdapter(dxgi_adapter.Receive());
+    base::win::ScopedComPtr<IDXGIFactory2> dxgi_factory;
+    dxgi_adapter->GetParent(IID_PPV_ARGS(dxgi_factory.Receive()));
+
+    DXGI_SWAP_CHAIN_DESC1 desc = {};
+    desc.Width = size_.width();
+    desc.Height = size_.height();
+    desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
+    desc.Stereo = FALSE;
+    desc.SampleDesc.Count = 1;
+    desc.BufferCount = 2;
+    desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+    desc.Scaling = DXGI_SCALING_STRETCH;
+    desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+    desc.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
+    desc.Flags = 0;
+    HRESULT hr = dxgi_factory->CreateSwapChainForComposition(
+        d3d11_device_.get(), &desc, nullptr, swap_chain_.Receive());
+    has_been_rendered_to_ = false;
+    first_swap_ = true;
+    CHECK(SUCCEEDED(hr));
+  }
+}
+
+void DirectCompositionSurfaceWin::ReleaseDrawTexture(bool will_discard) {
   if (real_surface_) {
     eglDestroySurface(GetDisplay(), real_surface_);
     real_surface_ = nullptr;
   }
   if (draw_texture_) {
     draw_texture_.Release();
-    HRESULT hr = dcomp_surface_->EndDraw();
-    CHECK(SUCCEEDED(hr));
+    if (dcomp_surface_) {
+      HRESULT hr = dcomp_surface_->EndDraw();
+      CHECK(SUCCEEDED(hr));
+    } else if (!will_discard) {
+      DXGI_PRESENT_PARAMETERS params = {};
+      RECT dirty_rect = swap_rect_.ToRECT();
+      params.DirtyRectsCount = 1;
+      params.pDirtyRects = &dirty_rect;
+      swap_chain_->Present1(first_swap_ ? 0 : 1, 0, &params);
+      if (first_swap_) {
+        // Wait for the GPU to finish executing its commands before
+        // committing the DirectComposition tree, or else the swapchain
+        // may flicker black when it's first presented.
+        base::win::ScopedComPtr<IDXGIDevice2> dxgi_device2;
+        HRESULT hr = d3d11_device_.QueryInterface(dxgi_device2.Receive());
+        DCHECK(SUCCEEDED(hr));
+        base::WaitableEvent event(
+            base::WaitableEvent::ResetPolicy::AUTOMATIC,
+            base::WaitableEvent::InitialState::NOT_SIGNALED);
+        dxgi_device2->EnqueueSetEvent(event.handle());
+        event.Wait();
+        first_swap_ = false;
+      }
+    }
   }
   if (dcomp_surface_ == g_current_surface)
     g_current_surface = nullptr;
@@ -200,8 +252,11 @@
     }
     real_surface_ = nullptr;
   }
-  if (dcomp_surface_ == g_current_surface)
+  if (dcomp_surface_ && (dcomp_surface_ == g_current_surface)) {
+    HRESULT hr = dcomp_surface_->EndDraw();
+    CHECK(SUCCEEDED(hr));
     g_current_surface = nullptr;
+  }
   draw_texture_.Release();
   dcomp_surface_.Release();
 }
@@ -231,7 +286,9 @@
     return false;
   }
   size_ = size;
-  InitializeSurface();
+  ScopedReleaseCurrent release_current(this);
+  // New surface will be initialized in SetDrawRectangle.
+  ReleaseCurrentSurface();
 
   return true;
 }
@@ -239,19 +296,16 @@
 gfx::SwapResult DirectCompositionSurfaceWin::SwapBuffers() {
   {
     ScopedReleaseCurrent release_current(this);
-    ReleaseDrawTexture();
-    visual_->SetContent(dcomp_surface_.get());
+    ReleaseDrawTexture(false);
+    DCHECK(dcomp_surface_ || swap_chain_);
+    if (dcomp_surface_)
+      visual_->SetContent(dcomp_surface_.get());
+    else
+      visual_->SetContent(swap_chain_.get());
 
     CommitAndClearPendingOverlays();
     dcomp_device_->Commit();
   }
-  // Force the driver to finish drawing before clearing the contents to
-  // transparent, to reduce or eliminate the period of time where the contents
-  // have flashed black.
-  if (first_swap_) {
-    glFinish();
-    first_swap_ = false;
-  }
   child_window_.ClearInvalidContents();
   return gfx::SwapResult::SWAP_ACK;
 }
@@ -260,13 +314,9 @@
                                                            int y,
                                                            int width,
                                                            int height) {
-  ScopedReleaseCurrent release_current(this);
-  ReleaseDrawTexture();
-  visual_->SetContent(dcomp_surface_.get());
-  CommitAndClearPendingOverlays();
-  dcomp_device_->Commit();
-  child_window_.ClearInvalidContents();
-  return gfx::SwapResult::SWAP_ACK;
+  // The arguments are ignored because SetDrawRectangle specified the area to
+  // be swapped.
+  return SwapBuffers();
 }
 
 gfx::VSyncProvider* DirectCompositionSurfaceWin::GetVSyncProvider() {
@@ -284,6 +334,11 @@
   return true;
 }
 
+bool DirectCompositionSurfaceWin::SetEnableDCLayers(bool enable) {
+  enable_dc_layers_ = enable;
+  return true;
+}
+
 bool DirectCompositionSurfaceWin::CommitAndClearPendingOverlays() {
   pending_overlays_.clear();
   return true;
@@ -313,13 +368,23 @@
   return true;
 }
 
-bool DirectCompositionSurfaceWin::SupportsSetDrawRectangle() const {
+bool DirectCompositionSurfaceWin::SupportsDCLayers() const {
   return true;
 }
 
 bool DirectCompositionSurfaceWin::SetDrawRectangle(const gfx::Rect& rectangle) {
   if (draw_texture_)
     return false;
+
+  DCHECK(!real_surface_);
+  ScopedReleaseCurrent release_current(this);
+
+  if ((enable_dc_layers_ && !dcomp_surface_) ||
+      (!enable_dc_layers_ && !swap_chain_)) {
+    ReleaseCurrentSurface();
+    InitializeSurface();
+  }
+
   if (!gfx::Rect(size_).Contains(rectangle)) {
     DLOG(ERROR) << "Draw rectangle must be contained within size of surface";
     return false;
@@ -329,20 +394,24 @@
     return false;
   }
 
-  DCHECK(!real_surface_);
   CHECK(!g_current_surface);
-  ScopedReleaseCurrent release_current(this);
 
   RECT rect = rectangle.ToRECT();
-  POINT update_offset;
-
-  HRESULT hr = dcomp_surface_->BeginDraw(
-      &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset);
-  CHECK(SUCCEEDED(hr));
+  if (dcomp_surface_) {
+    POINT update_offset;
+    HRESULT hr = dcomp_surface_->BeginDraw(
+        &rect, IID_PPV_ARGS(draw_texture_.Receive()), &update_offset);
+    draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin();
+    CHECK(SUCCEEDED(hr));
+  } else {
+    HRESULT hr =
+        swap_chain_->GetBuffer(0, IID_PPV_ARGS(draw_texture_.Receive()));
+    swap_rect_ = rectangle;
+    draw_offset_ = gfx::Vector2d();
+    CHECK(SUCCEEDED(hr));
+  }
   has_been_rendered_to_ = true;
 
-  draw_offset_ = gfx::Point(update_offset) - gfx::Rect(rect).origin();
-
   g_current_surface = dcomp_surface_.get();
 
   std::vector<EGLint> pbuffer_attribs{
diff --git a/gpu/ipc/service/direct_composition_surface_win.h b/gpu/ipc/service/direct_composition_surface_win.h
index ddcdd272..f514f9c 100644
--- a/gpu/ipc/service/direct_composition_surface_win.h
+++ b/gpu/ipc/service/direct_composition_surface_win.h
@@ -49,16 +49,20 @@
                             gl::GLImage* image,
                             const gfx::Rect& bounds_rect,
                             const gfx::RectF& crop_rect) override;
+  bool SetEnableDCLayers(bool enable) override;
   bool FlipsVertically() const override;
   bool SupportsPostSubBuffer() override;
   bool OnMakeCurrent(gl::GLContext* context) override;
-  bool SupportsSetDrawRectangle() const override;
+  bool SupportsDCLayers() const override;
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   gfx::Vector2d GetDrawOffset() const override;
 
   bool Initialize(std::unique_ptr<gfx::VSyncProvider> vsync_provider);
 
   scoped_refptr<base::TaskRunner> GetWindowTaskRunnerForTesting();
+  base::win::ScopedComPtr<IDXGISwapChain1> swap_chain() const {
+    return swap_chain_;
+  }
 
  protected:
   ~DirectCompositionSurfaceWin() override;
@@ -82,8 +86,12 @@
   };
 
   bool CommitAndClearPendingOverlays();
+  void ReleaseCurrentSurface();
   void InitializeSurface();
-  void ReleaseDrawTexture();
+  // Release the texture that's currently being drawn to. If will_discard is
+  // true then the surface should be discarded without swapping any contents
+  // to it.
+  void ReleaseDrawTexture(bool will_discard);
 
   ChildWindowWin child_window_;
 
@@ -97,8 +105,10 @@
   EGLSurface real_surface_ = 0;
   gfx::Size size_ = gfx::Size(1, 1);
   bool first_swap_ = true;
+  bool enable_dc_layers_ = false;
   std::unique_ptr<gfx::VSyncProvider> vsync_provider_;
   std::vector<Overlay> pending_overlays_;
+  gfx::Rect swap_rect_;
 
   gfx::Vector2d draw_offset_;
 
@@ -107,6 +117,7 @@
   base::win::ScopedComPtr<IDCompositionTarget> dcomp_target_;
   base::win::ScopedComPtr<IDCompositionVisual2> visual_;
   base::win::ScopedComPtr<IDCompositionSurface> dcomp_surface_;
+  base::win::ScopedComPtr<IDXGISwapChain1> swap_chain_;
   base::win::ScopedComPtr<ID3D11Texture2D> draw_texture_;
 
   // Keep track of whether the texture has been rendered to, as the first draw
diff --git a/gpu/ipc/service/direct_composition_surface_win_unittest.cc b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
index 19a1d2c..862e1525 100644
--- a/gpu/ipc/service/direct_composition_surface_win_unittest.cc
+++ b/gpu/ipc/service/direct_composition_surface_win_unittest.cc
@@ -42,6 +42,21 @@
   done.Wait();
 }
 
+void DestroySurface(scoped_refptr<DirectCompositionSurfaceWin> surface) {
+  scoped_refptr<base::TaskRunner> task_runner =
+      surface->GetWindowTaskRunnerForTesting();
+  DCHECK(surface->HasOneRef());
+
+  surface = nullptr;
+
+  // Ensure that the ChildWindowWin posts the task to delete the thread to the
+  // main loop before doing RunUntilIdle. Otherwise the child threads could
+  // outlive the main thread.
+  RunPendingTasks(task_runner);
+
+  base::RunLoop().RunUntilIdle();
+}
+
 TEST(DirectCompositionSurfaceTest, TestMakeCurrent) {
   if (!gl::QueryDirectCompositionDevice(
           gl::QueryD3D11DeviceObjectFromANGLE())) {
@@ -52,6 +67,74 @@
 
   TestImageTransportSurfaceDelegate delegate;
 
+  scoped_refptr<DirectCompositionSurfaceWin> surface1(
+      new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
+                                      ui::GetHiddenWindow()));
+  EXPECT_TRUE(surface1->Initialize());
+  surface1->SetEnableDCLayers(true);
+
+  scoped_refptr<gl::GLContext> context1 = gl::init::CreateGLContext(
+      nullptr, surface1.get(), gl::GLContextAttribs());
+  EXPECT_TRUE(surface1->Resize(gfx::Size(100, 100), 1.0, true));
+
+  // First SetDrawRectangle must be full size of surface.
+  EXPECT_FALSE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
+  EXPECT_TRUE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+
+  // SetDrawRectangle can't be called again until swap.
+  EXPECT_FALSE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+
+  EXPECT_TRUE(context1->MakeCurrent(surface1.get()));
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface1->SwapBuffers());
+
+  EXPECT_TRUE(context1->IsCurrent(surface1.get()));
+
+  // SetDrawRectangle must be contained within surface.
+  EXPECT_FALSE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 101, 101)));
+  EXPECT_TRUE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+  EXPECT_TRUE(context1->IsCurrent(surface1.get()));
+
+  EXPECT_TRUE(surface1->Resize(gfx::Size(50, 50), 1.0, true));
+  EXPECT_TRUE(context1->IsCurrent(surface1.get()));
+  EXPECT_TRUE(surface1->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
+  EXPECT_TRUE(context1->IsCurrent(surface1.get()));
+
+  scoped_refptr<DirectCompositionSurfaceWin> surface2(
+      new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
+                                      ui::GetHiddenWindow()));
+  EXPECT_TRUE(surface2->Initialize());
+
+  scoped_refptr<gl::GLContext> context2 = gl::init::CreateGLContext(
+      nullptr, surface2.get(), gl::GLContextAttribs());
+  surface2->SetEnableDCLayers(true);
+  EXPECT_TRUE(context2->MakeCurrent(surface2.get()));
+  EXPECT_TRUE(surface2->Resize(gfx::Size(100, 100), 1.0, true));
+  // The previous IDCompositionSurface should be suspended when another
+  // surface is being drawn to.
+  EXPECT_TRUE(surface2->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+  EXPECT_TRUE(context2->IsCurrent(surface2.get()));
+
+  // It should be possible to switch back to the previous surface and
+  // unsuspend it.
+  EXPECT_TRUE(context1->MakeCurrent(surface1.get()));
+  context2 = nullptr;
+  context1 = nullptr;
+
+  DestroySurface(std::move(surface1));
+  DestroySurface(std::move(surface2));
+}
+
+// Tests that switching using EnableDCLayers works.
+TEST(DirectCompositionSurfaceTest, DXGIDCLayerSwitch) {
+  if (!gl::QueryDirectCompositionDevice(
+          gl::QueryD3D11DeviceObjectFromANGLE())) {
+    LOG(WARNING)
+        << "GL implementation not using DirectComposition, skipping test.";
+    return;
+  }
+
+  TestImageTransportSurfaceDelegate delegate;
+
   scoped_refptr<DirectCompositionSurfaceWin> surface(
       new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
                                       ui::GetHiddenWindow()));
@@ -60,10 +143,13 @@
   scoped_refptr<gl::GLContext> context =
       gl::init::CreateGLContext(nullptr, surface.get(), gl::GLContextAttribs());
   EXPECT_TRUE(surface->Resize(gfx::Size(100, 100), 1.0, true));
+  EXPECT_FALSE(surface->swap_chain());
 
-  // First SetDrawRectangle must be full size of surface.
+  // First SetDrawRectangle must be full size of surface for DXGI
+  // swapchain.
   EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
   EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+  EXPECT_TRUE(surface->swap_chain());
 
   // SetDrawRectangle can't be called again until swap.
   EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
@@ -73,50 +159,27 @@
 
   EXPECT_TRUE(context->IsCurrent(surface.get()));
 
-  // SetDrawRectangle must be contained within surface.
-  EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 101, 101)));
+  surface->SetEnableDCLayers(true);
+
+  // Surface switched to use IDCompositionSurface, so must draw to
+  // entire surface.
+  EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
   EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
   EXPECT_TRUE(context->IsCurrent(surface.get()));
+  EXPECT_FALSE(surface->swap_chain());
 
-  EXPECT_TRUE(surface->Resize(gfx::Size(50, 50), 1.0, true));
-  EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
-  EXPECT_TRUE(context->IsCurrent(surface.get()));
+  surface->SetEnableDCLayers(false);
 
-  scoped_refptr<DirectCompositionSurfaceWin> surface2(
-      new DirectCompositionSurfaceWin(delegate.AsWeakPtr(),
-                                      ui::GetHiddenWindow()));
-  EXPECT_TRUE(surface2->Initialize());
+  EXPECT_EQ(gfx::SwapResult::SWAP_ACK, surface->SwapBuffers());
 
-  scoped_refptr<gl::GLContext> context2 = gl::init::CreateGLContext(
-      nullptr, surface2.get(), gl::GLContextAttribs());
-  EXPECT_TRUE(context2->MakeCurrent(surface2.get()));
-  EXPECT_TRUE(surface2->Resize(gfx::Size(100, 100), 1.0, true));
-  // The previous IDCompositionSurface should be suspended when another
-  // surface is being drawn to.
-  EXPECT_TRUE(surface2->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
-  EXPECT_TRUE(context2->IsCurrent(surface2.get()));
+  // Surface switched to use IDXGISwapChain, so must draw to entire
+  // surface.
+  EXPECT_FALSE(surface->SetDrawRectangle(gfx::Rect(0, 0, 50, 50)));
+  EXPECT_TRUE(surface->SetDrawRectangle(gfx::Rect(0, 0, 100, 100)));
+  EXPECT_TRUE(surface->swap_chain());
 
-  // It should be possible to switch back to the previous surface and
-  // unsuspend it.
-  EXPECT_TRUE(context->MakeCurrent(surface.get()));
-  scoped_refptr<base::TaskRunner> task_runner1 =
-      surface->GetWindowTaskRunnerForTesting();
-  scoped_refptr<base::TaskRunner> task_runner2 =
-      surface2->GetWindowTaskRunnerForTesting();
-
-  context2 = nullptr;
-  surface2 = nullptr;
   context = nullptr;
-  surface = nullptr;
-
-  // Ensure that the ChildWindowWin posts the task to delete the thread to the
-  // main loop before doing RunUntilIdle. Otherwise the child threads could
-  // outlive the main thread.
-  RunPendingTasks(task_runner1);
-  RunPendingTasks(task_runner2);
-
-  base::RunLoop().RunUntilIdle();
+  DestroySurface(std::move(surface));
 }
-
 }  // namespace
 }  // namespace gpu
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.cc b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
index 44edeb7..f9fa0bfb 100644
--- a/ios/chrome/browser/dom_distiller/distiller_viewer.cc
+++ b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
@@ -68,9 +68,11 @@
                   article_proto->pages(0).html().empty();
   if (!is_empty) {
     std::vector<ImageInfo> images;
-    for (int i = 0; i < article_proto->pages(0).image_size(); i++) {
-      auto image = article_proto->pages(0).image(i);
-      images.push_back(ImageInfo{GURL(image.url()), image.data()});
+    for (int p = 0; p < article_proto->pages_size(); p++) {
+      for (int i = 0; i < article_proto->pages(p).image_size(); i++) {
+        auto image = article_proto->pages(p).image(i);
+        images.push_back(ImageInfo{GURL(image.url()), image.data()});
+      }
     }
     const std::string html = viewer::GetUnsafeArticleTemplateHtml(
         url_.spec(), distilled_page_prefs_->GetTheme(),
diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page.h b/ios/chrome/browser/reading_list/reading_list_distiller_page.h
index 9b139f2..2a80e44 100644
--- a/ios/chrome/browser/reading_list/reading_list_distiller_page.h
+++ b/ios/chrome/browser/reading_list/reading_list_distiller_page.h
@@ -45,10 +45,11 @@
  public:
   typedef base::Callback<void(const GURL&, const GURL&)> RedirectionCallback;
 
-  // Creates a ReadingListDistillerPage. WebStates to download the pages will
-  // be provided by web_state_dispatcher.
+  // Creates a ReadingListDistillerPage to distill |url|. WebStates to download
+  // the pages will be provided by web_state_dispatcher.
   // |browser_state|, |web_state_dispatcher| and |delegate| must not be null.
   explicit ReadingListDistillerPage(
+      const GURL& url,
       web::BrowserState* browser_state,
       FaviconWebStateDispatcher* web_state_dispatcher,
       ReadingListDistillerPageDelegate* delegate);
@@ -97,6 +98,7 @@
   // Continues distillation by calling superclass |OnLoadURLDone|.
   void DelayedOnLoadURLDone(int delayed_task_id);
   GURL original_url_;
+  bool distilling_main_page_;
 
   FaviconWebStateDispatcher* web_state_dispatcher_;
   ReadingListDistillerPageDelegate* delegate_;
diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
index e2fd850a..97262da 100644
--- a/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
+++ b/ios/chrome/browser/reading_list/reading_list_distiller_page.mm
@@ -55,10 +55,12 @@
 ReadingListDistillerPageDelegate::~ReadingListDistillerPageDelegate() {}
 
 ReadingListDistillerPage::ReadingListDistillerPage(
+    const GURL& url,
     web::BrowserState* browser_state,
     FaviconWebStateDispatcher* web_state_dispatcher,
     ReadingListDistillerPageDelegate* delegate)
     : dom_distiller::DistillerPageIOS(browser_state),
+      original_url_(url),
       web_state_dispatcher_(web_state_dispatcher),
       delegate_(delegate),
       delayed_task_id_(0),
@@ -77,8 +79,9 @@
   std::unique_ptr<web::WebState> new_web_state =
       web_state_dispatcher_->RequestWebState();
   AttachWebState(std::move(new_web_state));
-  original_url_ = url;
+
   delayed_task_id_++;
+  distilling_main_page_ = url == original_url_;
   FetchFavicon(url);
 
   DistillerPageIOS::DistillPageImpl(url, script);
@@ -153,8 +156,10 @@
     DistillerPageIOS::OnLoadURLDone(load_completion_status);
     return;
   }
-  delegate_->DistilledPageHasMimeType(original_url_,
-                                      CurrentWebState()->GetContentsMimeType());
+  if (distilling_main_page_) {
+    delegate_->DistilledPageHasMimeType(
+        original_url_, CurrentWebState()->GetContentsMimeType());
+  }
   if (!CurrentWebState()->ContentIsHTML()) {
     // If content is not HTML, distillation will fail immediatly.
     // Call the handler to make sure cleaning methods are called correctly.
@@ -205,7 +210,7 @@
   // If the visible URL is not the original URL, notify the caller that URL
   // changed.
   GURL redirected_url = CurrentWebState()->GetVisibleURL();
-  if (redirected_url != original_url_ && delegate_) {
+  if (redirected_url != original_url_ && delegate_ && distilling_main_page_) {
     delegate_->DistilledPageRedirectedToURL(original_url_, redirected_url);
   }
   DistillerPageIOS::OnLoadURLDone(web::PageLoadCompletionStatus::SUCCESS);
diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.h b/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.h
index c1d2787..daabebe 100644
--- a/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.h
+++ b/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "url/gurl.h"
 
 namespace web {
 class BrowserState;
@@ -28,8 +29,10 @@
   explicit ReadingListDistillerPageFactory(web::BrowserState* browser_state);
   virtual ~ReadingListDistillerPageFactory();
 
-  // Creates a ReadingListDistillerPage.
+  // Creates a ReadingListDistillerPage to distill |url|.
+  // Information about page will be reported to |delegate|.
   std::unique_ptr<ReadingListDistillerPage> CreateReadingListDistillerPage(
+      const GURL& url,
       ReadingListDistillerPageDelegate* delegate) const;
 
   // Releases all WebState owned by |web_state_dispatcher_|.
diff --git a/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.mm b/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.mm
index eba07b7..6adb7689b5 100644
--- a/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.mm
+++ b/ios/chrome/browser/reading_list/reading_list_distiller_page_factory.mm
@@ -23,9 +23,10 @@
 
 std::unique_ptr<ReadingListDistillerPage>
 ReadingListDistillerPageFactory::CreateReadingListDistillerPage(
+    const GURL& url,
     ReadingListDistillerPageDelegate* delegate) const {
   return base::MakeUnique<ReadingListDistillerPage>(
-      browser_state_, web_state_dispatcher_.get(), delegate);
+      url, browser_state_, web_state_dispatcher_.get(), delegate);
 }
 
 void ReadingListDistillerPageFactory::ReleaseAllRetainedWebState() {
diff --git a/ios/chrome/browser/reading_list/url_downloader.cc b/ios/chrome/browser/reading_list/url_downloader.cc
index 0f58433b..358015e 100644
--- a/ios/chrome/browser/reading_list/url_downloader.cc
+++ b/ios/chrome/browser/reading_list/url_downloader.cc
@@ -173,7 +173,7 @@
   saved_size_ = 0;
   std::unique_ptr<reading_list::ReadingListDistillerPage>
       reading_list_distiller_page =
-          distiller_page_factory_->CreateReadingListDistillerPage(this);
+          distiller_page_factory_->CreateReadingListDistillerPage(url, this);
 
   distiller_.reset(new dom_distiller::DistillerViewer(
       distiller_factory_, std::move(reading_list_distiller_page), pref_service_,
diff --git a/ios/showcase/BUILD.gn b/ios/showcase/BUILD.gn
index d19ba9c..369f9965 100644
--- a/ios/showcase/BUILD.gn
+++ b/ios/showcase/BUILD.gn
@@ -28,6 +28,7 @@
     "//ios/clean/chrome/browser/ui/tools:tools_ui",
     "//ios/showcase/settings",
     "//ios/showcase/suggestions",
+    "//ios/showcase/tab",
     "//ios/showcase/tab_grid",
     "//ios/showcase/tab_strip",
     "//ios/showcase/toolbar",
@@ -51,6 +52,8 @@
 
     # Add all eg_tests targets below.
     "//ios/showcase/core:eg_tests",
+    "//ios/showcase/suggestions:eg_tests",
+    "//ios/showcase/tab:eg_tests",
     "//ios/showcase/tab_grid:eg_tests",
 
     # All shared libraries must have the sanitizer deps to properly link in
diff --git a/ios/showcase/core/showcase_model.mm b/ios/showcase/core/showcase_model.mm
index 7aafb0c..daec8c3 100644
--- a/ios/showcase/core/showcase_model.mm
+++ b/ios/showcase/core/showcase_model.mm
@@ -17,11 +17,6 @@
 + (NSArray<showcase::ModelRow*>*)model {
   return @[
     @{
-      showcase::kClassForDisplayKey : @"SettingsViewController",
-      showcase::kClassForInstantiationKey : @"SCSettingsCoordinator",
-      showcase::kUseCaseKey : @"Main settings screen",
-    },
-    @{
       showcase::kClassForDisplayKey : @"ContentSuggestionsViewController",
       showcase::kClassForInstantiationKey : @"SCSuggestionsCoordinator",
       showcase::kUseCaseKey : @"New Suggestions UI",
@@ -32,9 +27,9 @@
       showcase::kUseCaseKey : @"Tools menu",
     },
     @{
-      showcase::kClassForDisplayKey : @"UITableViewCell",
-      showcase::kClassForInstantiationKey : @"UIKitTableViewCellViewController",
-      showcase::kUseCaseKey : @"UIKit Table Cells",
+      showcase::kClassForDisplayKey : @"SettingsViewController",
+      showcase::kClassForInstantiationKey : @"SCSettingsCoordinator",
+      showcase::kUseCaseKey : @"Main settings screen",
     },
     @{
       showcase::kClassForDisplayKey : @"TabGridViewController",
@@ -47,10 +42,25 @@
       showcase::kUseCaseKey : @"Tab strip container",
     },
     @{
+      showcase::kClassForDisplayKey : @"TopToolbarTabViewController",
+      showcase::kClassForInstantiationKey : @"SCTopToolbarTabCoordinator",
+      showcase::kUseCaseKey : @"Top toolbar tab",
+    },
+    @{
+      showcase::kClassForDisplayKey : @"BottomToolbarTabViewController",
+      showcase::kClassForInstantiationKey : @"SCBottomToolbarTabCoordinator",
+      showcase::kUseCaseKey : @"Bottom toolbar tab",
+    },
+    @{
       showcase::kClassForDisplayKey : @"ToolbarViewController",
       showcase::kClassForInstantiationKey : @"SCToolbarCoordinator",
       showcase::kUseCaseKey : @"Toolbar",
     },
+    @{
+      showcase::kClassForDisplayKey : @"UITableViewCell",
+      showcase::kClassForInstantiationKey : @"UIKitTableViewCellViewController",
+      showcase::kUseCaseKey : @"UIKit Table Cells",
+    },
   ];
 }
 
diff --git a/ios/showcase/suggestions/sc_suggestions_egtest.mm b/ios/showcase/suggestions/sc_suggestions_egtest.mm
index 8509dea4..c698878f 100644
--- a/ios/showcase/suggestions/sc_suggestions_egtest.mm
+++ b/ios/showcase/suggestions/sc_suggestions_egtest.mm
@@ -4,6 +4,7 @@
 
 #import <EarlGrey/EarlGrey.h>
 
+#import "ios/showcase/test/showcase_matchers.h"
 #import "ios/showcase/test/showcase_test_case.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -17,10 +18,12 @@
 @implementation SCSuggestionsTestCase
 
 // Tests launching ContentSuggestionsViewController.
-- (void)testLaunchAndTappingCell {
+- (void)testLaunch {
   [[EarlGrey
       selectElementWithMatcher:grey_text(@"ContentSuggestionsViewController")]
       performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:showcase_matchers::FirstLevelBackButton()]
+      performAction:grey_tap()];
 }
 
 @end
diff --git a/ios/showcase/tab/BUILD.gn b/ios/showcase/tab/BUILD.gn
new file mode 100644
index 0000000..b3df825
--- /dev/null
+++ b/ios/showcase/tab/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("tab") {
+  sources = [
+    "sc_bottom_toolbar_tab_coordinator.h",
+    "sc_bottom_toolbar_tab_coordinator.mm",
+    "sc_top_toolbar_tab_coordinator.h",
+    "sc_top_toolbar_tab_coordinator.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/clean/chrome/browser/ui/commands",
+    "//ios/clean/chrome/browser/ui/tab:tab_ui",
+    "//ios/showcase/common",
+  ]
+  libs = [ "UIKit.framework" ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
+
+source_set("eg_tests") {
+  testonly = true
+  sources = [
+    "sc_tab_egtest.mm",
+  ]
+  deps = [
+    "//ios/showcase/test",
+    "//ios/third_party/earl_grey",
+  ]
+  libs = [ "XCTest.framework" ]
+  configs += [ "//build/config/compiler:enable_arc" ]
+}
diff --git a/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.h b/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.h
new file mode 100644
index 0000000..66b1557
--- /dev/null
+++ b/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.h
@@ -0,0 +1,15 @@
+// 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_SHOWCASE_TAB_SC_BOTTOM_TOOLBAR_TAB_COORDINATOR_H_
+#define IOS_SHOWCASE_TAB_SC_BOTTOM_TOOLBAR_TAB_COORDINATOR_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/showcase/common/navigation_coordinator.h"
+
+@interface SCBottomToolbarTabCoordinator : NSObject<NavigationCoordinator>
+@end
+
+#endif  // IOS_SHOWCASE_TAB_SC_BOTTOM_TOOLBAR_TAB_COORDINATOR_H_
diff --git a/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.mm b/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.mm
new file mode 100644
index 0000000..ae2c688
--- /dev/null
+++ b/ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.mm
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/showcase/tab/sc_bottom_toolbar_tab_coordinator.h"
+
+#import "ios/clean/chrome/browser/ui/tab/tab_container_view_controller.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation SCBottomToolbarTabCoordinator
+
+@synthesize baseViewController;
+
+- (void)start {
+  UIViewController* bottomToolbarTabViewController =
+      [[BottomToolbarTabViewController alloc] init];
+  bottomToolbarTabViewController.title = @"Bottom toolbar tab";
+  [self.baseViewController pushViewController:bottomToolbarTabViewController
+                                     animated:YES];
+}
+
+@end
diff --git a/ios/showcase/tab/sc_tab_egtest.mm b/ios/showcase/tab/sc_tab_egtest.mm
new file mode 100644
index 0000000..c1ab075
--- /dev/null
+++ b/ios/showcase/tab/sc_tab_egtest.mm
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <EarlGrey/EarlGrey.h>
+
+#import "ios/showcase/test/showcase_matchers.h"
+#import "ios/showcase/test/showcase_test_case.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+// Tests for the tab container view controller.
+@interface SCTabTestCase : ShowcaseTestCase
+@end
+
+@implementation SCTabTestCase
+
+// Tests launching TopToolbarTabViewController.
+- (void)testLaunchWithTopToolbar {
+  [[EarlGrey selectElementWithMatcher:grey_text(@"TopToolbarTabViewController")]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:showcase_matchers::FirstLevelBackButton()]
+      performAction:grey_tap()];
+}
+
+// Tests launching BottomToolbarTabViewController.
+- (void)testLaunchWithBottomToolbar {
+  [[EarlGrey
+      selectElementWithMatcher:grey_text(@"BottomToolbarTabViewController")]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:showcase_matchers::FirstLevelBackButton()]
+      performAction:grey_tap()];
+}
+
+@end
diff --git a/ios/showcase/tab/sc_top_toolbar_tab_coordinator.h b/ios/showcase/tab/sc_top_toolbar_tab_coordinator.h
new file mode 100644
index 0000000..6f59a82
--- /dev/null
+++ b/ios/showcase/tab/sc_top_toolbar_tab_coordinator.h
@@ -0,0 +1,15 @@
+// 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_SHOWCASE_TAB_SC_TOP_TOOLBAR_TAB_COORDINATOR_H_
+#define IOS_SHOWCASE_TAB_SC_TOP_TOOLBAR_TAB_COORDINATOR_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/showcase/common/navigation_coordinator.h"
+
+@interface SCTopToolbarTabCoordinator : NSObject<NavigationCoordinator>
+@end
+
+#endif  // IOS_SHOWCASE_TAB_SC_TOP_TOOLBAR_TAB_COORDINATOR_H_
diff --git a/ios/showcase/tab/sc_top_toolbar_tab_coordinator.mm b/ios/showcase/tab/sc_top_toolbar_tab_coordinator.mm
new file mode 100644
index 0000000..563dfcd
--- /dev/null
+++ b/ios/showcase/tab/sc_top_toolbar_tab_coordinator.mm
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/showcase/tab/sc_top_toolbar_tab_coordinator.h"
+
+#import "ios/clean/chrome/browser/ui/tab/tab_container_view_controller.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation SCTopToolbarTabCoordinator
+
+@synthesize baseViewController;
+
+- (void)start {
+  UIViewController* topToolbarTabViewController =
+      [[TopToolbarTabViewController alloc] init];
+  topToolbarTabViewController.title = @"Top toolbar tab";
+  [self.baseViewController pushViewController:topToolbarTabViewController
+                                     animated:YES];
+}
+
+@end
diff --git a/ios/showcase/tab_grid/sc_tab_grid_egtest.mm b/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
index cf0c922..c99c5db 100644
--- a/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
+++ b/ios/showcase/tab_grid/sc_tab_grid_egtest.mm
@@ -4,6 +4,7 @@
 
 #import <EarlGrey/EarlGrey.h>
 
+#import "ios/showcase/test/showcase_matchers.h"
 #import "ios/showcase/test/showcase_test_case.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -32,6 +33,8 @@
   [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
                                           @"protocol_alerter_done")]
       performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:showcase_matchers::FirstLevelBackButton()]
+      performAction:grey_tap()];
 }
 
 @end
diff --git a/ios/showcase/test/BUILD.gn b/ios/showcase/test/BUILD.gn
index 9be866c..277ef348 100644
--- a/ios/showcase/test/BUILD.gn
+++ b/ios/showcase/test/BUILD.gn
@@ -5,6 +5,8 @@
 source_set("test") {
   testonly = true
   sources = [
+    "showcase_matchers.h",
+    "showcase_matchers.mm",
     "showcase_test_case.h",
     "showcase_test_case.mm",
   ]
diff --git a/ios/showcase/test/showcase_matchers.h b/ios/showcase/test/showcase_matchers.h
new file mode 100644
index 0000000..e8fb5ceb
--- /dev/null
+++ b/ios/showcase/test/showcase_matchers.h
@@ -0,0 +1,18 @@
+// 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_SHOWCASE_TEST_SHOWCASE_MATCHERS_H_
+#define IOS_SHOWCASE_TEST_SHOWCASE_MATCHERS_H_
+
+#import <EarlGrey/EarlGrey.h>
+
+namespace showcase_matchers {
+
+// Matcher for the back button on screens presented from the Showcase home
+// screen.
+id<GREYMatcher> FirstLevelBackButton();
+
+}  // namespace showcase_matchers
+
+#endif  // IOS_SHOWCASE_TEST_SHOWCASE_MATCHERS_H_
diff --git a/ios/showcase/test/showcase_matchers.mm b/ios/showcase/test/showcase_matchers.mm
new file mode 100644
index 0000000..9eb945f2
--- /dev/null
+++ b/ios/showcase/test/showcase_matchers.mm
@@ -0,0 +1,18 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/showcase/test/showcase_matchers.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace showcase_matchers {
+
+id<GREYMatcher> FirstLevelBackButton() {
+  return grey_kindOfClass(
+      NSClassFromString(@"_UINavigationBarBackIndicatorView"));
+}
+
+}  // namespace showcase_matchers
diff --git a/ios/web_view/internal/translate/BUILD.gn b/ios/web_view/internal/translate/BUILD.gn
index 3c0d86a..d42ff35 100644
--- a/ios/web_view/internal/translate/BUILD.gn
+++ b/ios/web_view/internal/translate/BUILD.gn
@@ -29,4 +29,6 @@
     "//ios/web_view/public",
     "//url",
   ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
 }
diff --git a/ios/web_view/internal/translate/cwv_translate_manager_impl.mm b/ios/web_view/internal/translate/cwv_translate_manager_impl.mm
index 25e60df8..1f087aa 100644
--- a/ios/web_view/internal/translate/cwv_translate_manager_impl.mm
+++ b/ios/web_view/internal/translate/cwv_translate_manager_impl.mm
@@ -9,6 +9,10 @@
 #include "components/translate/core/browser/translate_manager.h"
 #include "components/translate/core/browser/translate_ui_delegate.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 @implementation CWVTranslateManagerImpl {
   std::unique_ptr<translate::TranslateUIDelegate> _translateUIDelegate;
 }
diff --git a/ios/web_view/internal/translate/web_view_translate_client.h b/ios/web_view/internal/translate/web_view_translate_client.h
index ea80696..9d0816b 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.h
+++ b/ios/web_view/internal/translate/web_view_translate_client.h
@@ -8,14 +8,15 @@
 #include <memory>
 #include <string>
 
+#import "base/ios/weak_nsobject.h"
 #include "components/translate/core/browser/translate_client.h"
 #include "components/translate/core/browser/translate_step.h"
 #include "components/translate/core/common/translate_errors.h"
 #import "components/translate/ios/browser/ios_translate_driver.h"
 #include "ios/web/public/web_state/web_state_observer.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
+#import "ios/web_view/public/cwv_translate_delegate.h"
 
-@protocol CWVTranslateDelegate;
 class PrefService;
 
 namespace translate {
@@ -38,7 +39,7 @@
   // Sets the delegate passed by the embedder.
   // |delegate| is assumed to outlive this WebViewTranslateClient.
   void set_translate_delegate(id<CWVTranslateDelegate> delegate) {
-    delegate_ = delegate;
+    delegate_.reset(delegate);
   }
 
  private:
@@ -72,7 +73,7 @@
   translate::IOSTranslateDriver translate_driver_;
 
   // Delegate provided by the embedder.
-  id<CWVTranslateDelegate> delegate_;  // Weak.
+  base::WeakNSProtocol<id<CWVTranslateDelegate>> delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(WebViewTranslateClient);
 };
diff --git a/ios/web_view/internal/translate/web_view_translate_client.mm b/ios/web_view/internal/translate/web_view_translate_client.mm
index 188e9de..d0f7171 100644
--- a/ios/web_view/internal/translate/web_view_translate_client.mm
+++ b/ios/web_view/internal/translate/web_view_translate_client.mm
@@ -26,6 +26,10 @@
 #import "ios/web_view/public/cwv_translate_delegate.h"
 #include "url/gurl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 DEFINE_WEB_STATE_USER_DATA_KEY(ios_web_view::WebViewTranslateClient);
 
 namespace ios_web_view {
@@ -55,7 +59,7 @@
     const std::string& target_language,
     translate::TranslateErrors::Type error_type,
     bool triggered_from_menu) {
-  if (!delegate_)
+  if (!delegate_.get())
     return;
 
   if (error_type != translate::TranslateErrors::NONE)
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 91836b8..4085df6 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -540,6 +540,15 @@
   config->Initialize(codec, profile, format, color_space, coded_size,
                      visible_rect, natural_size, extra_data,
                      GetEncryptionScheme(stream));
+
+  const AVCodecParameters* codec_parameters = stream->codecpar;
+  config->set_color_space_info(gfx::ColorSpace::CreateVideo(
+      codec_parameters->color_primaries, codec_parameters->color_trc,
+      codec_parameters->color_space,
+      codec_parameters->color_range != AVCOL_RANGE_MPEG
+          ? gfx::ColorSpace::RangeID::FULL
+          : gfx::ColorSpace::RangeID::LIMITED));
+
   return true;
 }
 
diff --git a/media/gpu/video_encode_accelerator_unittest.cc b/media/gpu/video_encode_accelerator_unittest.cc
index 6a924df..b3a071a 100644
--- a/media/gpu/video_encode_accelerator_unittest.cc
+++ b/media/gpu/video_encode_accelerator_unittest.cc
@@ -2224,8 +2224,9 @@
     ::testing::Values(
         std::make_tuple(1, false, 0, true, false, true, false, false, false)));
 
+// TODO(kcwu): add back bitrate test after crbug.com/693336 fixed.
 INSTANTIATE_TEST_CASE_P(
-    MidStreamParamSwitchFPS,
+    DISABLED_MidStreamParamSwitchFPS,
     VideoEncodeAcceleratorTest,
     ::testing::Values(
         std::make_tuple(1, false, 0, true, false, false, true, false, false)));
@@ -2235,7 +2236,6 @@
     VideoEncodeAcceleratorTest,
     ::testing::Values(
         std::make_tuple(3, false, 0, false, false, false, false, false, false),
-        std::make_tuple(3, false, 0, true, false, false, true, false, false),
         std::make_tuple(3, false, 0, true, false, true, false, false, false)));
 
 INSTANTIATE_TEST_CASE_P(
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index 0aea756..b519fe9 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -96,7 +96,7 @@
   // state.
   bool Accept(Message* message) override;
   bool AcceptWithResponder(Message* message,
-                           MessageReceiver* responder) override;
+                           std::unique_ptr<MessageReceiver> responder) override;
 
   // The following methods are called by the router. They must be called
   // outside of the router's lock.
diff --git a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
index 72f7960..a4b51882 100644
--- a/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/associated_interface_ptr_state.h
@@ -131,7 +131,7 @@
 
   void ForwardMessageWithResponder(Message message,
                                    std::unique_ptr<MessageReceiver> responder) {
-    endpoint_client_->AcceptWithResponder(&message, responder.release());
+    endpoint_client_->AcceptWithResponder(&message, std::move(responder));
   }
 
  private:
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.cc b/mojo/public/cpp/bindings/lib/control_message_handler.cc
index c90aadad..1b7bb78 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "base/macros.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
 #include "mojo/public/cpp/bindings/lib/validation_util.h"
@@ -80,19 +81,20 @@
 
 bool ControlMessageHandler::AcceptWithResponder(
     Message* message,
-    MessageReceiverWithStatus* responder) {
+    std::unique_ptr<MessageReceiverWithStatus> responder) {
   if (!ValidateControlRequestWithResponse(message))
     return false;
 
   if (message->header()->name == interface_control::kRunMessageId)
-    return Run(message, responder);
+    return Run(message, std::move(responder));
 
   NOTREACHED();
   return false;
 }
 
-bool ControlMessageHandler::Run(Message* message,
-                                MessageReceiverWithStatus* responder) {
+bool ControlMessageHandler::Run(
+    Message* message,
+    std::unique_ptr<MessageReceiverWithStatus> responder) {
   interface_control::internal::RunMessageParams_Data* params =
       reinterpret_cast<interface_control::internal::RunMessageParams_Data*>(
           message->mutable_payload());
@@ -124,9 +126,7 @@
       nullptr;
   Serialize<interface_control::RunResponseMessageParamsDataView>(
       response_params_ptr, builder.buffer(), &response_params, &context_);
-  bool ok = responder->Accept(builder.message());
-  ALLOW_UNUSED_LOCAL(ok);
-  delete responder;
+  ignore_result(responder->Accept(builder.message()));
 
   return true;
 }
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.h b/mojo/public/cpp/bindings/lib/control_message_handler.h
index 3c385e4..5d1f716 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.h
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.h
@@ -27,12 +27,13 @@
 
   // Call the following methods only if IsControlMessage() returned true.
   bool Accept(Message* message) override;
-  // Takes ownership of |responder|.
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiverWithStatus* responder) override;
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiverWithStatus> responder) override;
 
  private:
-  bool Run(Message* message, MessageReceiverWithStatus* responder);
+  bool Run(Message* message,
+           std::unique_ptr<MessageReceiverWithStatus> responder);
   bool RunOrClosePipe(Message* message);
 
   uint32_t interface_version_;
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index 23de991..d082b49 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -85,9 +85,10 @@
   interface_control::internal::RunMessageParams_Data* params = nullptr;
   Serialize<interface_control::RunMessageParamsDataView>(
       params_ptr, builder.buffer(), &params, &context);
-  MessageReceiver* responder = new RunResponseForwardToCallback(callback);
-  if (!receiver->AcceptWithResponder(builder.message(), responder))
-    delete responder;
+  std::unique_ptr<MessageReceiver> responder =
+      base::MakeUnique<RunResponseForwardToCallback>(callback);
+  ignore_result(
+      receiver->AcceptWithResponder(builder.message(), std::move(responder)));
 }
 
 Message ConstructRunOrClosePipeMessage(
@@ -115,8 +116,7 @@
     interface_control::RunOrClosePipeInputPtr input_ptr) {
   Message message(ConstructRunOrClosePipeMessage(std::move(input_ptr)));
 
-  bool ok = receiver->Accept(&message);
-  ALLOW_UNUSED_LOCAL(ok);
+  ignore_result(receiver->Accept(&message));
 }
 
 void RunVersionCallback(
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index 3eca5a1..4682e72f 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -234,8 +234,9 @@
   return controller_->SendMessage(message);
 }
 
-bool InterfaceEndpointClient::AcceptWithResponder(Message* message,
-                                                  MessageReceiver* responder) {
+bool InterfaceEndpointClient::AcceptWithResponder(
+    Message* message,
+    std::unique_ptr<MessageReceiver> responder) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(message->has_flag(Message::kFlagExpectsResponse));
   DCHECK(!handle_.pending_association());
@@ -261,15 +262,13 @@
     return false;
 
   if (!is_sync) {
-    // We assume ownership of |responder|.
-    async_responders_[request_id] = base::WrapUnique(responder);
+    async_responders_[request_id] = std::move(responder);
     return true;
   }
 
   SyncCallRestrictions::AssertSyncCallAllowed();
 
   bool response_received = false;
-  std::unique_ptr<MessageReceiver> sync_responder(responder);
   sync_responses_.insert(std::make_pair(
       request_id, base::MakeUnique<SyncResponseInfo>(&response_received)));
 
@@ -282,11 +281,10 @@
     auto iter = sync_responses_.find(request_id);
     DCHECK_EQ(&response_received, iter->second->response_received);
     if (response_received)
-      ignore_result(sync_responder->Accept(&iter->second->response));
+      ignore_result(responder->Accept(&iter->second->response));
     sync_responses_.erase(iter);
   }
 
-  // Return true means that we take ownership of |responder|.
   return true;
 }
 
@@ -375,17 +373,16 @@
   }
 
   if (message->has_flag(Message::kFlagExpectsResponse)) {
-    MessageReceiverWithStatus* responder =
-        new ResponderThunk(weak_ptr_factory_.GetWeakPtr(), task_runner_);
-    bool ok = false;
+    std::unique_ptr<MessageReceiverWithStatus> responder =
+        base::MakeUnique<ResponderThunk>(weak_ptr_factory_.GetWeakPtr(),
+                                         task_runner_);
     if (mojo::internal::ControlMessageHandler::IsControlMessage(message)) {
-      ok = control_message_handler_.AcceptWithResponder(message, responder);
+      return control_message_handler_.AcceptWithResponder(message,
+                                                          std::move(responder));
     } else {
-      ok = incoming_receiver_->AcceptWithResponder(message, responder);
+      return incoming_receiver_->AcceptWithResponder(message,
+                                                     std::move(responder));
     }
-    if (!ok)
-      delete responder;
-    return ok;
   } else if (message->has_flag(Message::kFlagIsResponse)) {
     uint64_t request_id = message->request_id();
 
diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_state.h b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
index 8f5b4ff..fa54979 100644
--- a/mojo/public/cpp/bindings/lib/interface_ptr_state.h
+++ b/mojo/public/cpp/bindings/lib/interface_ptr_state.h
@@ -163,7 +163,7 @@
   void ForwardMessageWithResponder(Message message,
                                    std::unique_ptr<MessageReceiver> responder) {
     ConfigureProxyIfNecessary();
-    endpoint_client_->AcceptWithResponder(&message, responder.release());
+    endpoint_client_->AcceptWithResponder(&message, std::move(responder));
   }
 
  private:
diff --git a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
index 701108e1..1029c2c4 100644
--- a/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/pipe_control_message_proxy.cc
@@ -7,8 +7,8 @@
 #include <stddef.h>
 #include <utility>
 
-#include "base/compiler_specific.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "mojo/public/cpp/bindings/lib/message_builder.h"
 #include "mojo/public/cpp/bindings/lib/serialization.h"
 #include "mojo/public/interfaces/bindings/pipe_control_messages.mojom.h"
@@ -44,8 +44,7 @@
     InterfaceId id,
     const base::Optional<DisconnectReason>& reason) {
   Message message(ConstructPeerEndpointClosedMessage(id, reason));
-  bool ok = receiver_->Accept(&message);
-  ALLOW_UNUSED_LOCAL(ok);
+  ignore_result(receiver_->Accept(&message));
 }
 
 // static
diff --git a/mojo/public/cpp/bindings/message.h b/mojo/public/cpp/bindings/message.h
index 65d6cec..48e6900 100644
--- a/mojo/public/cpp/bindings/message.h
+++ b/mojo/public/cpp/bindings/message.h
@@ -183,14 +183,8 @@
   // responder) to handle the response message generated from the given
   // message. The responder's Accept method may be called during
   // AcceptWithResponder or some time after its return.
-  //
-  // NOTE: Upon returning true, AcceptWithResponder assumes ownership of
-  // |responder| and will delete it after calling |responder->Accept| or upon
-  // its own destruction.
-  //
-  // TODO(yzshen): consider changing |responder| to
-  // std::unique_ptr<MessageReceiver>.
-  virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder)
+  virtual bool AcceptWithResponder(Message* message,
+                                   std::unique_ptr<MessageReceiver> responder)
       WARN_UNUSED_RESULT = 0;
 };
 
@@ -222,16 +216,9 @@
   // the responder) to handle the response message generated from the given
   // message. Any of the responder's methods (Accept or IsValid) may be called
   // during  AcceptWithResponder or some time after its return.
-  //
-  // NOTE: Upon returning true, AcceptWithResponder assumes ownership of
-  // |responder| and will delete it after calling |responder->Accept| or upon
-  // its own destruction.
-  //
-  // TODO(yzshen): consider changing |responder| to
-  // std::unique_ptr<MessageReceiver>.
   virtual bool AcceptWithResponder(Message* message,
-                                   MessageReceiverWithStatus* responder)
-      WARN_UNUSED_RESULT = 0;
+                                   std::unique_ptr<MessageReceiverWithStatus>
+                                       responder) WARN_UNUSED_RESULT = 0;
 };
 
 class MOJO_CPP_BINDINGS_EXPORT PassThroughFilter
diff --git a/mojo/public/cpp/bindings/tests/bindings_perftest.cc b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
index 6a50de4..65b3c8c1 100644
--- a/mojo/public/cpp/bindings/tests/bindings_perftest.cc
+++ b/mojo/public/cpp/bindings/tests/bindings_perftest.cc
@@ -160,8 +160,9 @@
     return true;
   }
 
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiverWithStatus* responder) override {
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiverWithStatus> responder) override {
     NOTREACHED();
     return true;
   }
@@ -232,8 +233,9 @@
     return true;
   }
 
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiverWithStatus* responder) override {
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiverWithStatus> responder) override {
     NOTREACHED();
     return true;
   }
diff --git a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
index 31963e0..8950928 100644
--- a/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/multiplex_router_unittest.cc
@@ -72,8 +72,8 @@
   MessageQueue message_queue;
   base::RunLoop run_loop;
   client0.AcceptWithResponder(
-      &request,
-      new MessageAccumulator(&message_queue, run_loop.QuitClosure()));
+      &request, base::MakeUnique<MessageAccumulator>(&message_queue,
+                                                     run_loop.QuitClosure()));
 
   run_loop.Run();
 
@@ -91,8 +91,8 @@
 
   base::RunLoop run_loop2;
   client0.AcceptWithResponder(
-      &request2,
-      new MessageAccumulator(&message_queue, run_loop2.QuitClosure()));
+      &request2, base::MakeUnique<MessageAccumulator>(&message_queue,
+                                                      run_loop2.QuitClosure()));
 
   run_loop2.Run();
 
@@ -117,7 +117,8 @@
   AllocRequestMessage(1, "hello", &request);
 
   MessageQueue message_queue;
-  client0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
+  client0.AcceptWithResponder(
+      &request, base::MakeUnique<MessageAccumulator>(&message_queue));
 
   router1_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
   router0_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
@@ -134,8 +135,8 @@
   Message request2;
   AllocRequestMessage(1, "hello again", &request2);
 
-  client0.AcceptWithResponder(&request2,
-                              new MessageAccumulator(&message_queue));
+  client0.AcceptWithResponder(
+      &request2, base::MakeUnique<MessageAccumulator>(&message_queue));
 
   router1_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
   router0_->WaitForIncomingMessage(MOJO_DEADLINE_INDEFINITE);
@@ -167,8 +168,8 @@
   MessageQueue message_queue;
   base::RunLoop run_loop2;
   client0.AcceptWithResponder(
-      &request,
-      new MessageAccumulator(&message_queue, run_loop2.QuitClosure()));
+      &request, base::MakeUnique<MessageAccumulator>(&message_queue,
+                                                     run_loop2.QuitClosure()));
   run_loop.Run();
 
   // The request has been received but the response has not been sent yet.
@@ -194,8 +195,8 @@
 
   base::RunLoop run_loop4;
   client0.AcceptWithResponder(
-      &request2,
-      new MessageAccumulator(&message_queue, run_loop4.QuitClosure()));
+      &request2, base::MakeUnique<MessageAccumulator>(&message_queue,
+                                                      run_loop4.QuitClosure()));
   run_loop3.Run();
 
   // The request has been received but the response has not been sent yet.
@@ -246,7 +247,8 @@
   AllocRequestMessage(1, "hello", &request);
 
   MessageQueue message_queue;
-  client0.AcceptWithResponder(&request, new MessageAccumulator(&message_queue));
+  client0.AcceptWithResponder(
+      &request, base::MakeUnique<MessageAccumulator>(&message_queue));
   run_loop3.Run();
 
   // The request has been received but no response has been sent.
@@ -293,8 +295,8 @@
     AllocRequestMessage(1, "hello", &request);
 
     MessageQueue message_queue;
-    client0.AcceptWithResponder(&request,
-                                new MessageAccumulator(&message_queue));
+    client0.AcceptWithResponder(
+        &request, base::MakeUnique<MessageAccumulator>(&message_queue));
 
     run_loop.Run();
 
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.cc b/mojo/public/cpp/bindings/tests/router_test_util.cc
index b9b93d8..9bab1cb 100644
--- a/mojo/public/cpp/bindings/tests/router_test_util.cc
+++ b/mojo/public/cpp/bindings/tests/router_test_util.cc
@@ -58,14 +58,13 @@
 
 bool ResponseGenerator::AcceptWithResponder(
     Message* message,
-    MessageReceiverWithStatus* responder) {
+    std::unique_ptr<MessageReceiverWithStatus> responder) {
   EXPECT_TRUE(message->has_flag(Message::kFlagExpectsResponse));
 
   bool result = SendResponse(message->name(), message->request_id(),
                              reinterpret_cast<const char*>(message->payload()),
-                             responder);
+                             responder.get());
   EXPECT_TRUE(responder->IsValid());
-  delete responder;
   return result;
 }
 
@@ -84,18 +83,16 @@
 LazyResponseGenerator::LazyResponseGenerator(const base::Closure& closure)
     : responder_(nullptr), name_(0), request_id_(0), closure_(closure) {}
 
-LazyResponseGenerator::~LazyResponseGenerator() {
-  delete responder_;
-}
+LazyResponseGenerator::~LazyResponseGenerator() = default;
 
 bool LazyResponseGenerator::AcceptWithResponder(
     Message* message,
-    MessageReceiverWithStatus* responder) {
+    std::unique_ptr<MessageReceiverWithStatus> responder) {
   name_ = message->name();
   request_id_ = message->request_id();
   request_string_ =
       std::string(reinterpret_cast<const char*>(message->payload()));
-  responder_ = responder;
+  responder_ = std::move(responder);
   if (!closure_.is_null()) {
     closure_.Run();
     closure_.Reset();
@@ -105,9 +102,8 @@
 
 void LazyResponseGenerator::Complete(bool send_response) {
   if (send_response) {
-    SendResponse(name_, request_id_, request_string_.c_str(), responder_);
+    SendResponse(name_, request_id_, request_string_.c_str(), responder_.get());
   }
-  delete responder_;
   responder_ = nullptr;
 }
 
diff --git a/mojo/public/cpp/bindings/tests/router_test_util.h b/mojo/public/cpp/bindings/tests/router_test_util.h
index c6fb372d..dd6aff63 100644
--- a/mojo/public/cpp/bindings/tests/router_test_util.h
+++ b/mojo/public/cpp/bindings/tests/router_test_util.h
@@ -42,9 +42,9 @@
 
   bool Accept(Message* message) override;
 
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiverWithStatus* responder) override;
-
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiverWithStatus> responder) override;
   bool SendResponse(uint32_t name,
                     uint64_t request_id,
                     const char* request_string,
@@ -58,8 +58,9 @@
 
   ~LazyResponseGenerator() override;
 
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiverWithStatus* responder) override;
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiverWithStatus> responder) override;
 
   bool has_responder() const { return !!responder_; }
 
@@ -78,7 +79,7 @@
   // also sends a response.
   void Complete(bool send_response);
 
-  MessageReceiverWithStatus* responder_;
+  std::unique_ptr<MessageReceiverWithStatus> responder_;
   uint32_t name_;
   uint64_t request_id_;
   std::string request_string_;
diff --git a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
index 579576fd..1f95a27a 100644
--- a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc
@@ -295,8 +295,9 @@
     return stub.Accept(message);
   }
 
-  bool AcceptWithResponder(mojo::Message* message,
-                           mojo::MessageReceiver* responder) override {
+  bool AcceptWithResponder(
+      mojo::Message* message,
+      std::unique_ptr<mojo::MessageReceiver> responder) override {
     return false;
   }
 };
diff --git a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
index bab6d22c..8b32b30b 100644
--- a/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
+++ b/mojo/public/cpp/bindings/thread_safe_interface_ptr.h
@@ -73,16 +73,17 @@
     return true;
   }
 
-  bool AcceptWithResponder(Message* message,
-                           MessageReceiver* response_receiver) override {
+  bool AcceptWithResponder(
+      Message* message,
+      std::unique_ptr<MessageReceiver> response_receiver) override {
     if (!message->associated_endpoint_handles()->empty()) {
       // Please see comment for the DCHECK in the previous method.
       DCHECK(associated_group_.GetController());
       message->SerializeAssociatedEndpointHandles(
           associated_group_.GetController());
     }
-    auto responder = base::MakeUnique<ForwardToCallingThread>(
-        base::WrapUnique(response_receiver));
+    auto responder =
+        base::MakeUnique<ForwardToCallingThread>(std::move(response_receiver));
     task_runner_->PostTask(
         FROM_HERE, base::Bind(forward_with_responder_, base::Passed(message),
                               base::Passed(&responder)));
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 a23b107..aba18380 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -169,14 +169,14 @@
                   "&serialization_context")}}
 
   bool result = false;
-  mojo::MessageReceiver* responder =
+  std::unique_ptr<mojo::MessageReceiver> responder(
       new {{class_name}}_{{method.name}}_HandleSyncResponse(
           &result
 {%-     for param in method.response_parameters -%}
           , param_{{param.name}}
-{%-     endfor %});
-  if (!receiver_->AcceptWithResponder(builder.message(), responder))
-    delete responder;
+{%-     endfor %}));
+  ignore_result(receiver_->AcceptWithResponder(builder.message(),
+                                               std::move(responder)));
   return result;
 }
 {%-   endif %}
@@ -200,15 +200,15 @@
                   "&serialization_context")}}
 
 {%- if method.response_parameters != None %}
-  mojo::MessageReceiver* responder =
-      new {{class_name}}_{{method.name}}_ForwardToCallback(std::move(callback));
-  if (!receiver_->AcceptWithResponder(builder.message(), responder))
-    delete responder;
+  std::unique_ptr<mojo::MessageReceiver> responder(
+      new {{class_name}}_{{method.name}}_ForwardToCallback(
+          std::move(callback)));
+  ignore_result(receiver_->AcceptWithResponder(builder.message(),
+                                               std::move(responder)));
 {%- else %}
-  bool ok = receiver_->Accept(builder.message());
-  // This return value may be ignored as !ok implies the Connector has
+  // This return value may be ignored as false implies the Connector has
   // encountered an error, which will be visible through other means.
-  ALLOW_UNUSED_LOCAL(ok);
+  ignore_result(receiver_->Accept(builder.message()));
 {%- endif %}
 }
 {%- endfor %}
@@ -226,10 +226,10 @@
   static {{class_name}}::{{method.name}}Callback CreateCallback(
       uint64_t request_id,
       bool is_sync,
-      mojo::MessageReceiverWithStatus* responder) {
+      std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
     std::unique_ptr<{{class_name}}_{{method.name}}_ProxyToResponder> proxy(
         new {{class_name}}_{{method.name}}_ProxyToResponder(
-            request_id, is_sync, responder));
+            request_id, is_sync, std::move(responder)));
     return base::Bind(&{{class_name}}_{{method.name}}_ProxyToResponder::Run,
                       base::Passed(&proxy));
   }
@@ -245,17 +245,17 @@
 #endif
     // If the Callback was dropped then deleting the responder will close
     // the pipe so the calling application knows to stop waiting for a reply.
-    delete responder_;
+    responder_ = nullptr;
   }
 
  private:
   {{class_name}}_{{method.name}}_ProxyToResponder(
       uint64_t request_id,
       bool is_sync,
-      mojo::MessageReceiverWithStatus* responder)
+      std::unique_ptr<mojo::MessageReceiverWithStatus> responder)
       : request_id_(request_id),
         is_sync_(is_sync),
-        responder_(responder) {
+        responder_(std::move(responder)) {
   }
 
   void Run(
@@ -264,7 +264,7 @@
 
   uint64_t request_id_;
   bool is_sync_;
-  mojo::MessageReceiverWithStatus* responder_;
+  std::unique_ptr<mojo::MessageReceiverWithStatus> responder_;
 
   DISALLOW_COPY_AND_ASSIGN({{class_name}}_{{method.name}}_ProxyToResponder);
 };
@@ -285,12 +285,10 @@
 
   {{build_message(response_params_struct, "in_%s", params_description,
                   "&serialization_context")}}
-  bool ok = responder_->Accept(builder.message());
-  ALLOW_UNUSED_LOCAL(ok);
-  // TODO(darin): !ok returned here indicates a malformed message, and that may
-  // be good reason to close the connection. However, we don't have a way to do
-  // that from here. We should add a way.
-  delete responder_;
+  ignore_result(responder_->Accept(builder.message()));
+  // TODO(darin): Accept() returning false indicates a malformed message, and
+  // that may be good reason to close the connection. However, we don't have a
+  // way to do that from here. We should add a way.
   responder_ = nullptr;
 }
 {%-   endif -%}
@@ -334,7 +332,7 @@
 bool {{class_name}}StubDispatch::AcceptWithResponder(
     {{interface.name}}* impl,
     mojo::Message* message,
-    mojo::MessageReceiverWithStatus* responder) {
+    std::unique_ptr<mojo::MessageReceiverWithStatus> responder) {
 {%- if interface.methods %}
   switch (message->header()->name) {
 {%-   for method in interface.methods %}
@@ -350,7 +348,8 @@
       {{class_name}}::{{method.name}}Callback callback =
           {{class_name}}_{{method.name}}_ProxyToResponder::CreateCallback(
               message->request_id(),
-              message->has_flag(mojo::Message::kFlagIsSync), responder);
+              message->has_flag(mojo::Message::kFlagIsSync),
+              std::move(responder));
       // A null |impl| means no implementation was bound.
       assert(impl);
       TRACE_EVENT0("mojom", "{{class_name}}::{{method.name}}");
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
index 9f01348..79ab46f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl
@@ -1,9 +1,10 @@
 class {{export_attribute}} {{interface.name}}StubDispatch {
  public:
   static bool Accept({{interface.name}}* impl, mojo::Message* message);
-  static bool AcceptWithResponder({{interface.name}}* impl,
-                                  mojo::Message* message,
-                                  mojo::MessageReceiverWithStatus* responder);
+  static bool AcceptWithResponder(
+      {{interface.name}}* impl,
+      mojo::Message* message,
+      std::unique_ptr<mojo::MessageReceiverWithStatus> responder);
 };
 
 template <typename ImplRefTraits =
@@ -28,11 +29,11 @@
 
   bool AcceptWithResponder(
       mojo::Message* message,
-      mojo::MessageReceiverWithStatus* responder) override {
+      std::unique_ptr<mojo::MessageReceiverWithStatus> responder) override {
     if (ImplRefTraits::IsNull(sink_))
       return false;
     return {{interface.name}}StubDispatch::AcceptWithResponder(
-        ImplRefTraits::GetRawPointer(&sink_), message, responder);
+        ImplRefTraits::GetRawPointer(&sink_), message, std::move(responder));
   }
 
  private:
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
index acdad5e..804a46b 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl
@@ -40,6 +40,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/macros.h"
 #include "base/optional.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr_info.h"
diff --git a/services/shape_detection/DEPS b/services/shape_detection/DEPS
index a2872a2..1987787 100644
--- a/services/shape_detection/DEPS
+++ b/services/shape_detection/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+media/capture/video/scoped_result_callback.h",
+  "+skia/ext/skia_utils_mac.h",
   "+third_party/skia/include",
   "+ui/gfx/codec",
   "+ui/gl/gl_switches.h"
diff --git a/services/shape_detection/barcode_detection_impl_mac.h b/services/shape_detection/barcode_detection_impl_mac.h
index a7779897..6a5609a 100644
--- a/services/shape_detection/barcode_detection_impl_mac.h
+++ b/services/shape_detection/barcode_detection_impl_mac.h
@@ -7,6 +7,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 
 @class CIDetector;
 
@@ -18,9 +19,7 @@
   BarcodeDetectionImplMac();
   ~BarcodeDetectionImplMac() override;
 
-  void Detect(mojo::ScopedSharedBufferHandle frame_data,
-              uint32_t width,
-              uint32_t height,
+  void Detect(const SkBitmap& bitmap,
               const shape_detection::mojom::BarcodeDetection::DetectCallback&
                   callback) override;
 
diff --git a/services/shape_detection/barcode_detection_impl_mac.mm b/services/shape_detection/barcode_detection_impl_mac.mm
index ec0ac0b..2abbc03 100644
--- a/services/shape_detection/barcode_detection_impl_mac.mm
+++ b/services/shape_detection/barcode_detection_impl_mac.mm
@@ -50,22 +50,20 @@
 
 BarcodeDetectionImplMac::~BarcodeDetectionImplMac() {}
 
-void BarcodeDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
-                                     uint32_t width,
-                                     uint32_t height,
+void BarcodeDetectionImplMac::Detect(const SkBitmap& bitmap,
                                      const DetectCallback& callback) {
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithBarcodes, callback),
       base::Bind(&RunCallbackWithNoBarcodes));
 
-  base::scoped_nsobject<CIImage> ci_image =
-      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
+  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
   std::vector<mojom::BarcodeDetectionResultPtr> results;
+  const int height = bitmap.height();
   for (CIQRCodeFeature* const f in features) {
     shape_detection::mojom::BarcodeDetectionResultPtr result =
         shape_detection::mojom::BarcodeDetectionResult::New();
diff --git a/services/shape_detection/barcode_detection_impl_mac_unittest.mm b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
index 55c2cd27..d3c305c 100644
--- a/services/shape_detection/barcode_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/barcode_detection_impl_mac_unittest.mm
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 #include "ui/gl/gl_switches.h"
 
 namespace shape_detection {
@@ -64,7 +65,6 @@
 
   const gfx::Size size([qr_code_image extent].size.width,
                        [qr_code_image extent].size.height);
-  const int num_bytes = size.GetArea() * 4 /* bytes per pixel */;
 
   base::scoped_nsobject<CIContext> context([[CIContext alloc] init]);
 
@@ -73,30 +73,16 @@
   EXPECT_EQ(static_cast<size_t>(size.width()), CGImageGetWidth(cg_image));
   EXPECT_EQ(static_cast<size_t>(size.height()), CGImageGetHeight(cg_image));
 
-  base::ScopedCFTypeRef<CFDataRef> raw_cg_image_data(
-      CGDataProviderCopyData(CGImageGetDataProvider(cg_image)));
-  EXPECT_TRUE(CFDataGetBytePtr(raw_cg_image_data));
-  EXPECT_EQ(num_bytes, CFDataGetLength(raw_cg_image_data));
-
-  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
-  // copy the generated qr code image pixels into it.
-  mojo::ScopedSharedBufferHandle handle =
-      mojo::SharedBufferHandle::Create(num_bytes);
-  ASSERT_TRUE(handle->is_valid());
-
-  mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
-  ASSERT_TRUE(mapping);
-
-  memcpy(mapping.get(), CFDataGetBytePtr(raw_cg_image_data), num_bytes);
+  SkBitmap bitmap;
+  ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, cg_image));
 
   base::RunLoop run_loop;
   base::Closure quit_closure = run_loop.QuitClosure();
   // Send the image Detect() and expect the response in callback.
   EXPECT_CALL(*this, Detection(1, kInfoString))
       .WillOnce(RunClosure(quit_closure));
-  impl_.Detect(std::move(handle), size.width(), size.height(),
-               base::Bind(&BarcodeDetectionImplMacTest::DetectCallback,
-                          base::Unretained(this)));
+  impl_.Detect(bitmap, base::Bind(&BarcodeDetectionImplMacTest::DetectCallback,
+                                  base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/services/shape_detection/detection_utils_mac.h b/services/shape_detection/detection_utils_mac.h
index 98e3c0f..69e46426 100644
--- a/services/shape_detection/detection_utils_mac.h
+++ b/services/shape_detection/detection_utils_mac.h
@@ -9,15 +9,14 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 
 namespace shape_detection {
 
 // Takes a ScopedSharedBufferHandle with dimensions and produces a new CIImage
 // with the same contents, or a null scoped_nsobject is something goes wrong.
-base::scoped_nsobject<CIImage> CreateCIImageFromSharedMemory(
-    mojo::ScopedSharedBufferHandle frame_data,
-    uint32_t width,
-    uint32_t height);
+base::scoped_nsobject<CIImage> CreateCIImageFromSkBitmap(
+    const SkBitmap& bitmap);
 
 }  // namespace shape_detection
 
diff --git a/services/shape_detection/detection_utils_mac.mm b/services/shape_detection/detection_utils_mac.mm
index 4e87812e99..554cd7e5 100644
--- a/services/shape_detection/detection_utils_mac.mm
+++ b/services/shape_detection/detection_utils_mac.mm
@@ -9,61 +9,31 @@
 #include "base/memory/shared_memory.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/shape_detection/barcode_detection_impl.h"
+#include "skia/ext/skia_utils_mac.h"
+#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 
 namespace shape_detection {
 
-// These formats are available but not public until Mac 10.11.
-#if !defined(MAC_OS_X_VERSION_10_11) || \
-    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
-const int kCIFormatRGBA8 = 24;
-#else
-//static_assert(kCIFormatRGBA8 == 24, "RGBA8 format enum index.");
-#endif
-
-base::scoped_nsobject<CIImage> CreateCIImageFromSharedMemory(
-    mojo::ScopedSharedBufferHandle frame_data,
-    uint32_t width,
-    uint32_t height) {
+base::scoped_nsobject<CIImage> CreateCIImageFromSkBitmap(
+    const SkBitmap& bitmap) {
   base::CheckedNumeric<uint32_t> num_pixels =
-      base::CheckedNumeric<uint32_t>(width) * height;
+      base::CheckedNumeric<uint32_t>(bitmap.width()) * bitmap.height();
   base::CheckedNumeric<uint32_t> num_bytes = num_pixels * 4;
   if (!num_bytes.IsValid()) {
     DLOG(ERROR) << "Data overflow";
     return base::scoped_nsobject<CIImage>();
   }
 
-  base::SharedMemoryHandle memory_handle;
-  size_t memory_size = 0;
-  bool read_only_flag = false;
-  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
-      std::move(frame_data), &memory_handle, &memory_size, &read_only_flag);
-  DCHECK_EQ(MOJO_RESULT_OK, result) << "Failed to unwrap SharedBufferHandle";
-  if (!memory_size || memory_size != num_bytes.ValueOrDie()) {
-    DLOG(ERROR) << "Invalid image size";
+  // First convert SkBitmap to CGImageRef.
+  base::ScopedCFTypeRef<CGImageRef> cg_image(
+      SkCreateCGImageRefWithColorspace(bitmap, NULL));
+  if (!cg_image) {
+    DLOG(ERROR) << "Failed to create CGImageRef";
     return base::scoped_nsobject<CIImage>();
   }
 
-  auto shared_memory =
-      base::MakeUnique<base::SharedMemory>(memory_handle, true /* read_only */);
-  if (!shared_memory->Map(memory_size)) {
-    DLOG(ERROR) << "Failed to map bytes from shared memory";
-    return base::scoped_nsobject<CIImage>();
-  }
-
-  NSData* byte_data = [NSData dataWithBytesNoCopy:shared_memory->memory()
-                                           length:num_bytes.ValueOrDie()
-                                     freeWhenDone:NO];
-
-  base::ScopedCFTypeRef<CGColorSpaceRef> colorspace(
-      CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
-
-  // CIImage will return nil if RGBA8 is not supported in a certain version.
-  base::scoped_nsobject<CIImage> ci_image([[CIImage alloc]
-      initWithBitmapData:byte_data
-             bytesPerRow:width * 4
-                    size:CGSizeMake(width, height)
-                  format:kCIFormatRGBA8
-              colorSpace:colorspace]);
+  base::scoped_nsobject<CIImage> ci_image(
+      [[CIImage alloc] initWithCGImage:cg_image]);
   if (!ci_image) {
     DLOG(ERROR) << "Failed to create CIImage";
     return base::scoped_nsobject<CIImage>();
diff --git a/services/shape_detection/face_detection_impl_mac.h b/services/shape_detection/face_detection_impl_mac.h
index fb978c7..459ffa7 100644
--- a/services/shape_detection/face_detection_impl_mac.h
+++ b/services/shape_detection/face_detection_impl_mac.h
@@ -7,6 +7,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "services/shape_detection/public/interfaces/facedetection.mojom.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 
 @class CIDetector;
 
@@ -18,9 +19,7 @@
       shape_detection::mojom::FaceDetectorOptionsPtr options);
   ~FaceDetectionImplMac() override;
 
-  void Detect(mojo::ScopedSharedBufferHandle frame_data,
-              uint32_t width,
-              uint32_t height,
+  void Detect(const SkBitmap& bitmap,
               const shape_detection::mojom::FaceDetection::DetectCallback&
                   callback) override;
 
diff --git a/services/shape_detection/face_detection_impl_mac.mm b/services/shape_detection/face_detection_impl_mac.mm
index 151e0a7c..8bece619 100644
--- a/services/shape_detection/face_detection_impl_mac.mm
+++ b/services/shape_detection/face_detection_impl_mac.mm
@@ -47,21 +47,19 @@
 
 FaceDetectionImplMac::~FaceDetectionImplMac() {}
 
-void FaceDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
-                                  uint32_t width,
-                                  uint32_t height,
+void FaceDetectionImplMac::Detect(const SkBitmap& bitmap,
                                   const DetectCallback& callback) {
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithFaces, callback),
       base::Bind(&RunCallbackWithNoFaces));
 
-  base::scoped_nsobject<CIImage> ci_image =
-      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
+  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
+  const int height = bitmap.height();
   shape_detection::mojom::FaceDetectionResultPtr faces =
       shape_detection::mojom::FaceDetectionResult::New();
   for (CIFaceFeature* const f in features) {
diff --git a/services/shape_detection/face_detection_impl_mac_unittest.mm b/services/shape_detection/face_detection_impl_mac_unittest.mm
index e07f700f..9b9c569 100644
--- a/services/shape_detection/face_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/face_detection_impl_mac_unittest.mm
@@ -76,24 +76,12 @@
   const int num_bytes = size.GetArea() * 4 /* bytes per pixel */;
   ASSERT_EQ(num_bytes, image->computeSize64());
 
-  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
-  // copy the image pixels into it.
-  mojo::ScopedSharedBufferHandle handle =
-      mojo::SharedBufferHandle::Create(num_bytes);
-  ASSERT_TRUE(handle->is_valid());
-
-  mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
-  ASSERT_TRUE(mapping);
-
-  memcpy(mapping.get(), image->getPixels(), num_bytes);
-
   base::RunLoop run_loop;
   base::Closure quit_closure = run_loop.QuitClosure();
   // Send the image to Detect() and expect the response in callback.
   EXPECT_CALL(*this, Detection(1)).WillOnce(RunClosure(quit_closure));
-  impl_->Detect(std::move(handle), size.width(), size.height(),
-                base::Bind(&FaceDetectionImplMacTest::DetectCallback,
-                           base::Unretained(this)));
+  impl_->Detect(*image, base::Bind(&FaceDetectionImplMacTest::DetectCallback,
+                                   base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/services/shape_detection/public/interfaces/BUILD.gn b/services/shape_detection/public/interfaces/BUILD.gn
index 953742864..44522415 100644
--- a/services/shape_detection/public/interfaces/BUILD.gn
+++ b/services/shape_detection/public/interfaces/BUILD.gn
@@ -14,6 +14,7 @@
   ]
 
   public_deps = [
+    "//skia/public/interfaces",
     "//ui/gfx/geometry/mojo",
   ]
 }
diff --git a/services/shape_detection/public/interfaces/barcodedetection.mojom b/services/shape_detection/public/interfaces/barcodedetection.mojom
index 27f95ecd..5ae9aef5 100644
--- a/services/shape_detection/public/interfaces/barcodedetection.mojom
+++ b/services/shape_detection/public/interfaces/barcodedetection.mojom
@@ -6,6 +6,7 @@
 
 module shape_detection.mojom;
 
+import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 struct BarcodeDetectionResult {
@@ -17,9 +18,7 @@
 };
 
 interface BarcodeDetection {
-  // |frame_data| contains tightly packed image pixels in ARGB32 format,
-  // row-major order.
-  // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488.
-  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
+  // |bitmap_data| contains tightly packed image pixels in row-major order.
+  Detect(skia.mojom.Bitmap bitmap_data)
     => (array<BarcodeDetectionResult> results);
 };
diff --git a/services/shape_detection/public/interfaces/facedetection.mojom b/services/shape_detection/public/interfaces/facedetection.mojom
index 38102f8..0ee1390 100644
--- a/services/shape_detection/public/interfaces/facedetection.mojom
+++ b/services/shape_detection/public/interfaces/facedetection.mojom
@@ -6,6 +6,7 @@
 
 module shape_detection.mojom;
 
+import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // Since "//ui/gfx/geometry/mojo" is not exposed to blink, we need to declare
@@ -21,9 +22,7 @@
 };
 
 interface FaceDetection {
-  // |frame_data| contains tightly packed image pixels in ARGB32 format,
-  // row-major order.
-  // TODO(mcasas): Consider using mojo::Bitmap here, https://crbug.com/665488.
-  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
+  // |bitmap_data| contains tightly packed image pixels in row-major order.
+  Detect(skia.mojom.Bitmap bitmap_data)
     => (FaceDetectionResult result);
 };
diff --git a/services/shape_detection/public/interfaces/textdetection.mojom b/services/shape_detection/public/interfaces/textdetection.mojom
index 6e8bb01..7a0fed5 100644
--- a/services/shape_detection/public/interfaces/textdetection.mojom
+++ b/services/shape_detection/public/interfaces/textdetection.mojom
@@ -4,6 +4,7 @@
 
 module shape_detection.mojom;
 
+import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 struct TextDetectionResult {
@@ -12,8 +13,7 @@
 };
 
 interface TextDetection {
-  // |frame_data| contains tightly packed image pixels in ARGB32 format,
-  // row-major order.
-  Detect(handle<shared_buffer> frame_data, uint32 width, uint32 height)
+  // |bitmap_data| contains tightly packed image pixels in row-major order.
+  Detect(skia.mojom.Bitmap bitmap_data)
     => (array<TextDetectionResult> results);
 };
diff --git a/services/shape_detection/text_detection_impl_mac.h b/services/shape_detection/text_detection_impl_mac.h
index d86be927..738d8da 100644
--- a/services/shape_detection/text_detection_impl_mac.h
+++ b/services/shape_detection/text_detection_impl_mac.h
@@ -17,9 +17,7 @@
   TextDetectionImplMac();
   ~TextDetectionImplMac() override;
 
-  void Detect(mojo::ScopedSharedBufferHandle frame_data,
-              uint32_t width,
-              uint32_t height,
+  void Detect(const SkBitmap& bitmap,
               const mojom::TextDetection::DetectCallback& callback) override;
 
  private:
diff --git a/services/shape_detection/text_detection_impl_mac.mm b/services/shape_detection/text_detection_impl_mac.mm
index 3894770a..45d8d46 100644
--- a/services/shape_detection/text_detection_impl_mac.mm
+++ b/services/shape_detection/text_detection_impl_mac.mm
@@ -48,22 +48,20 @@
 
 TextDetectionImplMac::~TextDetectionImplMac() {}
 
-void TextDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
-                                  uint32_t width,
-                                  uint32_t height,
+void TextDetectionImplMac::Detect(const SkBitmap& bitmap,
                                   const DetectCallback& callback) {
   DCHECK(base::mac::IsAtLeastOS10_11());
   media::ScopedResultCallback<DetectCallback> scoped_callback(
       base::Bind(&RunCallbackWithResults, callback),
       base::Bind(&RunCallbackWithNoResults));
 
-  base::scoped_nsobject<CIImage> ci_image =
-      CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
+  base::scoped_nsobject<CIImage> ci_image = CreateCIImageFromSkBitmap(bitmap);
   if (!ci_image)
     return;
 
   NSArray* const features = [detector_ featuresInImage:ci_image];
 
+  const int height = bitmap.height();
   std::vector<mojom::TextDetectionResultPtr> results;
   for (CIRectangleFeature* const f in features) {
     // CIRectangleFeature only has bounding box information.
diff --git a/services/shape_detection/text_detection_impl_mac_unittest.mm b/services/shape_detection/text_detection_impl_mac_unittest.mm
index 5333a51..7b27fe0 100644
--- a/services/shape_detection/text_detection_impl_mac_unittest.mm
+++ b/services/shape_detection/text_detection_impl_mac_unittest.mm
@@ -12,6 +12,7 @@
 #include "base/run_loop.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/utils/mac/SkCGUtils.h"
 #include "ui/gl/gl_switches.h"
 
 namespace shape_detection {
@@ -81,29 +82,15 @@
   EXPECT_EQ(static_cast<size_t>(width), CGImageGetWidth(cg_image));
   EXPECT_EQ(static_cast<size_t>(height), CGImageGetHeight(cg_image));
 
-  base::ScopedCFTypeRef<CFDataRef> raw_cg_image_data(
-      CGDataProviderCopyData(CGImageGetDataProvider(cg_image)));
-  EXPECT_TRUE(CFDataGetBytePtr(raw_cg_image_data));
-  const int num_bytes = width * height * 4;
-  EXPECT_EQ(num_bytes, CFDataGetLength(raw_cg_image_data));
-
-  // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
-  // copy the generated text image pixels into it.
-  auto handle = mojo::SharedBufferHandle::Create(num_bytes);
-  ASSERT_TRUE(handle->is_valid());
-
-  mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
-  ASSERT_TRUE(mapping);
-
-  memcpy(mapping.get(), CFDataGetBytePtr(raw_cg_image_data), num_bytes);
+  SkBitmap bitmap;
+  ASSERT_TRUE(SkCreateBitmapFromCGImage(&bitmap, cg_image));
 
   base::RunLoop run_loop;
   base::Closure quit_closure = run_loop.QuitClosure();
   // Send the image to Detect() and expect the response in callback.
   EXPECT_CALL(*this, Detection(1)).WillOnce(RunClosure(quit_closure));
-  impl_.Detect(std::move(handle), width, height,
-               base::Bind(&TextDetectionImplMacTest::DetectCallback,
-                          base::Unretained(this)));
+  impl_.Detect(bitmap, base::Bind(&TextDetectionImplMacTest::DetectCallback,
+                                  base::Unretained(this)));
 
   run_loop.Run();
 }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 673bc0f..30934a5 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1402,6 +1402,20 @@
 
 crbug.com/700795 [ Mac ] inspector/animation/animation-transition-setTiming-crash.html [ Timeout Pass ]
 
+crbug.com/701500 inspector-protocol/debugger/debugger-doesnt-step-into-injected-script.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-pause/pause-on-elements-panel.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-into-across-timeouts.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-into-document-write.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-out-across-timeouts.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-out-document-write.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-out-event-listener.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-over-across-timeouts.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-over-document-write.html [ NeedsManualRebaseline ]
+crbug.com/701500 inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html [ NeedsManualRebaseline ]
+
 # Flaky on Win10 and Win7
 crbug.com/619539 [ Win ] http/tests/workers/terminate-during-sync-operation-file.html [ Pass Timeout ]
 crbug.com/619539 [ Win ] virtual/mojo-loading/http/tests/workers/terminate-during-sync-operation-file.html [ Pass Timeout ]
@@ -2651,7 +2665,7 @@
 crbug.com/698521 external/wpt/preload/preload-with-type.html [ Failure Pass ]
 
 # Sheriff failures 2017-03-10
-crbug.com/402805 [ Mac10.10 Mac10.11 Mac10.12 Win10 ] inspector-protocol/input/emulateTouchFromMouseEvent.html [ Timeout ]
+crbug.com/402805 [ Mac10.10 Mac10.11 Mac10.12 Win7 Win10 ] inspector-protocol/input/emulateTouchFromMouseEvent.html [ Timeout ]
 crbug.com/700374 [ Win ] virtual/mojo-loading/http/tests/inspector/workers-on-navigation.html [ Failure Pass ]
 crbug.com/700374 [ Win ] http/tests/inspector/workers-on-navigation.html [ Failure Pass ]
 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-interpolation.html
new file mode 100644
index 0000000..832b8101
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-interpolation.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+.target {
+  width: 10px;
+  height: 10px;
+  background-color: black;
+}
+.expected {
+  background-color: green;
+}
+</style>
+<body>
+<script src="resources/interpolation-test.js"></script>
+<script>
+
+assertInterpolation({
+  property: 'border',
+  from: '10px solid #000',
+  to: '20px dashed #000',
+  method: 'CSS Transitions',
+}, [
+  {at: -0.3, is: '7px dashed #000'},
+  {at: 0, is: '10px dashed #000'},
+  {at: 0.3, is: '13px dashed #000'},
+  {at: 0.6, is: '16px dashed #000'},
+  {at: 1, is: '20px dashed #000'},
+  {at: 1.5, is: '25px dashed #000'},
+]);
+
+assertInterpolation({
+  property: 'border',
+  from: '10px solid #000',
+  to: '20px dashed #000',
+  method: 'CSS Animations',
+}, [
+  {at: -0.3, is: '7px solid #000'},
+  {at: 0, is: '10px solid #000'},
+  {at: 0.3, is: '13px solid #000'},
+  {at: 0.6, is: '16px dashed #000'},
+  {at: 1, is: '20px dashed #000'},
+  {at: 1.5, is: '25px dashed #000'},
+]);
+
+assertInterpolation({
+  property: 'border',
+  from: '10px solid #000',
+  to: '20px dashed #000',
+  method: 'Web Animations',
+}, [
+  {at: -0.3, is: '7px solid #000'},
+  {at: 0, is: '10px solid #000'},
+  {at: 0.3, is: '13px solid #000'},
+  {at: 0.6, is: '16px dashed #000'},
+  {at: 1, is: '20px dashed #000'},
+  {at: 1.5, is: '25px dashed #000'},
+]);
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/offset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/offset-interpolation.html
new file mode 100644
index 0000000..7bdcdcfe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/offset-interpolation.html
@@ -0,0 +1,102 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<style>
+.target {
+  width: 10px;
+  height: 10px;
+  background-color: black;
+}
+.expected {
+  background-color: green;
+}
+</style>
+<body>
+<script src="resources/interpolation-test.js"></script>
+<script>
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 200H 700") 500px 800deg',
+  to: 'path("M0 300H 700 Z") 600px 900deg',
+  method: 'CSS Transitions',
+}, [
+  {at: -0.3, is: 'path("M0 300H 700 Z") 470px 770deg'},
+  {at: 0, is: 'path("M0 300H 700 Z") 500px 800deg'},
+  {at: 0.3, is: 'path("M0 300H 700 Z") 530px 830deg'},
+  {at: 0.6, is: 'path("M0 300H 700 Z") 560px 860deg'},
+  {at: 1, is: 'path("M0 300H 700 Z") 600px 900deg'},
+  {at: 1.5, is: 'path("M0 300H 700 Z") 650px 950deg'},
+]);
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 0H 200") 500px auto',
+  to: 'path("M0 0H 300") 600px 0deg',
+  method: 'CSS Transitions',
+}, [
+  {at: -0.3, is: 'path("M0 0H 300") 470px 0deg'},
+  {at: 0, is: 'path("M0 0H 300") 500px 0deg'},
+  {at: 0.3, is: 'path("M0 0H 300") 530px 0deg'},
+  {at: 0.6, is: 'path("M0 0H 300") 560px 0deg'},
+  {at: 1, is: 'path("M0 0H 300") 600px 0deg'},
+  {at: 1.5, is: 'path("M0 0H 300") 650px 0deg'},
+]);
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 200H 700") 500px 800deg',
+  to: 'path("M0 300H 700 Z") 600px 900deg',
+  method: 'CSS Animations',
+}, [
+  {at: -0.3, is: 'path("M0 200H 700") 470px 770deg'},
+  {at: 0, is: 'path("M0 200H 700") 500px 800deg'},
+  {at: 0.3, is: 'path("M0 200H 700") 530px 830deg'},
+  {at: 0.6, is: 'path("M0 300H 700 Z") 560px 860deg'},
+  {at: 1, is: 'path("M0 300H 700 Z") 600px 900deg'},
+  {at: 1.5, is: 'path("M0 300H 700 Z") 650px 950deg'},
+]);
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 0H 200") 500px auto',
+  to: 'path("M0 0H 300") 600px 0deg',
+  method: 'CSS Animations',
+}, [
+  {at: -0.3, is: 'path("M0 0H 200") 470px auto'},
+  {at: 0, is: 'path("M0 0H 200") 500px auto'},
+  {at: 0.3, is: 'path("M0 0H 200") 530px auto'},
+  {at: 0.6, is: 'path("M0 0H 300") 560px 0deg'},
+  {at: 1, is: 'path("M0 0H 300") 600px 0deg'},
+  {at: 1.5, is: 'path("M0 0H 300") 650px 0deg'},
+]);
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 200H 700") 500px 800deg',
+  to: 'path("M0 300H 700 Z") 600px 900deg',
+  method: 'Web Animations',
+}, [
+  {at: -0.3, is: 'path("M0 200H 700") 470px 770deg'},
+  {at: 0, is: 'path("M0 200H 700") 500px 800deg'},
+  {at: 0.3, is: 'path("M0 200H 700") 530px 830deg'},
+  {at: 0.6, is: 'path("M0 300H 700 Z") 560px 860deg'},
+  {at: 1, is: 'path("M0 300H 700 Z") 600px 900deg'},
+  {at: 1.5, is: 'path("M0 300H 700 Z") 650px 950deg'},
+]);
+
+assertInterpolation({
+  property: 'offset',
+  from: 'path("M0 0H 200") 500px auto',
+  to: 'path("M0 0H 300") 600px 0deg',
+  method: 'Web Animations',
+}, [
+  {at: -0.3, is: 'path("M0 0H 200") 470px auto'},
+  {at: 0, is: 'path("M0 0H 200") 500px auto'},
+  {at: 0.3, is: 'path("M0 0H 200") 530px auto'},
+  {at: 0.6, is: 'path("M0 0H 300") 560px 0deg'},
+  {at: 1, is: 'path("M0 0H 300") 600px 0deg'},
+  {at: 1.5, is: 'path("M0 0H 300") 650px 0deg'},
+]);
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js b/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
index 4539a679..07b0853 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
@@ -136,6 +136,8 @@
             property = property.substring(0, i) + property[i + 1].toUpperCase() + property.substring(i + 2);
           }
         }
+        if (property === 'offset')
+          property = 'cssOffset';
       }
       var keyframes = [];
       if (!isNeutralKeyframe(from)) {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-doesnt-step-into-injected-script-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-doesnt-step-into-injected-script-expected.txt
index eab57bfa..204ea45c 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-doesnt-step-into-injected-script-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-doesnt-step-into-injected-script-expected.txt
@@ -14,6 +14,6 @@
 
 Perform stepInto
 Stack trace:
-foo:5:12
+foo:7:4
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/elements-img-tooltip.html b/third_party/WebKit/LayoutTests/inspector/elements/elements-img-tooltip.html
index 0385d0e..4929505 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/elements-img-tooltip.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/elements-img-tooltip.html
@@ -13,7 +13,7 @@
 
     function step1(node)
     {
-        InspectorTest.firstElementsTreeOutline()._loadDimensionsForNode(node, step2);
+        InspectorTest.firstElementsTreeOutline()._loadDimensionsForNode(node).then(step2);
     }
 
     function step2(dimensions)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
index 75f29638..d01eacb 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
@@ -19,7 +19,7 @@
 
 Executing StepInto...
 Call stack:
-    0) callback (frameworks-step-into-skips-setTimeout.html:15)
+    0) callback (frameworks-step-into-skips-setTimeout.html:17)
   * 1) Framework_scheduleUntilDone (framework.js:142)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/pause-on-elements-panel-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/pause-on-elements-panel-expected.txt
index 07e2d01..f203eda 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/pause-on-elements-panel-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-pause/pause-on-elements-panel-expected.txt
@@ -1,6 +1,6 @@
 Tests that debugger pause button works on Elements panel after a DOM node highlighting. Chromium bug 433366
 
 Call stack:
-    0) callback (pause-on-elements-panel.html:8)
+    0) callback (pause-on-elements-panel.html:10)
 PASS: Debugger paused.
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-across-timeouts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-across-timeouts-expected.txt
index 04eab25..0e1c66e0 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-across-timeouts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-across-timeouts-expected.txt
@@ -7,6 +7,6 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) callback2 (debugger-step-into-across-timeouts.html:18)
+    0) callback2 (debugger-step-into-across-timeouts.html:20)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write-expected.txt
index d578283..241a77e 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write-expected.txt
@@ -6,11 +6,6 @@
 
 Executing StepInto...
 Call stack:
-    0)  (:1)
-    1)  (debugger-step-into-document-write.html:4)
-
-Executing StepInto...
-Call stack:
     0)  (:5)
     1)  (debugger-step-into-document-write.html:4)
 
@@ -37,7 +32,7 @@
 
 Executing StepInto...
 Call stack:
-    0)  (debugger-step-into-document-write.html:7)
+    0)  (debugger-step-into-document-write.html:8)
 
 Executing StepInto...
 Call stack:
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write.html
index 180b9ad..08e42ab 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-document-write.html
@@ -15,7 +15,7 @@
 
 function test()
 {
-    var numberOfStepInto = 8;
+    var numberOfStepInto = 7;
 
     InspectorTest.startDebuggerTest(step1, true);
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
index 2e14f2d..8dc8ec8 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
@@ -16,10 +16,6 @@
 
 Executing StepInto...
 Call stack:
-    0)  (debugger-step-into-inlined-scripts.html:12)
-
-Executing StepInto...
-Call stack:
     0)  (debugger-step-into-inlined-scripts.html:17)
 
 Executing StepInto...
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html
index 1a09a42..fae7e5f 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html
@@ -24,7 +24,7 @@
 
 function test()
 {
-    var numberOfStepInto = 7;
+    var numberOfStepInto = 6;
 
     InspectorTest.startDebuggerTest(step1, true);
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-across-timeouts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-across-timeouts-expected.txt
index 307c071..3e085c1 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-across-timeouts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-across-timeouts-expected.txt
@@ -6,6 +6,6 @@
 
 Executing StepOut...
 Call stack:
-    0) callback2 (debugger-step-out-across-timeouts.html:19)
+    0) callback2 (debugger-step-out-across-timeouts.html:21)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks-expected.txt
index c87abf4..262f431 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks-expected.txt
@@ -14,7 +14,6 @@
     0) testFunction (debugger-step-out-custom-element-callbacks.html:29)
 
 Executing StepInto...
-Executing StepInto...
 Call stack:
     0) attributeChangedCallback (debugger-step-out-custom-element-callbacks.html:25)
     1) testFunction (debugger-step-out-custom-element-callbacks.html:29)
@@ -24,7 +23,6 @@
     0) testFunction (debugger-step-out-custom-element-callbacks.html:30)
 
 Executing StepInto...
-Executing StepInto...
 Call stack:
     0) attachedCallback (debugger-step-out-custom-element-callbacks.html:17)
     1) testFunction (debugger-step-out-custom-element-callbacks.html:30)
@@ -34,7 +32,6 @@
     0) testFunction (debugger-step-out-custom-element-callbacks.html:31)
 
 Executing StepInto...
-Executing StepInto...
 Call stack:
     0) detachedCallback (debugger-step-out-custom-element-callbacks.html:21)
     1) testFunction (debugger-step-out-custom-element-callbacks.html:31)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html
index e4363b8f8..56d73a5 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-custom-element-callbacks.html
@@ -45,11 +45,11 @@
         var actions = [
             "Print", // debugger; in createdCallback
             "StepOut", "Print", // at foo.setAttribute()
-            "StepInto", "StepInto", "Print", // at attributeChangedCallback
+            "StepInto", "Print", // at attributeChangedCallback
             "StepOut", "Print", // at document.body.appendChild()
-            "StepInto", "StepInto", "Print", // at attachedCallback
+            "StepInto", "Print", // at attachedCallback
             "StepOut", "Print", // at foo.remove()
-            "StepInto", "StepInto", "Print", // at detachedCallback
+            "StepInto", "Print", // at detachedCallback
             "StepOut", "Print", // at testFunction() return point
         ];
         InspectorTest.waitUntilPausedAndPerformSteppingActions(actions, step3);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-document-write-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-document-write-expected.txt
index 0e1177d..466abc6 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-document-write-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-document-write-expected.txt
@@ -6,11 +6,11 @@
 
 Executing StepOut...
 Call stack:
-    0)  (debugger-step-out-document-write.html:9)
+    0)  (debugger-step-out-document-write.html:10)
 
 Executing StepOut...
 Call stack:
-    0)  (debugger-step-out-document-write.html:12)
+    0)  (debugger-step-out-document-write.html:18)
 
 Executing StepOut...
 Call stack:
@@ -23,7 +23,7 @@
 
 Executing StepOut...
 Call stack:
-    0)  (debugger-step-out-document-write.html:20)
+    0)  (debugger-step-out-document-write.html:21)
 
 Executing Resume...
 Page reloaded.
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-event-listener-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-event-listener-expected.txt
index 60ba0b7..9def0dfa 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-event-listener-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-out-event-listener-expected.txt
@@ -10,13 +10,13 @@
 Executing StepInto...
 Executing StepInto...
 Call stack:
-    0) fooEventHandler1 (debugger-step-out-event-listener.html:14)
+    0) fooEventHandler1 (debugger-step-out-event-listener.html:15)
     1) inner (debugger-step-out-event-listener.html:27)
     2) testFunction (debugger-step-out-event-listener.html:32)
 
 Executing StepOut...
 Call stack:
-    0) fooEventHandler2 (debugger-step-out-event-listener.html:17)
+    0) fooEventHandler2 (debugger-step-out-event-listener.html:19)
     1) inner (debugger-step-out-event-listener.html:27)
     2) testFunction (debugger-step-out-event-listener.html:32)
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-across-timeouts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-across-timeouts-expected.txt
index fb0d1210..f0beb72d 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-across-timeouts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-across-timeouts-expected.txt
@@ -7,6 +7,6 @@
 Executing StepOver...
 Executing StepOver...
 Call stack:
-    0) callback2 (debugger-step-over-across-timeouts.html:18)
+    0) callback2 (debugger-step-over-across-timeouts.html:20)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write-expected.txt
index b9bc3ce..c700f97 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write-expected.txt
@@ -10,10 +10,6 @@
 
 Executing StepOver...
 Call stack:
-    0)  (debugger-step-over-document-write.html:7)
-
-Executing StepOver...
-Call stack:
     0)  (debugger-step-over-document-write.html:8)
 
 Executing StepOver...
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write.html
index 05f8a120..4fde2ded 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-document-write.html
@@ -15,7 +15,7 @@
 
 function test()
 {
-    var numberOfStepOver = 4;
+    var numberOfStepOver = 3;
 
     InspectorTest.startDebuggerTest(step1, true);
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
index e0ebd50..2a44a8c 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
@@ -16,10 +16,6 @@
 
 Executing StepOver...
 Call stack:
-    0)  (debugger-step-over-inlined-scripts.html:12)
-
-Executing StepOver...
-Call stack:
     0)  (debugger-step-over-inlined-scripts.html:17)
 
 Executing StepOver...
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html
index 9afe966..d70debf 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html
@@ -24,7 +24,7 @@
 
 function test()
 {
-    var numberOfStepOver = 5;
+    var numberOfStepOver = 4;
 
     InspectorTest.startDebuggerTest(step1, true);
 
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
index 1f6a479..129c660ee 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-barcodedetection.js
@@ -18,8 +18,8 @@
           handle => this.bindingSet_.addBinding(this, handle));
     }
 
-    detect(frame_data, width, height) {
-      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
+    detect(bitmap_data) {
+      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         results: [
@@ -45,7 +45,6 @@
           },
         ],
       });
-      mojo.unmapBuffer(receivedStruct.buffer);
     }
 
     getFrameData() {
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
index 1faf89f..c02fda2 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-facedetection.js
@@ -44,8 +44,8 @@
                                            request);
     }
 
-    detect(frame_data, width, height) {
-      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
+    detect(bitmap_data) {
+      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         result: {
@@ -56,7 +56,6 @@
           ]
         }
       });
-      mojo.unmapBuffer(receivedStruct.buffer);
     }
   }
   return new MockFaceDetectionProvider();
diff --git a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
index 08195c9..a622605 100644
--- a/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
+++ b/third_party/WebKit/LayoutTests/shapedetection/resources/mock-textdetection.js
@@ -17,8 +17,8 @@
           handle => this.bindingSet_.addBinding(this, handle));
     }
 
-    detect(frame_data, width, height) {
-      let receivedStruct = mojo.mapBuffer(frame_data, 0, width*height*4, 0);
+    detect(bitmap_data) {
+      let receivedStruct = new Uint8Array(bitmap_data.pixel_data);
       this.buffer_data_ = new Uint32Array(receivedStruct.buffer);
       return Promise.resolve({
         results: [
@@ -32,7 +32,6 @@
           },
         ],
       });
-      mojo.unmapBuffer(receivedStruct.buffer);
     }
 
     getFrameData() {
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
index 12d089bd..9d263d4 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-custom-sweep-snr.html
@@ -21,8 +21,9 @@
 
         // The thresholds are experimentally determined.
         tester.setThresholds({
-          snr: 93.450,
-          maxDiff: 0.00004
+          snr: 1000,
+          maxDiff: 0,
+          diffCount: 0
         });
         tester.runTest(context, "custom",
           "Custom Oscillator with Exponential Sweep", task, should);
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
index 8d90c61..e0ec7d8 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sawtooth-sweep-snr.html
@@ -3,7 +3,7 @@
   <head>
     <title>Test Oscillator Node: sawtooth</title>
     <script src="../../resources/testharness.js"></script>
-    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../../resources/testharnessreport.js"></script> 
     <script src="../resources/audit-util.js"></script>
     <script src="../resources/audit.js"></script>
     <script src="../resources/buffer-loader.js"></script>
@@ -21,11 +21,13 @@
 
         // The thresholds are experimentally determined.
         tester.setThresholds({
-          snr: 92.858,
-          maxDiff: 0.0001
+          snr: 1000,
+          maxDiff: 0,
+          diffCount: 0
         });
         tester.runTest(context, "sawtooth",
-          "Sawtooth Oscillator with Exponential Sweep", task, should);
+          "Sawtooth Oscillator with Exponential Sweep",
+          task, should);
       });
 
       audit.run();
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
index e5937b7..d56ea415 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-sine-sweep-snr.html
@@ -21,11 +21,13 @@
 
         // The thresholds are experimentally determined.
         tester.setThresholds({
-          snr: 94.001,
-          maxDiff: 0.00006
+          snr: 1000,
+          maxDiff: 0,
+          diffCount: 0
         });
         tester.runTest(context, "sine",
-          "Sine Oscillator with Exponential Sweep", task, should);
+          "Sine Oscillator with Exponential Sweep",
+          task, should);
       });
 
       audit.run();
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
index 2a3d350..3389a666 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-square-sweep-snr.html
@@ -21,8 +21,9 @@
 
         // The thresholds are experimentally determined.
         tester.setThresholds({
-          snr: 93.325,
-          maxDiff: 0.00011
+          snr: 1000,
+          maxDiff: 0,
+          diffCount: 0
         });
         tester.runTest(context, "square",
           "Square Oscillator with Exponential Sweep", task, should);
diff --git a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
index 5d0366d..9728229 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Oscillator/osc-triangle-sweep-snr.html
@@ -19,10 +19,12 @@
         let context = new OfflineAudioContext(1, tester.sampleRate *
           tester.lengthInSeconds, tester.sampleRate);
 
-        // The thresholds are experimentally determined.
+        // Thresholds for verifying the test passes.  The thresholds are
+        // experimentally determined.
         tester.setThresholds({
-          snr: 93.92,
-          maxDiff: 0.00005
+          snr: 1000,
+          maxDiff: 0,
+          diffCount: 0
         });
         tester.runTest(context, "triangle",
           "Triangle Oscillator with Exponential Sweep ", task, should);
diff --git a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
index 2144ded4f..9e16ba8e 100644
--- a/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
+++ b/third_party/WebKit/LayoutTests/webaudio/PeriodicWave/periodicwave-contexts.html
@@ -33,7 +33,8 @@
         // The thresholds are experimentally determined.
         tester.setThresholds({
           snr: 80.00,
-          maxDiff: 4.06
+          maxDiff: 4.06,
+          diffCount: 15827
         });
         tester.runTest(context, "sawtooth", "Sawtooth PeriodicWave Test",
           task, should);
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
index ae615bdec..bd3051a5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/audit.js
@@ -1191,19 +1191,15 @@
   function loadFileFromUrl (fileUrl) {
     return new Promise((resolve, reject) => {
       let xhr = new XMLHttpRequest();
-      xhr.open('GET', fileUrl, true);
+      xhr.open('GET', fileUrl);
       xhr.responseType = 'arraybuffer';
 
       xhr.onload = () => {
-        // |status = 0| is a workaround for the run-webkit-test server. We are
-        // speculating the server quits the transaction prematurely without
-        // completing the request.
-        if (xhr.status === 200 || xhr.status === 0) {
+        if (xhr.status === 200) {
           resolve(xhr.response);
         } else {
           let errorMessage = 'loadFile: Request failed when loading ' +
-              fileUrl + '. ' + xhr.statusText + '. (status = ' +
-              xhr.status + ')';
+              fileUrl + '. (' + xhr.statusText + ')';
           if (reject) {
             reject(errorMessage);
           } else {
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
index f2d8f9c..8454386 100644
--- a/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
+++ b/third_party/WebKit/LayoutTests/webaudio/resources/oscillator-testing.js
@@ -43,6 +43,10 @@
 // Max diff must be less than this to pass the test.
 var thresholdDiff = 0;
 
+// Count the number of differences between the expected and actual result. The tests passes
+// if the count is less than this threshold.
+var thresholdDiffCount = 0;
+
 // Mostly for debugging
 
 // An AudioBuffer for the reference (expected) result.
@@ -119,6 +123,11 @@
             maxError = Math.abs(diff);
             errorPosition = k;
         }
+        // The reference file is a 16-bit WAV file, so we will almost never get an exact match
+        // between it and the actual floating-point result.
+        if (diff > 0) {
+            diffCount++;
+        }
     }
 
     var snr = calculateSNR(signalPower, noisePower);
@@ -127,6 +136,11 @@
     should(maxError, "Maximum difference")
         .beLessThanOrEqualTo(thresholdDiff);
 
+    should(diffCount,
+           "Number of differences between actual and expected result out of "
+           + renderedData.length + " frames")
+        .beLessThanOrEqualTo(thresholdDiffCount);
+
     var filename = "oscillator-" + oscType + "-actual.wav";
     if (downloadAudioBuffer(renderedBuffer, filename, true))
       should(true, "Saved reference file").message(filename, "");
@@ -147,6 +161,7 @@
     lengthInSeconds: lengthInSeconds,
     thresholdSNR: thresholdSNR,
     thresholdDiff: thresholdDiff,
+    thresholdDiffCount: thresholdDiffCount,
     waveScaleFactor: waveScaleFactor,
     setThresholds: setThresholds,
     runTest: runTest,
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
index 2f9ec0b0..bf82aa1 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-expected.txt
@@ -33,13 +33,10 @@
 PASS   Suspending OAC with no argument rejected correctly with TypeError. 
 PASS   Start OAC rendering resolved correctly. 
 PASS < [basic] All assertions passed. (total 20 assertions) 
-PASS > [load-file-in-should] Test Audit.loadFileFromUrl() within |should| assertion. 
-PASS   Loading file within should().beResolved() resolved correctly. 
-PASS < [load-file-in-should] All assertions passed. (total 1 assertions) 
 PASS > [dummy-label-string]  
 PASS < [dummy-label-string] All assertions passed. (total 0 assertions) 
 PASS > [dummy-label-object]  
 PASS < [dummy-label-object] All assertions passed. (total 0 assertions) 
-PASS # AUDIT TASK RUNNER FINISHED: 5 tasks ran successfully. 
+PASS # AUDIT TASK RUNNER FINISHED: 4 tasks ran successfully. 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures-expected.txt b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures-expected.txt
index edd8fd8..36ff95f 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures-expected.txt
@@ -90,9 +90,6 @@
 	[6]	7.0000000000000000e+0	8.0000000000000000e+2	7.9300000000000000e+2	9.9124999999999996e-1	0.0000000000000000e+0
  assert_true: expected true got false
 FAIL < [numerical-failures] 11 out of 11 assertions were failed. assert_true: expected true got false
-PASS > [load-file-in-should] Testing the failure handling of Audit.loadFileFromUrl(). 
-FAIL X Loading non-existent file within should().beResolved() rejected incorrectly with loadFile: Network failure when loading non-existent-audio-file.wav.. Got undefined. assert_true: expected true got false
-FAIL < [load-file-in-should] 1 out of 1 assertions were failed. assert_true: expected true got false
-FAIL # AUDIT TASK RUNNER FINISHED: 3 out of 3 tasks were failed. assert_true: expected true got false
+FAIL # AUDIT TASK RUNNER FINISHED: 2 out of 2 tasks were failed. assert_true: expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
index ccb863a..ea959d5 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit-failures.html
@@ -85,20 +85,6 @@
       task.done();
     });
 
-    // Testing the failure handling of Audit.loadFileFromUrl().
-    audit.define({ 
-        label: 'load-file-in-should',
-        description: 'Testing the failure handling of Audit.loadFileFromUrl().'
-      }, (task, should) => {
-        let url = 'non-existent-audio-file.wav';
-        let promise = should(
-            Audit.loadFileFromUrl(url),
-            'Loading non-existent file within should().beResolved()')
-                .beResolved();
-        promise.then(() => { task.done() });
-      }
-    );
-
     // With no argument, this executes all tasks in the order defined.
     audit.run();
   </script>
diff --git a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
index adb2d785..27bc852 100644
--- a/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
+++ b/third_party/WebKit/LayoutTests/webaudio/unit-tests/audit.html
@@ -65,20 +65,6 @@
       }
     );
 
-    // Test Audit.loadFileFromUrl() within |should| assertion.
-    // See: crbug.com/701813
-    audit.define({ 
-        label: 'load-file-in-should',
-        description: 'Test Audit.loadFileFromUrl() within |should| assertion.'
-      }, (task, should) => {
-        let url = '../resources/hyper-reality/laughter.wav';
-        let promise = should(Audit.loadFileFromUrl(url),
-                             'Loading file within should().beResolved()')
-                          .beResolved();
-        promise.then(() => { task.done() });
-      }
-    );
-
 
     // The task headline needs to be printed even if there is no description is
     // given.
@@ -103,8 +89,7 @@
 
     // You can enumerate tasks you want to execute in the order, or simply pass
     // no argument to run all the defined tasks.
-    audit.run('numerical', 'basic', 'load-file-in-should',
-              'dummy-label-string', 'dummy-label-object');
+    audit.run('numerical', 'basic', 'dummy-label-string', 'dummy-label-object');
   </script>
 </body>
 </html>
diff --git a/third_party/WebKit/Source/core/animation/AnimationInputHelpers.cpp b/third_party/WebKit/Source/core/animation/AnimationInputHelpers.cpp
index 5a0a86c..d3a9dca 100644
--- a/third_party/WebKit/Source/core/animation/AnimationInputHelpers.cpp
+++ b/third_party/WebKit/Source/core/animation/AnimationInputHelpers.cpp
@@ -42,6 +42,8 @@
     return CSSPropertyInvalid;
   if (property == "cssFloat")
     return CSSPropertyFloat;
+  if (property == "cssOffset")
+    return CSSPropertyOffset;
 
   StringBuilder builder;
   for (size_t i = 0; i < property.length(); ++i) {
diff --git a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
index ba85f542..a31d95a1 100644
--- a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
+++ b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
@@ -50,6 +50,12 @@
   return networkStateNotifier().connectionType() == WebConnectionTypeCellular2G;
 }
 
+bool isInterventionV2Enabled() {
+  return RuntimeEnabledFeatures::webFontsInterventionV2With2GEnabled() ||
+         RuntimeEnabledFeatures::webFontsInterventionV2With3GEnabled() ||
+         RuntimeEnabledFeatures::webFontsInterventionV2WithSlow2GEnabled();
+}
+
 }  // namespace
 
 RemoteFontFaceSource::RemoteFontFaceSource(FontResource* font,
@@ -197,20 +203,16 @@
       m_histograms.dataSource() == FontLoadHistograms::FromDataURL)
     return false;
 
-  bool isV2Enabled =
-      RuntimeEnabledFeatures::webFontsInterventionV2With2GEnabled() ||
-      RuntimeEnabledFeatures::webFontsInterventionV2With3GEnabled() ||
-      RuntimeEnabledFeatures::webFontsInterventionV2WithSlow2GEnabled();
-
   bool networkIsSlow =
-      isV2Enabled ? isEffectiveConnectionTypeSlowFor(m_fontSelector->document())
-                  : isConnectionTypeSlow();
+      isInterventionV2Enabled()
+          ? isEffectiveConnectionTypeSlowFor(m_fontSelector->document())
+          : isConnectionTypeSlow();
 
   return networkIsSlow && m_display == FontDisplayAuto;
 }
 
 bool RemoteFontFaceSource::isLowPriorityLoadingAllowedForRemoteFont() const {
-  return m_isInterventionTriggered;
+  return m_isInterventionTriggered && isInterventionV2Enabled();
 }
 
 PassRefPtr<SimpleFontData> RemoteFontFaceSource::createFontData(
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
index 2dbafa11..46aacf5 100644
--- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp
+++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -788,7 +788,6 @@
     child->detachLayoutTree(childrenContext);
 
   setChildNeedsStyleRecalc();
-  setChildNeedsReattachLayoutTree();
   Node::detachLayoutTree(context);
 }
 
@@ -801,10 +800,6 @@
       setChildNeedsStyleRecalc();
       markAncestorsWithChildNeedsStyleRecalc();
     }
-    if (!childNeedsReattachLayoutTree()) {
-      setChildNeedsReattachLayoutTree();
-      markAncestorsWithChildNeedsReattachLayoutTree();
-    }
   }
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 4b13bb38..4ba216f 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -139,7 +139,6 @@
 #include "core/frame/DOMVisualViewport.h"
 #include "core/frame/EventHandlerRegistry.h"
 #include "core/frame/FrameConsole.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/History.h"
 #include "core/frame/HostsUsingFeatures.h"
@@ -1661,9 +1660,6 @@
   return m_frame ? m_frame->page() : nullptr;
 }
 
-FrameHost* Document::frameHost() const {
-  return m_frame ? m_frame->host() : nullptr;
-}
 
 Settings* Document::settings() const {
   return m_frame ? m_frame->settings() : nullptr;
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index ea9df469..83ac390 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -108,7 +108,6 @@
 class FloatQuad;
 class FloatRect;
 class FormController;
-class FrameHost;
 class FrameRequestCallback;
 class FrameView;
 class HTMLAllCollection;
@@ -471,7 +470,6 @@
 
   FrameView* view() const;                       // can be null
   LocalFrame* frame() const { return m_frame; }  // can be null
-  FrameHost* frameHost() const;                  // can be null
   Page* page() const;                            // can be null
   Settings* settings() const;                    // can be null
 
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index 8043437..a403176 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -92,7 +92,6 @@
 #include "core/editing/serializers/Serialization.h"
 #include "core/events/EventDispatcher.h"
 #include "core/events/FocusEvent.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/HostsUsingFeatures.h"
 #include "core/frame/LocalDOMWindow.h"
@@ -154,11 +153,11 @@
 
 // We need to retain the scroll customization callbacks until the element
 // they're associated with is destroyed. It would be simplest if the callbacks
-// could be stored in ElementRareData, but we can't afford the space
-// increase. Instead, keep the scroll customization callbacks here. The other
-// option would be to store these callbacks on the FrameHost or document, but
-// that necessitates a bunch more logic for transferring the callbacks between
-// FrameHosts when elements are moved around.
+// could be stored in ElementRareData, but we can't afford the space increase.
+// Instead, keep the scroll customization callbacks here. The other option would
+// be to store these callbacks on the Page or document, but that necessitates a
+// bunch more logic for transferring the callbacks between Pages when elements
+// are moved around.
 ScrollCustomizationCallbacks& scrollCustomizationCallbacks() {
   DEFINE_STATIC_LOCAL(ScrollCustomizationCallbacks,
                       scrollCustomizationCallbacks,
@@ -605,8 +604,8 @@
   // or CC. http://crbug.com/625676.
   DisableCompositingQueryAsserts disabler;
 
-  if (!document().frameHost()) {
-    // We should always have a frameHost if we're scrolling. See
+  if (!document().page()) {
+    // We should always have a Page if we're scrolling. See
     // crbug.com/689074 for details.
     return;
   }
@@ -1882,8 +1881,13 @@
           elementAnimations->setAnimationStyleChange(false);
       }
     }
-    if (parentComputedStyle())
+    if (parentComputedStyle()) {
       change = recalcOwnStyle(change);
+    } else if (needsAttach()) {
+      setNeedsReattachLayoutTree();
+      change = Reattach;
+    }
+
     // Needed because the rebuildLayoutTree code needs to see what the
     // styleChangeType() was on reattach roots. See Node::reattachLayoutTree()
     // for an example.
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index 98b470d9..9e1e08e 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -725,6 +725,8 @@
 }
 
 void Node::setNeedsReattachLayoutTree() {
+  DCHECK(document().inStyleRecalc());
+  DCHECK(!document().childNeedsDistributionRecalc());
   setFlag(NeedsReattachLayoutTree);
   markAncestorsWithChildNeedsReattachLayoutTree();
 }
@@ -932,7 +934,6 @@
     layoutObject()->destroyAndCleanupAnonymousWrappers();
   setLayoutObject(nullptr);
   setStyleChange(NeedsReattachStyleChange);
-  setFlag(NeedsReattachLayoutTree);
   clearChildNeedsStyleInvalidation();
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index 870742f3..26d31c65 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -822,9 +822,7 @@
     NeedsReattachLayoutTree = 1 << 26,
     ChildNeedsReattachLayoutTree = 1 << 27,
 
-    DefaultNodeFlags = IsFinishedParsingChildrenFlag |
-                       NeedsReattachStyleChange |
-                       NeedsReattachLayoutTree
+    DefaultNodeFlags = IsFinishedParsingChildrenFlag | NeedsReattachStyleChange
   };
 
   // 4 bits remaining.
@@ -969,7 +967,6 @@
 
   detachLayoutTree(context);
   markAncestorsWithChildNeedsStyleRecalc();
-  markAncestorsWithChildNeedsReattachLayoutTree();
 }
 
 inline bool Node::shouldCallRecalcStyle(StyleRecalcChange change) {
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
index 3ea4dee..5037e303 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.cpp
@@ -104,32 +104,9 @@
   Member<Element> m_currentElement;
 };
 
-void SelectorDataList::initialize(const CSSSelectorList& selectorList) {
-  DCHECK(m_selectors.isEmpty());
-
-  unsigned selectorCount = 0;
-  for (const CSSSelector* selector = selectorList.first(); selector;
-       selector = CSSSelectorList::next(*selector))
-    selectorCount++;
-
-  m_usesDeepCombinatorOrShadowPseudo = false;
-  m_needsUpdatedDistribution = false;
-  m_selectors.reserveInitialCapacity(selectorCount);
-  for (const CSSSelector* selector = selectorList.first(); selector;
-       selector = CSSSelectorList::next(*selector)) {
-    if (selector->matchesPseudoElement())
-      continue;
-    m_selectors.uncheckedAppend(selector);
-    m_usesDeepCombinatorOrShadowPseudo |=
-        selector->hasDeepCombinatorOrShadowPseudo();
-    m_needsUpdatedDistribution |= selector->needsUpdatedDistribution();
-  }
-}
-
-inline bool SelectorDataList::selectorMatches(
-    const CSSSelector& selector,
-    Element& element,
-    const ContainerNode& rootNode) const {
+inline bool selectorMatches(const CSSSelector& selector,
+                            Element& element,
+                            const ContainerNode& rootNode) {
   SelectorChecker::Init init;
   init.mode = SelectorChecker::QueryingRules;
   SelectorChecker checker(init);
@@ -140,7 +117,7 @@
   return checker.match(context);
 }
 
-bool SelectorDataList::matches(Element& targetElement) const {
+bool SelectorQuery::matches(Element& targetElement) const {
   if (m_needsUpdatedDistribution)
     targetElement.updateDistribution();
 
@@ -152,7 +129,7 @@
   return false;
 }
 
-Element* SelectorDataList::closest(Element& targetElement) const {
+Element* SelectorQuery::closest(Element& targetElement) const {
   if (m_selectors.size() == 0)
     return nullptr;
   if (m_needsUpdatedDistribution)
@@ -168,23 +145,23 @@
   return nullptr;
 }
 
-StaticElementList* SelectorDataList::queryAll(ContainerNode& rootNode) const {
+StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const {
   HeapVector<Member<Element>> result;
   execute<AllElementsSelectorQueryTrait>(rootNode, result);
   return StaticElementList::adopt(result);
 }
 
-Element* SelectorDataList::queryFirst(ContainerNode& rootNode) const {
+Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const {
   Element* matchedElement = nullptr;
   execute<SingleElementSelectorQueryTrait>(rootNode, matchedElement);
   return matchedElement;
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::collectElementsByClassName(
+static void collectElementsByClassName(
     ContainerNode& rootNode,
     const AtomicString& className,
-    typename SelectorQueryTrait::OutputType& output) const {
+    typename SelectorQueryTrait::OutputType& output) {
   for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
     if (element.hasClass() && element.classNames().contains(className)) {
       SelectorQueryTrait::appendElement(output, element);
@@ -210,10 +187,10 @@
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::collectElementsByTagName(
+static void collectElementsByTagName(
     ContainerNode& rootNode,
     const QualifiedName& tagName,
-    typename SelectorQueryTrait::OutputType& output) const {
+    typename SelectorQueryTrait::OutputType& output) {
   DCHECK_EQ(tagName.namespaceURI(), starAtom);
   for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
     if (matchesTagName(tagName, element)) {
@@ -224,7 +201,7 @@
   }
 }
 
-inline bool SelectorDataList::canUseFastQuery(
+inline bool SelectorQuery::canUseFastQuery(
     const ContainerNode& rootNode) const {
   if (m_usesDeepCombinatorOrShadowPseudo)
     return false;
@@ -260,7 +237,7 @@
 // The travseralRoots may be empty, regardless of the returned bool value, if
 // this method finds that the selectors won't match any element.
 template <typename SelectorQueryTrait>
-void SelectorDataList::findTraverseRootsAndExecute(
+void SelectorQuery::findTraverseRootsAndExecute(
     ContainerNode& rootNode,
     typename SelectorQueryTrait::OutputType& output) const {
   // We need to return the matches in document order. To use id lookup while
@@ -343,7 +320,7 @@
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::executeForTraverseRoot(
+void SelectorQuery::executeForTraverseRoot(
     const CSSSelector& selector,
     ContainerNode* traverseRoot,
     MatchTraverseRootState matchTraverseRoot,
@@ -368,7 +345,7 @@
 }
 
 template <typename SelectorQueryTrait, typename SimpleElementListType>
-void SelectorDataList::executeForTraverseRoots(
+void SelectorQuery::executeForTraverseRoots(
     const CSSSelector& selector,
     SimpleElementListType& traverseRoots,
     MatchTraverseRootState matchTraverseRoots,
@@ -402,7 +379,7 @@
 }
 
 template <typename SelectorQueryTrait>
-bool SelectorDataList::selectorListMatches(
+bool SelectorQuery::selectorListMatches(
     ContainerNode& rootNode,
     Element& element,
     typename SelectorQueryTrait::OutputType& output) const {
@@ -416,7 +393,7 @@
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::executeSlow(
+void SelectorQuery::executeSlow(
     ContainerNode& rootNode,
     typename SelectorQueryTrait::OutputType& output) const {
   for (Element& element : ElementTraversal::descendantsOf(rootNode)) {
@@ -480,7 +457,7 @@
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::executeSlowTraversingShadowTree(
+void SelectorQuery::executeSlowTraversingShadowTree(
     ContainerNode& rootNode,
     typename SelectorQueryTrait::OutputType& output) const {
   for (ContainerNode* node = firstWithinTraversingShadowTree(rootNode); node;
@@ -513,7 +490,7 @@
 }
 
 template <typename SelectorQueryTrait>
-void SelectorDataList::execute(
+void SelectorQuery::execute(
     ContainerNode& rootNode,
     typename SelectorQueryTrait::OutputType& output) const {
   if (m_selectors.isEmpty())
@@ -596,23 +573,25 @@
 
 SelectorQuery::SelectorQuery(CSSSelectorList selectorList) {
   m_selectorList = std::move(selectorList);
-  m_selectors.initialize(m_selectorList);
-}
+  DCHECK(m_selectors.isEmpty());
 
-bool SelectorQuery::matches(Element& element) const {
-  return m_selectors.matches(element);
-}
+  unsigned selectorCount = 0;
+  for (const CSSSelector* selector = m_selectorList.first(); selector;
+       selector = CSSSelectorList::next(*selector))
+    selectorCount++;
 
-Element* SelectorQuery::closest(Element& element) const {
-  return m_selectors.closest(element);
-}
-
-StaticElementList* SelectorQuery::queryAll(ContainerNode& rootNode) const {
-  return m_selectors.queryAll(rootNode);
-}
-
-Element* SelectorQuery::queryFirst(ContainerNode& rootNode) const {
-  return m_selectors.queryFirst(rootNode);
+  m_usesDeepCombinatorOrShadowPseudo = false;
+  m_needsUpdatedDistribution = false;
+  m_selectors.reserveInitialCapacity(selectorCount);
+  for (const CSSSelector* selector = m_selectorList.first(); selector;
+       selector = CSSSelectorList::next(*selector)) {
+    if (selector->matchesPseudoElement())
+      continue;
+    m_selectors.uncheckedAppend(selector);
+    m_usesDeepCombinatorOrShadowPseudo |=
+        selector->hasDeepCombinatorOrShadowPseudo();
+    m_needsUpdatedDistribution |= selector->needsUpdatedDistribution();
+  }
 }
 
 SelectorQuery* SelectorQueryCache::add(const AtomicString& selectors,
diff --git a/third_party/WebKit/Source/core/dom/SelectorQuery.h b/third_party/WebKit/Source/core/dom/SelectorQuery.h
index ce28ed3..f6591f91 100644
--- a/third_party/WebKit/Source/core/dom/SelectorQuery.h
+++ b/third_party/WebKit/Source/core/dom/SelectorQuery.h
@@ -45,31 +45,29 @@
 class StaticNodeTypeList;
 using StaticElementList = StaticNodeTypeList<Element>;
 
-class SelectorDataList {
-  DISALLOW_NEW();
+class CORE_EXPORT SelectorQuery {
+  WTF_MAKE_NONCOPYABLE(SelectorQuery);
+  USING_FAST_MALLOC(SelectorQuery);
 
  public:
-  void initialize(const CSSSelectorList&);
+  static std::unique_ptr<SelectorQuery> adopt(CSSSelectorList);
+
+  // https://dom.spec.whatwg.org/#dom-element-matches
   bool matches(Element&) const;
+
+  // https://dom.spec.whatwg.org/#dom-element-closest
   Element* closest(Element&) const;
+
+  // https://dom.spec.whatwg.org/#dom-parentnode-queryselectorall
   StaticElementList* queryAll(ContainerNode& rootNode) const;
+
+  // https://dom.spec.whatwg.org/#dom-parentnode-queryselector
   Element* queryFirst(ContainerNode& rootNode) const;
 
  private:
-  bool canUseFastQuery(const ContainerNode& rootNode) const;
-  bool selectorMatches(const CSSSelector&,
-                       Element&,
-                       const ContainerNode&) const;
+  explicit SelectorQuery(CSSSelectorList);
 
-  template <typename SelectorQueryTrait>
-  void collectElementsByClassName(
-      ContainerNode& rootNode,
-      const AtomicString& className,
-      typename SelectorQueryTrait::OutputType&) const;
-  template <typename SelectorQueryTrait>
-  void collectElementsByTagName(ContainerNode& rootNode,
-                                const QualifiedName& tagName,
-                                typename SelectorQueryTrait::OutputType&) const;
+  bool canUseFastQuery(const ContainerNode& rootNode) const;
 
   template <typename SelectorQueryTrait>
   void findTraverseRootsAndExecute(
@@ -108,30 +106,12 @@
   void execute(ContainerNode& rootNode,
                typename SelectorQueryTrait::OutputType&) const;
 
+  CSSSelectorList m_selectorList;
   Vector<const CSSSelector*> m_selectors;
   bool m_usesDeepCombinatorOrShadowPseudo : 1;
   bool m_needsUpdatedDistribution : 1;
 };
 
-class CORE_EXPORT SelectorQuery {
-  WTF_MAKE_NONCOPYABLE(SelectorQuery);
-  USING_FAST_MALLOC(SelectorQuery);
-
- public:
-  static std::unique_ptr<SelectorQuery> adopt(CSSSelectorList);
-
-  bool matches(Element&) const;
-  Element* closest(Element&) const;
-  StaticElementList* queryAll(ContainerNode& rootNode) const;
-  Element* queryFirst(ContainerNode& rootNode) const;
-
- private:
-  explicit SelectorQuery(CSSSelectorList);
-
-  SelectorDataList m_selectors;
-  CSSSelectorList m_selectorList;
-};
-
 class SelectorQueryCache {
   USING_FAST_MALLOC(SelectorQueryCache);
 
diff --git a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
index c0c743f..8e5eec44 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ElementShadow.cpp
@@ -86,7 +86,6 @@
   shadowHost.setNeedsStyleRecalc(
       SubtreeStyleChange,
       StyleChangeReasonForTracing::create(StyleChangeReason::Shadow));
-  shadowRoot->setNeedsReattachLayoutTree();
 
   probe::didPushShadowRoot(&shadowHost, shadowRoot);
 
diff --git a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
index 3d99595..17ff2f2 100644
--- a/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
+++ b/third_party/WebKit/Source/core/dom/shadow/ShadowRoot.cpp
@@ -142,8 +142,11 @@
 
   StyleSharingDepthScope sharingScope(*this);
 
-  if (getStyleChangeType() >= SubtreeStyleChange)
+  if (getStyleChangeType() >= SubtreeStyleChange) {
     change = Force;
+    if (needsAttach())
+      setNeedsReattachLayoutTree();
+  }
 
   // There's no style to update so just calling recalcStyle means we're updated.
   clearNeedsStyleRecalc();
diff --git a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
index a4e45f4..841eb77 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodControllerTest.cpp
@@ -212,6 +212,64 @@
   EXPECT_STREQ("\xF0\x9F\x8F\x86\x61\x62", div->innerText().utf8().data());
 }
 
+TEST_F(InputMethodControllerTest, SetCompositionWithGraphemeCluster) {
+  insertHTMLElement("<div id='sample' contenteditable></div>", "sample");
+
+  Vector<CompositionUnderline> underlines;
+  underlines.push_back(CompositionUnderline(6, 6, Color(255, 0, 0), false, 0));
+  document().updateStyleAndLayout();
+
+  // UTF16 = 0x0939 0x0947 0x0932 0x0932. Note that 0x0932 0x0932 is a grapheme
+  // cluster.
+  controller().setComposition(
+      String::fromUTF8("\xE0\xA4\xB9\xE0\xA5\x87\xE0\xA4\xB2\xE0\xA4\xB2"),
+      underlines, 4, 4);
+  EXPECT_EQ(4u, controller().getSelectionOffsets().start());
+  EXPECT_EQ(4u, controller().getSelectionOffsets().end());
+
+  // UTF16 = 0x0939 0x0947 0x0932 0x094D 0x0932 0x094B.
+  controller().setComposition(
+      String::fromUTF8("\xE0\xA4\xB9\xE0\xA5\x87\xE0\xA4\xB2\xE0\xA5\x8D\xE0"
+                       "\xA4\xB2\xE0\xA5\x8B"),
+      underlines, 6, 6);
+  EXPECT_EQ(6u, controller().getSelectionOffsets().start());
+  EXPECT_EQ(6u, controller().getSelectionOffsets().end());
+}
+
+TEST_F(InputMethodControllerTest,
+       SetCompositionWithGraphemeClusterAndMultipleNodes) {
+  Element* div =
+      insertHTMLElement("<div id='sample' contenteditable></div>", "sample");
+
+  Vector<CompositionUnderline> underlines;
+  underlines.push_back(
+      CompositionUnderline(12, 12, Color(255, 0, 0), false, 0));
+  document().updateStyleAndLayout();
+
+  // UTF16 = 0x0939 0x0947 0x0932 0x094D 0x0932 0x094B. 0x0939 0x0947 0x0932 is
+  // a grapheme cluster, so is the remainding 0x0932 0x094B.
+  controller().commitText(
+      String::fromUTF8("\xE0\xA4\xB9\xE0\xA5\x87\xE0\xA4\xB2\xE0\xA5\x8D\xE0"
+                       "\xA4\xB2\xE0\xA5\x8B"),
+      underlines, 1);
+  controller().commitText("\nab ", underlines, 1);
+  controller().setComposition(String("c"), underlines, 1, 1);
+  EXPECT_STREQ(
+      "\xE0\xA4\xB9\xE0\xA5\x87\xE0\xA4\xB2\xE0\xA5\x8D\xE0\xA4\xB2\xE0\xA5"
+      "\x8B\nab c",
+      div->innerText().utf8().data());
+  EXPECT_EQ(11u, controller().getSelectionOffsets().start());
+  EXPECT_EQ(11u, controller().getSelectionOffsets().end());
+
+  controller().setComposition(String("cd"), underlines, 2, 2);
+  EXPECT_STREQ(
+      "\xE0\xA4\xB9\xE0\xA5\x87\xE0\xA4\xB2\xE0\xA5\x8D\xE0\xA4\xB2\xE0\xA5"
+      "\x8B\nab cd",
+      div->innerText().utf8().data());
+  EXPECT_EQ(12u, controller().getSelectionOffsets().start());
+  EXPECT_EQ(12u, controller().getSelectionOffsets().end());
+}
+
 TEST_F(InputMethodControllerTest, SetCompositionKeepingStyle) {
   Element* div = insertHTMLElement(
       "<div id='sample' "
diff --git a/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp b/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
index 4759d76..5d01df33 100644
--- a/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/InsertIncrementalTextCommand.cpp
@@ -51,17 +51,18 @@
                              adjustedPosition.computeOffsetInContainerNode());
 }
 
-size_t computeCommonGraphemeClusterPrefixLength(
-    const int selectionStart,
-    const String& oldText,
-    const String& newText,
-    const Element* rootEditableElement) {
+size_t computeCommonGraphemeClusterPrefixLength(const Position& selectionStart,
+                                                const String& oldText,
+                                                const String& newText) {
   const size_t commonPrefixLength = computeCommonPrefixLength(oldText, newText);
+  const int selectionOffset = selectionStart.computeOffsetInContainerNode();
+  const ContainerNode* selectionNode =
+      selectionStart.computeContainerNode()->parentNode();
 
   // For grapheme cluster, we should adjust it for grapheme boundary.
   const EphemeralRange& range =
-      PlainTextRange(0, selectionStart + commonPrefixLength)
-          .createRange(*rootEditableElement);
+      PlainTextRange(0, selectionOffset + commonPrefixLength)
+          .createRange(*selectionNode);
   if (range.isNull())
     return 0;
   const Position& position = range.endPosition();
@@ -83,22 +84,24 @@
                              position.computeOffsetInContainerNode());
 }
 
-size_t computeCommonGraphemeClusterSuffixLength(
-    const int selectionStart,
-    const String& oldText,
-    const String& newText,
-    const Element* rootEditableElement) {
+size_t computeCommonGraphemeClusterSuffixLength(const Position& selectionStart,
+                                                const String& oldText,
+                                                const String& newText) {
   const size_t commonSuffixLength = computeCommonSuffixLength(oldText, newText);
+  const int selectionOffset = selectionStart.computeOffsetInContainerNode();
+  const ContainerNode* selectionNode =
+      selectionStart.computeContainerNode()->parentNode();
 
   // For grapheme cluster, we should adjust it for grapheme boundary.
   const EphemeralRange& range =
-      PlainTextRange(0, selectionStart + oldText.length() - commonSuffixLength)
-          .createRange(*rootEditableElement);
+      PlainTextRange(0, selectionOffset + oldText.length() - commonSuffixLength)
+          .createRange(*selectionNode);
   if (range.isNull())
     return 0;
   const Position& position = range.endPosition();
   const size_t diff = computeDistanceToRightGraphemeBoundary(position);
-  DCHECK_GE(commonSuffixLength, diff);
+  if (diff > commonSuffixLength)
+    return 0;
   return commonSuffixLength - diff;
 }
 
@@ -153,16 +156,15 @@
   const String oldText = plainText(selectionRange);
   const String& newText = m_text;
 
-  const int selectionStart =
-      endingSelection().start().computeOffsetInContainerNode();
+  const Position& selectionStart = endingSelection().start();
   const size_t newTextLength = newText.length();
   const size_t oldTextLength = oldText.length();
   const size_t commonPrefixLength = computeCommonGraphemeClusterPrefixLength(
-      selectionStart, oldText, newText, element);
+      selectionStart, oldText, newText);
   // We should ignore common prefix when finding common suffix.
   const size_t commonSuffixLength = computeCommonGraphemeClusterSuffixLength(
       selectionStart, oldText.right(oldTextLength - commonPrefixLength),
-      newText.right(newTextLength - commonPrefixLength), element);
+      newText.right(newTextLength - commonPrefixLength));
   DCHECK_GE(oldTextLength, commonPrefixLength + commonSuffixLength);
 
   m_text =
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 0d022a76..6e8030f 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -50,7 +50,6 @@
 #include "core/events/ErrorEvent.h"
 #include "core/frame/BrowserControls.h"
 #include "core/frame/EventHandlerRegistry.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameClient.h"
 #include "core/frame/Location.h"
@@ -2753,8 +2752,8 @@
 }
 
 void FrameView::didAttachDocument() {
-  FrameHost* frameHost = m_frame->host();
-  DCHECK(frameHost);
+  Page* page = m_frame->page();
+  DCHECK(page);
 
   DCHECK(m_frame->document());
 
@@ -2767,9 +2766,8 @@
         RootFrameViewport::create(visualViewport, *layoutViewport);
     m_viewportScrollableArea = rootFrameViewport;
 
-    frameHost->page()
-        .globalRootScrollerController()
-        .initializeViewportScrollCallback(*rootFrameViewport);
+    page->globalRootScrollerController().initializeViewportScrollCallback(
+        *rootFrameViewport);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 0424399..a5c9ff7 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1489,6 +1489,7 @@
     CSSOverflowPaged = 1867,
     ChildSrcAllowedWorkerThatScriptSrcBlocked = 1868,
     HTMLTableElementPresentationAttributeBackground = 1869,
+    V8Navigator_GetInstalledRelatedApps_Method = 1870,
 
     // Add new features immediately above this line. Don't change assigned
     // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
index 14e6031..4a449c5 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElementTest.cpp
@@ -8,7 +8,6 @@
 #include "core/dom/Document.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/KeyboardEventInit.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/VisualViewport.h"
 #include "core/html/HTMLBodyElement.h"
@@ -99,7 +98,7 @@
 
 TEST_F(HTMLInputElementTest, NoAssertWhenMovedInNewDocument) {
   Document* documentWithoutFrame = Document::create();
-  EXPECT_EQ(nullptr, documentWithoutFrame->frameHost());
+  EXPECT_EQ(nullptr, documentWithoutFrame->page());
   HTMLHtmlElement* html = HTMLHtmlElement::create(*documentWithoutFrame);
   html->appendChild(HTMLBodyElement::create(*documentWithoutFrame));
 
@@ -109,7 +108,7 @@
 
   std::unique_ptr<DummyPageHolder> pageHolder = DummyPageHolder::create();
   auto& document = pageHolder->document();
-  EXPECT_NE(nullptr, document.frameHost());
+  EXPECT_NE(nullptr, document.page());
 
   // Put the input element inside a document with frame.
   document.body()->appendChild(documentWithoutFrame->body()->firstChild());
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index e2a0d5b..490f727 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -54,7 +54,6 @@
 #include "core/events/WheelEvent.h"
 #include "core/frame/Deprecation.h"
 #include "core/frame/EventHandlerRegistry.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/LocalFrameClient.h"
@@ -2093,11 +2092,4 @@
   return WebInputEventResult::HandledSystem;
 }
 
-FrameHost* EventHandler::frameHost() const {
-  if (!m_frame->page())
-    return nullptr;
-
-  return &m_frame->page()->frameHost();
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/input/EventHandler.h b/third_party/WebKit/Source/core/input/EventHandler.h
index e3c9ce7..6080578 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.h
+++ b/third_party/WebKit/Source/core/input/EventHandler.h
@@ -59,7 +59,6 @@
 template <typename EventType>
 class EventWithHitTestResults;
 class FloatQuad;
-class FrameHost;
 class HTMLFrameSetElement;
 class HitTestRequest;
 class HitTestResult;
@@ -338,8 +337,6 @@
 
   bool shouldBrowserControlsConsumeScroll(FloatSize) const;
 
-  FrameHost* frameHost() const;
-
   bool rootFrameTouchPointerActiveInCurrentFrame(int pointerId) const;
 
   // NOTE: If adding a new field to this class please ensure that it is
diff --git a/third_party/WebKit/Source/core/input/GestureManager.cpp b/third_party/WebKit/Source/core/input/GestureManager.cpp
index 4b4617d..8cdaaaa9 100644
--- a/third_party/WebKit/Source/core/input/GestureManager.cpp
+++ b/third_party/WebKit/Source/core/input/GestureManager.cpp
@@ -8,7 +8,6 @@
 #include "core/dom/DocumentUserGestureToken.h"
 #include "core/editing/SelectionController.h"
 #include "core/events/GestureEvent.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/Settings.h"
 #include "core/frame/VisualViewport.h"
@@ -426,13 +425,6 @@
   return WebInputEventResult::NotHandled;
 }
 
-FrameHost* GestureManager::frameHost() const {
-  if (!m_frame->page())
-    return nullptr;
-
-  return &m_frame->page()->frameHost();
-}
-
 WTF::Optional<WTF::TimeTicks> GestureManager::getLastShowPressTimestamp()
     const {
   return m_lastShowPressTimestamp;
diff --git a/third_party/WebKit/Source/core/input/GestureManager.h b/third_party/WebKit/Source/core/input/GestureManager.h
index 6baedf1..6ac90b5 100644
--- a/third_party/WebKit/Source/core/input/GestureManager.h
+++ b/third_party/WebKit/Source/core/input/GestureManager.h
@@ -61,8 +61,6 @@
   WebInputEventResult sendContextMenuEventForGesture(
       const GestureEventWithHitTestResults&);
 
-  FrameHost* frameHost() const;
-
   // NOTE: If adding a new field to this class please ensure that it is
   // cleared if needed in |GestureManager::clear()|.
 
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index 6527abc4..35cb29e 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -907,6 +907,12 @@
                     { "name": "displayedInsecureContentStyle", "$ref": "SecurityState", "description": "Security state representing a page that displayed insecure content." }
                 ],
                 "description": "Information about insecure content on the page."
+            },
+            {
+                "id": "CertificateErrorAction",
+                "type": "string",
+                "enum": ["continue", "cancel"],
+                "description": "The action to take when a certificate error occurs. continue will continue processing the request and cancel will cancel the request."
             }
         ],
         "commands": [
@@ -921,6 +927,21 @@
             {
                 "name": "showCertificateViewer",
                 "description": "Displays native dialog with the certificate details."
+            },
+            {
+                "name": "handleCertificateError",
+                "description": "Handles a certificate error that fired a certificateError event.",
+                "parameters": [
+                    { "name": "eventId", "type": "integer", "description": "The ID of the event."},
+                    { "name": "action", "$ref": "CertificateErrorAction", "description": "The action to take on the certificate error." }
+                ]
+            },
+            {
+                "name": "setOverrideCertificateErrors",
+                "description": "Enable/disable overriding certificate errors. If enabled, all certificate error events need to be handled by the DevTools client and should be answered with handleCertificateError commands.",
+                "parameters": [
+                    { "name": "override", "type": "boolean", "description": "If true, certificate errors will be overridden."}
+                ]
             }
         ],
         "events": [
@@ -934,6 +955,15 @@
                     { "name": "insecureContentStatus", "$ref": "InsecureContentStatus", "description": "Information about insecure content on the page." },
                     { "name": "summary", "type": "string", "description": "Overrides user-visible description of the state.", "optional": true }
                 ]
+            },
+            {
+                "name": "certificateError",
+                "description": "There is a certificate error. If overriding certificate errors is enabled, then it should be handled with the handleCertificateError command. Note: this event does not fire if the certificate error has been allowed internally.",
+                "parameters": [
+                    { "name": "eventId", "type": "integer", "description": "The ID of the event."},
+                    { "name": "errorType", "type": "string", "description": "The type of the error."},
+                    { "name": "requestURL", "type": "string", "description": "The url that was requested."}
+                ]
             }
         ]
     },
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 0b1aaf72..88b23d77 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -941,41 +941,6 @@
   return logicalRightOffsetForContent();
 }
 
-LayoutBlock* LayoutBlock::blockBeforeWithinSelectionRoot(
-    LayoutSize& offset) const {
-  if (isSelectionRoot())
-    return nullptr;
-
-  const LayoutObject* object = this;
-  LayoutObject* sibling;
-  do {
-    sibling = object->previousSibling();
-    while (sibling && (!sibling->isLayoutBlock() ||
-                       toLayoutBlock(sibling)->isSelectionRoot()))
-      sibling = sibling->previousSibling();
-
-    offset -= LayoutSize(toLayoutBlock(object)->logicalLeft(),
-                         toLayoutBlock(object)->logicalTop());
-    object = object->parent();
-  } while (!sibling && object && object->isLayoutBlock() &&
-           !toLayoutBlock(object)->isSelectionRoot());
-
-  if (!sibling)
-    return nullptr;
-
-  LayoutBlock* beforeBlock = toLayoutBlock(sibling);
-
-  offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
-
-  LayoutObject* child = beforeBlock->lastChild();
-  while (child && child->isLayoutBlock()) {
-    beforeBlock = toLayoutBlock(child);
-    offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
-    child = beforeBlock->lastChild();
-  }
-  return beforeBlock;
-}
-
 void LayoutBlock::setSelectionState(SelectionState state) {
   LayoutBox::setSelectionState(state);
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index 49de48e4..f1273cc 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -215,8 +215,6 @@
   LayoutUnit blockDirectionOffset(const LayoutSize& offsetFromBlock) const;
   LayoutUnit inlineDirectionOffset(const LayoutSize& offsetFromBlock) const;
 
-  LayoutBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const;
-
   void setSelectionState(SelectionState) override;
 
   static LayoutBlock* createAnonymousWithParentAndDisplay(
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h
index 51df00a8..f49cccd 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h
@@ -184,10 +184,6 @@
 
   bool containsFloats() const { return toBlockFlow()->containsFloats(); }
 
-  LayoutBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const {
-    return toBlockFlow()->blockBeforeWithinSelectionRoot(offset);
-  }
-
   InlineBox* createAndAppendRootInlineBox() {
     return toBlockFlow()->createAndAppendRootInlineBox();
   }
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index d88d5225..c2077930 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -1564,7 +1564,7 @@
 static unsigned eventHandlerCount(
     Document& document,
     EventHandlerRegistry::EventHandlerClass handlerClass) {
-  if (!document.frameHost())
+  if (!document.page())
     return 0;
   EventHandlerRegistry* registry = &document.page()->eventHandlerRegistry();
   unsigned count = 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
index ddff22f0..771e9be 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
+++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
@@ -131,9 +131,8 @@
     this._updatePlaybackControls();
 
     this._previewContainer = this.contentElement.createChild('div', 'animation-timeline-buffer');
-    this._popoverHelper = new UI.PopoverHelper(this._previewContainer, true);
-    this._popoverHelper.initializeCallbacks(
-        this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this._previewContainer, this._getPopoverRequest.bind(this));
+    this._popoverHelper.setDisableOnClick(true);
     this._popoverHelper.setTimeout(0);
     var emptyBufferHint = this.contentElement.createChild('div', 'animation-timeline-buffer-hint');
     emptyBufferHint.textContent = Common.UIString('Listening for animations...');
@@ -162,49 +161,44 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!Element|!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
-    if (element.isDescendant(this._previewContainer))
-      return element;
-  }
+  _getPopoverRequest(event) {
+    var element = event.target;
+    if (!element.isDescendant(this._previewContainer))
+      return null;
 
-  /**
-   * @param {!Element|!AnchorBox} anchor
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(anchor, popover) {
-    var animGroup;
-    for (var group of this._previewMap.keysArray()) {
-      if (this._previewMap.get(group).element === anchor.parentElement)
-        animGroup = group;
-    }
-    console.assert(animGroup);
-    var screenshots = animGroup.screenshots();
-    if (!screenshots.length)
-      return Promise.resolve(false);
+    return {
+      box: event.target.boxInWindow(),
+      show: popover => {
+        var animGroup;
+        for (var group of this._previewMap.keysArray()) {
+          if (this._previewMap.get(group).element === element.parentElement)
+            animGroup = group;
+        }
+        console.assert(animGroup);
+        var screenshots = animGroup.screenshots();
+        if (!screenshots.length)
+          return Promise.resolve(false);
 
-    var fulfill;
-    var promise = new Promise(x => fulfill = x);
-    if (!screenshots[0].complete)
-      screenshots[0].onload = onFirstScreenshotLoaded.bind(null, screenshots);
-    else
-      onFirstScreenshotLoaded(screenshots);
-    return promise;
+        var fulfill;
+        var promise = new Promise(x => fulfill = x);
+        if (!screenshots[0].complete)
+          screenshots[0].onload = onFirstScreenshotLoaded.bind(null, screenshots);
+        else
+          onFirstScreenshotLoaded(screenshots);
+        return promise;
 
-    /**
-     * @param  {!Array.<!Image>} screenshots
-     */
-    function onFirstScreenshotLoaded(screenshots) {
-      new Animation.AnimationScreenshotPopover(screenshots).show(popover.contentElement);
-      fulfill(true);
-    }
-  }
-
-  _onHidePopover() {
+        /**
+         * @param  {!Array.<!Image>} screenshots
+         */
+        function onFirstScreenshotLoaded(screenshots) {
+          new Animation.AnimationScreenshotPopover(screenshots).show(popover.contentElement);
+          fulfill(true);
+        }
+      }
+    };
   }
 
   _togglePauseAll() {
diff --git a/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js b/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
index 69a34727..cd0c0c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/DOMPresentationUtils.js
@@ -148,36 +148,30 @@
  * @param {!SDK.Target} target
  * @param {string} originalImageURL
  * @param {boolean} showDimensions
- * @param {function(!Element=)} userCallback
  * @param {!Object=} precomputedFeatures
+ * @return {!Promise<?Element>}
  */
 Components.DOMPresentationUtils.buildImagePreviewContents = function(
-    target, originalImageURL, showDimensions, userCallback, precomputedFeatures) {
+    target, originalImageURL, showDimensions, precomputedFeatures) {
   var resourceTreeModel = SDK.ResourceTreeModel.fromTarget(target);
-  if (!resourceTreeModel) {
-    userCallback();
-    return;
-  }
+  if (!resourceTreeModel)
+    return Promise.resolve(/** @type {?Element} */ (null));
   var resource = resourceTreeModel.resourceForURL(originalImageURL);
   var imageURL = originalImageURL;
   if (!isImageResource(resource) && precomputedFeatures && precomputedFeatures.currentSrc) {
     imageURL = precomputedFeatures.currentSrc;
     resource = resourceTreeModel.resourceForURL(imageURL);
   }
-  if (!isImageResource(resource)) {
-    userCallback();
-    return;
-  }
+  if (!isImageResource(resource))
+    return Promise.resolve(/** @type {?Element} */ (null));
 
+  var fulfill;
+  var promise = new Promise(x => fulfill = x);
   var imageElement = createElement('img');
   imageElement.addEventListener('load', buildContent, false);
-  imageElement.addEventListener('error', errorCallback, false);
+  imageElement.addEventListener('error', () => fulfill(null), false);
   resource.populateImageSource(imageElement);
-
-  function errorCallback() {
-    // Drop the event parameter when invoking userCallback.
-    userCallback();
-  }
+  return promise;
 
   /**
    * @param {?SDK.Resource} resource
@@ -212,7 +206,7 @@
       container.createChild('tr').createChild('td').createChild('span', 'description').textContent =
           String.sprintf('currentSrc: %s', imageURL.trimMiddle(100));
     }
-    userCallback(container);
+    fulfill(container);
   }
 };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/dom_extension/DOMExtension.js b/third_party/WebKit/Source/devtools/front_end/dom_extension/DOMExtension.js
index dd12c01..f9d202ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/dom_extension/DOMExtension.js
+++ b/third_party/WebKit/Source/devtools/front_end/dom_extension/DOMExtension.js
@@ -472,6 +472,15 @@
     this.width = width || 0;
     this.height = height || 0;
   }
+
+  /**
+   * @param {number} x
+   * @param {number} y
+   * @return {boolean}
+   */
+  contains(x, y) {
+    return x >= this.x && x <= this.x + this.width && y >= this.y && y <= this.y + this.height;
+  }
 };
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
index 6d0eeead..b095335 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -568,41 +568,29 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!Element|!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
-    var link = element;
+  _getPopoverRequest(event) {
+    var link = event.target;
     while (link && !link[Elements.ElementsTreeElement.HrefSymbol])
       link = link.parentElementOrShadowHost();
-    return link ? link : undefined;
-  }
+    if (!link)
+      return null;
 
-  /**
-   * @param {!Element|!AnchorBox} link
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(link, popover) {
-    var node = this.selectedDOMNode();
-    if (!node)
-      return Promise.resolve(false);
-
-    var fulfill;
-    var promise = new Promise(x => fulfill = x);
-    Components.DOMPresentationUtils.buildImagePreviewContents(
-        node.target(), link[Elements.ElementsTreeElement.HrefSymbol], true, showPopover);
-    return promise;
-
-    /**
-     * @param {!Element=} contents
-     */
-    function showPopover(contents) {
-      if (contents)
-        popover.contentElement.appendChild(contents);
-      fulfill(!!contents);
-    }
+    return {
+      box: link.boxInWindow(),
+      show: async popover => {
+        var node = this.selectedDOMNode();
+        if (!node)
+          return false;
+        var preview = await Components.DOMPresentationUtils.buildImagePreviewContents(
+            node.target(), link[Elements.ElementsTreeElement.HrefSymbol], true);
+        if (preview)
+          popover.contentElement.appendChild(preview);
+        return !!preview;
+      }
+    };
   }
 
   _jumpToSearchResult(index) {
@@ -907,9 +895,8 @@
     var tabbedPane = this.sidebarPaneView.tabbedPane();
     if (this._popoverHelper)
       this._popoverHelper.hidePopover();
-    this._popoverHelper = new UI.PopoverHelper(tabbedPane.element);
+    this._popoverHelper = new UI.PopoverHelper(tabbedPane.element, this._getPopoverRequest.bind(this));
     this._popoverHelper.setHasPadding(true);
-    this._popoverHelper.initializeCallbacks(this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
     this._popoverHelper.setTimeout(0);
 
     if (horizontally) {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
index 38d3a035c..3fe0a40 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js
@@ -75,8 +75,7 @@
 
     this._visible = false;
 
-    this._popoverHelper = new UI.PopoverHelper(this._element);
-    this._popoverHelper.initializeCallbacks(this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this._element, this._getPopoverRequest.bind(this));
     this._popoverHelper.setHasPadding(true);
     this._popoverHelper.setTimeout(0, 100);
 
@@ -522,36 +521,51 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!Element|!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
-    var link = element;
+  _getPopoverRequest(event) {
+    var link = event.target;
     while (link && !link[Elements.ElementsTreeElement.HrefSymbol])
       link = link.parentElementOrShadowHost();
-    return link ? link : undefined;
+    if (!link)
+      return null;
+
+    return {
+      box: link.boxInWindow(),
+      show: async popover => {
+        var listItem = link.enclosingNodeOrSelfWithNodeName('li');
+        var node = /** @type {!Elements.ElementsTreeElement} */ (listItem.treeElement).node();
+        var precomputedFeatures = await this._loadDimensionsForNode(node);
+        var preview = await Components.DOMPresentationUtils.buildImagePreviewContents(
+            node.target(), link[Elements.ElementsTreeElement.HrefSymbol], true, precomputedFeatures);
+        if (preview)
+          popover.contentElement.appendChild(preview);
+        return !!preview;
+      }
+    };
   }
 
   /**
    * @param {!SDK.DOMNode} node
-   * @param {function()} callback
+   * @return {!Promise<!Object|undefined>}
    */
-  _loadDimensionsForNode(node, callback) {
-    if (!node.nodeName() || node.nodeName().toLowerCase() !== 'img') {
-      callback();
-      return;
-    }
+  _loadDimensionsForNode(node) {
+    if (!node.nodeName() || node.nodeName().toLowerCase() !== 'img')
+      return Promise.resolve();
 
+    var fulfill;
+    var promise = new Promise(x => fulfill = x);
     node.resolveToObject('', resolvedNode);
+    return promise;
 
     function resolvedNode(object) {
       if (!object) {
-        callback();
+        fulfill();
         return;
       }
 
-      object.callFunctionJSON(features, undefined, callback);
+      object.callFunctionJSON(features, undefined, fulfill);
       object.release();
 
       /**
@@ -571,32 +585,6 @@
     }
   }
 
-  /**
-   * @param {!Element|!AnchorBox} link
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(link, popover) {
-    var fulfill;
-    var promise = new Promise(x => fulfill = x);
-    var listItem = link.enclosingNodeOrSelfWithNodeName('li');
-    var node = /** @type {!Elements.ElementsTreeElement} */ (listItem.treeElement).node();
-    this._loadDimensionsForNode(
-        node, Components.DOMPresentationUtils.buildImagePreviewContents.bind(
-                  Components.DOMPresentationUtils, node.target(), link[Elements.ElementsTreeElement.HrefSymbol], true,
-                  showPopover));
-    return promise;
-
-    /**
-     * @param {!Element=} contents
-     */
-    function showPopover(contents) {
-      if (contents)
-        popover.contentElement.appendChild(contents);
-      fulfill(!!contents);
-    }
-  }
-
   _onmousedown(event) {
     var element = this._treeElementFromEvent(event);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
index 5f26a5c..6508efe8 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
@@ -92,9 +92,7 @@
     this._loadColumnExtensions();
     this._loadCustomColumnsAndSettings();
 
-    this._popoverHelper = new UI.PopoverHelper(this._networkLogView.element);
-    this._popoverHelper.initializeCallbacks(
-        this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this._networkLogView.element, this._getPopoverRequest.bind(this));
     this._popoverHelper.setHasPadding(true);
 
     /** @type {!DataGrid.SortableDataGrid<!Network.NetworkNode>} */
@@ -570,37 +568,31 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!Element|!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
+  _getPopoverRequest(event) {
     if (!this._gridMode)
-      return;
-    var anchor = element.enclosingNodeOrSelfWithClass('network-script-initiated');
-    if (anchor && anchor.request) {
-      var initiator = /** @type {!SDK.NetworkRequest} */ (anchor.request).initiator();
-      if (initiator && initiator.stack)
-        return anchor;
-    }
-  }
+      return null;
 
-  /**
-   * @param {!Element|!AnchorBox} anchor
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(anchor, popover) {
-    var request = /** @type {!SDK.NetworkRequest} */ (anchor.request);
-    var initiator = /** @type {!Protocol.Network.Initiator} */ (request.initiator());
-    var content = Components.DOMPresentationUtils.buildStackTracePreviewContents(
-        request.target(), this._popupLinkifier, initiator.stack);
-    popover.contentElement.appendChild(content);
-    return Promise.resolve(true);
-  }
+    var anchor = event.target.enclosingNodeOrSelfWithClass('network-script-initiated');
+    var request = /** @type {?SDK.NetworkRequest} */ (anchor ? anchor.request : null);
+    var initiator = request ? request.initiator() : null;
+    if (!initiator || !initiator.stack)
+      return null;
 
-  _onHidePopover() {
-    this._popupLinkifier.reset();
+    return {
+      box: anchor.boxInWindow(),
+      show: popover => {
+        var content = Components.DOMPresentationUtils.buildStackTracePreviewContents(
+            anchor.request.target(), this._popupLinkifier, initiator.stack);
+        popover.contentElement.appendChild(content);
+        return Promise.resolve(true);
+      },
+      hide: () => {
+        this._popupLinkifier.reset();
+      }
+    };
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
index 1f36a35..ed370ad2 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkWaterfallColumn.js
@@ -33,8 +33,7 @@
     this._startTime = this._calculator.minimumBoundary();
     this._endTime = this._calculator.maximumBoundary();
 
-    this._popoverHelper = new UI.PopoverHelper(this.element);
-    this._popoverHelper.initializeCallbacks(this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this.element, this._getPopoverRequest.bind(this));
     this._popoverHelper.setHasPadding(true);
     this._popoverHelper.setTimeout(300, 300);
 
@@ -187,16 +186,15 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
+  _getPopoverRequest(event) {
     if (!this._hoveredNode)
-      return;
+      return null;
     var request = this._hoveredNode.request();
     if (!request)
-      return;
+      return null;
     var useTimingBars = !Common.moduleSetting('networkColorCodeResourceTypes').get() && !this._calculator.startAtZero;
     if (useTimingBars) {
       var range = Network.RequestTimingView.calculateRequestTimeRanges(request, 0)
@@ -216,37 +214,30 @@
     }
 
     if (event.clientX < this._canvasPosition.left + start || event.clientX > this._canvasPosition.left + end)
-      return;
+      return null;
 
     var rowIndex = this._nodes.findIndex(node => node.hovered());
     var barHeight = this._getBarHeight(range.name);
     var y = this._headerHeight + (this._rowHeight * rowIndex - this._scrollTop) + ((this._rowHeight - barHeight) / 2);
 
     if (event.clientY < this._canvasPosition.top + y || event.clientY > this._canvasPosition.top + y + barHeight)
-      return;
+      return null;
 
     var anchorBox = this.element.boxInWindow();
     anchorBox.x += start;
     anchorBox.y += y;
     anchorBox.width = end - start;
     anchorBox.height = barHeight;
-    return anchorBox;
-  }
 
-  /**
-   * @param {!Element|!AnchorBox} anchor
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(anchor, popover) {
-    if (!this._hoveredNode)
-      return Promise.resolve(false);
-    var request = this._hoveredNode.request();
-    if (!request)
-      return Promise.resolve(false);
-    var content = Network.RequestTimingView.createTimingTable(request, this._calculator);
-    popover.contentElement.appendChild(content);
-    return Promise.resolve(true);
+    return {
+      box: anchorBox,
+      show: popover => {
+        var content =
+            Network.RequestTimingView.createTimingTable(/** @type {!SDK.NetworkRequest} */ (request), this._calculator);
+        popover.contentElement.appendChild(content);
+        return Promise.resolve(true);
+      }
+    };
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js b/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
index 82f6a33..25ab9f55 100644
--- a/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
+++ b/third_party/WebKit/Source/devtools/front_end/network_conditions/NetworkConditionsSelector.js
@@ -176,21 +176,19 @@
         SDK.MultitargetNetworkManager.Events.ConditionsChanged, networkConditionsChanged);
     checkbox.setChecked(SDK.multitargetNetworkManager.networkConditions() === SDK.NetworkManager.OfflineConditions);
 
-    var lastNetworkConditions;
-
     function forceOffline() {
       if (checkbox.checked()) {
-        lastNetworkConditions = SDK.multitargetNetworkManager.networkConditions();
+        NetworkConditions.NetworkConditionsSelector._lastNetworkConditions =
+            SDK.multitargetNetworkManager.networkConditions();
         SDK.multitargetNetworkManager.setNetworkConditions(SDK.NetworkManager.OfflineConditions);
       } else {
-        SDK.multitargetNetworkManager.setNetworkConditions(lastNetworkConditions);
+        SDK.multitargetNetworkManager.setNetworkConditions(
+            NetworkConditions.NetworkConditionsSelector._lastNetworkConditions);
       }
     }
 
     function networkConditionsChanged() {
       var conditions = SDK.multitargetNetworkManager.networkConditions();
-      if (conditions !== SDK.NetworkManager.OfflineConditions)
-        lastNetworkConditions = conditions;
       checkbox.setChecked(conditions === SDK.NetworkManager.OfflineConditions);
     }
     return checkbox;
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js
index 4a222288..8a52f32 100644
--- a/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/TimelineOverviewPane.js
@@ -53,9 +53,7 @@
     this._overviewControls = [];
     this._markers = new Map();
 
-    this._popoverHelper = new UI.PopoverHelper(this._cursorArea);
-    this._popoverHelper.initializeCallbacks(
-        this._getPopoverAnchor.bind(this), this._showPopover.bind(this), this._onHidePopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this._cursorArea, this._getPopoverRequest.bind(this));
     this._popoverHelper.setHasPadding(true);
     this._popoverHelper.setTimeout(0);
 
@@ -67,42 +65,27 @@
   }
 
   /**
-   * @param {!Element} element
    * @param {!Event} event
-   * @return {!Element|!AnchorBox|undefined}
+   * @return {?UI.PopoverRequest}
    */
-  _getPopoverAnchor(element, event) {
-    return this._cursorArea;
-  }
-
-  /**
-   * @param {!Element|!AnchorBox} anchor
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showPopover(anchor, popover) {
-    return this._buildPopoverContents().then(maybeShowPopover.bind(this));
-
-    /**
-     * @this {PerfUI.TimelineOverviewPane}
-     * @param {!DocumentFragment} fragment
-     * @return {boolean}
-     */
-    function maybeShowPopover(fragment) {
-      if (!fragment.firstChild)
-        return false;
-      var content = new PerfUI.TimelineOverviewPane.PopoverContents();
-      this._popoverContents = content.contentElement.createChild('div');
-      this._popoverContents.appendChild(fragment);
-      this._popover = popover;
-      content.show(popover.contentElement);
-      return true;
-    }
-  }
-
-  _onHidePopover() {
-    this._popover = null;
-    this._popoverContents = null;
+  _getPopoverRequest(event) {
+    return {
+      box: this._cursorElement.boxInWindow(),
+      show: popover => this._buildPopoverContents().then(fragment => {
+        if (!fragment.firstChild)
+          return false;
+        var content = new PerfUI.TimelineOverviewPane.PopoverContents();
+        this._popoverContents = content.contentElement.createChild('div');
+        this._popoverContents.appendChild(fragment);
+        this._popover = popover;
+        content.show(popover.contentElement);
+        return true;
+      }),
+      hide: () => {
+        this._popover = null;
+        this._popoverContents = null;
+      }
+    };
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotGridNodes.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotGridNodes.js
index 6ded00de..fe1ff3e 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotGridNodes.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotGridNodes.js
@@ -133,10 +133,10 @@
 
   /**
    * @param {!SDK.Target} target
-   * @param {function(!SDK.RemoteObject)} callback
    * @param {string} objectGroupName
+   * @return {!Promise<!SDK.RemoteObject>}
    */
-  queryObjectContent(target, callback, objectGroupName) {
+  queryObjectContent(target, objectGroupName) {
   }
 
   /**
@@ -605,15 +605,18 @@
   /**
    * @override
    * @param {!SDK.Target} target
-   * @param {function(!SDK.RemoteObject)} callback
    * @param {string} objectGroupName
+   * @return {!Promise<!SDK.RemoteObject>}
    */
-  queryObjectContent(target, callback, objectGroupName) {
+  queryObjectContent(target, objectGroupName) {
+    var fulfill;
+    var promise = new Promise(x => fulfill = x);
+
     /**
      * @param {?SDK.RemoteObject} object
      */
     function onResult(object) {
-      callback(
+      fulfill(
           object ||
           target.runtimeModel.createRemoteObjectFromPrimitiveValue(Common.UIString('Preview is not available')));
     }
@@ -625,6 +628,7 @@
       onResult(null);
     else
       heapProfilerModel.objectForSnapshotObjectId(String(this.snapshotNodeId), objectGroupName).then(onResult);
+    return promise;
   }
 
   updateHasChildren() {
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
index 95e833e..32551e390 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -153,9 +153,8 @@
 
     this._selectedSizeText = new UI.ToolbarText();
 
-    this._popoverHelper = new UI.PopoverHelper(this.element, true);
-    this._popoverHelper.initializeCallbacks(
-        this._getHoverAnchor.bind(this), this._showObjectPopover.bind(this), this._onHidePopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this.element, this._getPopoverRequest.bind(this));
+    this._popoverHelper.setDisableOnClick(true);
     this._popoverHelper.setHasPadding(true);
     this.element.addEventListener('scroll', this._popoverHelper.hidePopover.bind(this._popoverHelper), true);
 
@@ -607,58 +606,36 @@
     }
   }
 
-  _getHoverAnchor(target) {
-    var span = target.enclosingNodeOrSelfWithNodeName('span');
-    if (!span)
-      return;
-    var row = target.enclosingNodeOrSelfWithNodeName('tr');
-    if (!row)
-      return;
-    span.node = row._dataGridNode;
-    return span;
-  }
-
   /**
-   * @param {!Element|!AnchorBox} element
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
+   * @param {!Event} event
+   * @return {?UI.PopoverRequest}
    */
-  _showObjectPopover(element, popover) {
-    if (!this._profile.target() || !element.node)
-      return Promise.resolve(false);
-
-    var fulfill;
-    var promise = new Promise(x => fulfill = x);
-    element.node.queryObjectContent(this._profile.target(), onObjectResolved.bind(this), 'popover');
-    return promise;
-
-    /**
-     * @param {?SDK.RemoteObject} result
-     * @this {Profiler.HeapSnapshotView}
-     */
-    function onObjectResolved(result) {
-      if (!result) {
-        fulfill(false);
-        return;
-      }
-      ObjectUI.ObjectPopoverHelper.buildObjectPopover(result, popover).then(objectPopoverHelper => {
+  _getPopoverRequest(event) {
+    var span = event.target.enclosingNodeOrSelfWithNodeName('span');
+    var row = event.target.enclosingNodeOrSelfWithNodeName('tr');
+    var target = this._profile.target();
+    if (!row || !span || !target)
+      return null;
+    var node = row._dataGridNode;
+    var objectPopoverHelper;
+    return {
+      box: span.boxInWindow(),
+      show: async popover => {
+        var remoteObject = await node.queryObjectContent(target, 'popover');
+        if (!remoteObject)
+          return false;
+        objectPopoverHelper = await ObjectUI.ObjectPopoverHelper.buildObjectPopover(remoteObject, popover);
         if (!objectPopoverHelper) {
-          this._onHidePopover();  // Cleanup object resolving artifacts.
-          fulfill(false);
-          return;
+          target.runtimeModel.releaseObjectGroup('popover');
+          return false;
         }
-        this._objectPopoverHelper = objectPopoverHelper;
-        fulfill(true);
-      });
-    }
-  }
-
-  _onHidePopover() {
-    if (this._objectPopoverHelper) {
-      this._objectPopoverHelper.dispose();
-      delete this._objectPopoverHelper;
-    }
-    this._profile.target().runtimeModel.releaseObjectGroup('popover');
+        return true;
+      },
+      hide: () => {
+        target.runtimeModel.releaseObjectGroup('popover');
+        objectPopoverHelper.dispose();
+      }
+    };
   }
 
   _updatePerspectiveOptions() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
index 9646937..b31fb71a 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMetadata.js
@@ -252,6 +252,7 @@
   'border-top',
   'border-top-color',
   'box-shadow',
+  'caret-color',
   'color',
   'column-rule',
   'column-rule-color',
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
index 078ee22c..5d6fcff 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -1185,6 +1185,36 @@
   }
 
   /**
+   * @param {string} code
+   * @param {string} objectGroup
+   * @param {boolean} includeCommandLineAPI
+   * @param {boolean} silent
+   * @param {boolean} returnByValue
+   * @param {boolean} generatePreview
+   * @return {!Promise<?SDK.RemoteObject>}
+   */
+  evaluatePromise(code, objectGroup, includeCommandLineAPI, silent, returnByValue, generatePreview) {
+    var fulfill;
+    var promise = new Promise(x => fulfill = x);
+    this.evaluate(
+        code, objectGroup, includeCommandLineAPI, silent, returnByValue, generatePreview, callback.bind(this));
+    return promise;
+
+    /**
+     * @param {?Protocol.Runtime.RemoteObject} result
+     * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
+     * @param {string=} error
+     * @this {SDK.DebuggerModel.CallFrame}
+     */
+    function callback(result, exceptionDetails, error) {
+      if (!result || exceptionDetails)
+        fulfill(null);
+      else
+        fulfill(this.debuggerModel._runtimeModel.createRemoteObject(result));
+    }
+  }
+
+  /**
    * @param {function(?Protocol.Error=)=} callback
    */
   restart(callback) {
diff --git a/third_party/WebKit/Source/devtools/front_end/security/SecurityModel.js b/third_party/WebKit/Source/devtools/front_end/security/SecurityModel.js
index 157f418..273c3a6 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/SecurityModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/security/SecurityModel.js
@@ -108,4 +108,14 @@
         securityState, schemeIsCryptographic, explanations, insecureContentStatus, summary || null);
     this._model.dispatchEventToListeners(Security.SecurityModel.Events.SecurityStateChanged, pageSecurityState);
   }
+
+
+  /**
+   * @override
+   * @param {number} eventId
+   * @param {string} errorType
+   * @param {string} requestURL
+   */
+  certificateError(eventId, errorType, requestURL) {
+  }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js b/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
index 33beb72..38935d66 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/UISourceCodeFrame.js
@@ -74,8 +74,7 @@
     this._updateStyle();
     this._updateDiffUISourceCode();
 
-    this._errorPopoverHelper = new UI.PopoverHelper(this.element);
-    this._errorPopoverHelper.initializeCallbacks(this._getErrorAnchor.bind(this), this._showErrorPopover.bind(this));
+    this._errorPopoverHelper = new UI.PopoverHelper(this.element, this._getErrorPopoverContent.bind(this));
     this._errorPopoverHelper.setHasPadding(true);
 
     this._errorPopoverHelper.setTimeout(100, 100);
@@ -401,33 +400,26 @@
   }
 
   /**
-   * @param {!Element} target
    * @param {!Event} event
-   * @return {(!Element|undefined)}
+   * @return {?UI.PopoverRequest}
    */
-  _getErrorAnchor(target, event) {
-    var element = target.enclosingNodeOrSelfWithClass('text-editor-line-decoration-icon') ||
-        target.enclosingNodeOrSelfWithClass('text-editor-line-decoration-wave');
+  _getErrorPopoverContent(event) {
+    var element = event.target.enclosingNodeOrSelfWithClass('text-editor-line-decoration-icon') ||
+        event.target.enclosingNodeOrSelfWithClass('text-editor-line-decoration-wave');
     if (!element)
-      return;
-    this._errorWavePopoverAnchor = new AnchorBox(event.clientX, event.clientY, 1, 1);
-    return element;
-  }
-
-  /**
-   * @param {!Element|!AnchorBox} anchor
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showErrorPopover(anchor, popover) {
-    var element = /** @type {!Element} */ (anchor);
-    var messageBucket = element.enclosingNodeOrSelfWithClass('text-editor-line-decoration')._messageBucket;
-    var messagesOutline = messageBucket.messagesDescription();
-    popover.setContentAnchorBox(
-        element.enclosingNodeOrSelfWithClass('text-editor-line-decoration-icon') ? element.boxInWindow() :
-                                                                                   this._errorWavePopoverAnchor);
-    popover.contentElement.appendChild(messagesOutline);
-    return Promise.resolve(true);
+      return null;
+    var anchor = element.enclosingNodeOrSelfWithClass('text-editor-line-decoration-icon') ?
+        element.boxInWindow() :
+        new AnchorBox(event.clientX, event.clientY, 1, 1);
+    return {
+      box: anchor,
+      show: popover => {
+        var messageBucket = element.enclosingNodeOrSelfWithClass('text-editor-line-decoration')._messageBucket;
+        var messagesOutline = messageBucket.messagesDescription();
+        popover.contentElement.appendChild(messagesOutline);
+        return Promise.resolve(true);
+      }
+    };
   }
 
   _updateBucketDecorations() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index 8cd68688..e76e19e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -44,9 +44,8 @@
     if (uiSourceCode.project().type() === Workspace.projectTypes.Debugger)
       this.element.classList.add('source-frame-debugger-script');
 
-    this._popoverHelper = new UI.PopoverHelper(this._scriptsPanel.element, true);
-    this._popoverHelper.initializeCallbacks(
-        this._getPopoverAnchor.bind(this), this._showObjectPopover.bind(this), this._onHidePopover.bind(this));
+    this._popoverHelper = new UI.PopoverHelper(this._scriptsPanel.element, this._getPopoverRequest.bind(this));
+    this._popoverHelper.setDisableOnClick(true);
     this._popoverHelper.setTimeout(250, 250);
     this._popoverHelper.setHasPadding(true);
     this._scriptsPanel.element.addEventListener(
@@ -376,150 +375,99 @@
     return tokenType.startsWith('js-variable') || tokenType.startsWith('js-property') || tokenType === 'js-def';
   }
 
-  _getPopoverAnchor(element, event) {
+  /**
+   * @param {!Event} event
+   * @return {?UI.PopoverRequest}
+   */
+  _getPopoverRequest(event) {
     var target = UI.context.flavor(SDK.Target);
     var debuggerModel = target ? target.model(SDK.DebuggerModel) : null;
     if (!debuggerModel || !debuggerModel.isPaused())
-      return;
+      return null;
 
     var textPosition = this.textEditor.coordinatesToCursorPosition(event.x, event.y);
     if (!textPosition)
-      return;
+      return null;
+
     var mouseLine = textPosition.startLine;
     var mouseColumn = textPosition.startColumn;
     var textSelection = this.textEditor.selection().normalize();
+    var anchorBox;
+    var lineNumber;
+    var startHighlight;
+    var endHighlight;
+
     if (textSelection && !textSelection.isEmpty()) {
       if (textSelection.startLine !== textSelection.endLine || textSelection.startLine !== mouseLine ||
           mouseColumn < textSelection.startColumn || mouseColumn > textSelection.endColumn)
-        return;
+        return null;
 
       var leftCorner = this.textEditor.cursorPositionToCoordinates(textSelection.startLine, textSelection.startColumn);
       var rightCorner = this.textEditor.cursorPositionToCoordinates(textSelection.endLine, textSelection.endColumn);
-      var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
-      anchorBox.highlight = {
-        lineNumber: textSelection.startLine,
-        startColumn: textSelection.startColumn,
-        endColumn: textSelection.endColumn - 1
-      };
-      anchorBox.forSelection = true;
-      return anchorBox;
-    }
+      anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
+      lineNumber = textSelection.startLine;
+      startHighlight = textSelection.startColumn;
+      endHighlight = textSelection.endColumn - 1;
+    } else {
+      var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, textPosition.startColumn);
+      if (!token || !token.type)
+        return null;
+      lineNumber = textPosition.startLine;
+      var line = this.textEditor.line(lineNumber);
+      var tokenContent = line.substring(token.startColumn, token.endColumn);
 
-    var token = this.textEditor.tokenAtTextPosition(textPosition.startLine, textPosition.startColumn);
-    if (!token || !token.type)
-      return;
-    var lineNumber = textPosition.startLine;
-    var line = this.textEditor.line(lineNumber);
-    var tokenContent = line.substring(token.startColumn, token.endColumn);
+      var isIdentifier = this._isIdentifier(token.type);
+      if (!isIdentifier && (token.type !== 'js-keyword' || tokenContent !== 'this'))
+        return null;
 
-    var isIdentifier = this._isIdentifier(token.type);
-    if (!isIdentifier && (token.type !== 'js-keyword' || tokenContent !== 'this'))
-      return;
+      var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.startColumn);
+      var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.endColumn - 1);
+      anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
 
-    var leftCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.startColumn);
-    var rightCorner = this.textEditor.cursorPositionToCoordinates(lineNumber, token.endColumn - 1);
-    var anchorBox = new AnchorBox(leftCorner.x, leftCorner.y, rightCorner.x - leftCorner.x, leftCorner.height);
-
-    anchorBox.highlight = {lineNumber: lineNumber, startColumn: token.startColumn, endColumn: token.endColumn - 1};
-
-    return anchorBox;
-  }
-
-  /**
-   * @param {!AnchorBox} anchorBox
-   * @return {!Promise<?SDK.RemoteObject>}
-   */
-  _resolveObjectForPopover(anchorBox) {
-    var selectedCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
-    if (!selectedCallFrame)
-      return Promise.resolve(/** @type {?SDK.RemoteObject} */ (null));
-    var lineNumber = anchorBox.highlight.lineNumber;
-    var startHighlight = anchorBox.highlight.startColumn;
-    var endHighlight = anchorBox.highlight.endColumn;
-    var line = this.textEditor.line(lineNumber);
-    if (!anchorBox.forSelection) {
+      startHighlight = token.startColumn;
+      endHighlight = token.endColumn - 1;
       while (startHighlight > 1 && line.charAt(startHighlight - 1) === '.') {
-        var token = this.textEditor.tokenAtTextPosition(lineNumber, startHighlight - 2);
-        if (!token || !token.type)
-          return Promise.resolve(/** @type {?SDK.RemoteObject} */ (null));
-        startHighlight = token.startColumn;
+        var tokenBefore = this.textEditor.tokenAtTextPosition(lineNumber, startHighlight - 2);
+        if (!tokenBefore || !tokenBefore.type)
+          return null;
+        startHighlight = tokenBefore.startColumn;
       }
     }
-    var evaluationText = line.substring(startHighlight, endHighlight + 1);
-    return Sources.SourceMapNamesResolver
-        .resolveExpression(
-            selectedCallFrame, evaluationText, this._debuggerSourceCode, lineNumber, startHighlight, endHighlight)
-        .then(onResolve.bind(this));
 
-    /**
-     * @param {?string=} text
-     * @return {!Promise<?SDK.RemoteObject>}
-     * @this {Sources.JavaScriptSourceFrame}
-     */
-    function onResolve(text) {
-      var fulfill;
-      var promise = new Promise(x => fulfill = x);
-      selectedCallFrame.evaluate(
-          text || evaluationText, 'popover', false, true, false, false, showObjectPopover.bind(this, fulfill));
-      return promise;
-    }
+    var objectPopoverHelper;
+    var highlightDescriptor;
 
-    /**
-     * @param {function(?SDK.RemoteObject)} fulfill
-     * @param {?Protocol.Runtime.RemoteObject} result
-     * @param {!Protocol.Runtime.ExceptionDetails=} exceptionDetails
-     * @this {Sources.JavaScriptSourceFrame}
-     */
-    function showObjectPopover(fulfill, result, exceptionDetails) {
-      var target = UI.context.flavor(SDK.Target);
-      var potentiallyUpdatedCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
-      if (selectedCallFrame !== potentiallyUpdatedCallFrame || !result || exceptionDetails) {
-        fulfill(null);
-        return;
-      }
-      this._popoverAnchorBox = anchorBox;
-      this._popoverTarget = target;
-      var highlightRange = new Common.TextRange(lineNumber, startHighlight, lineNumber, endHighlight);
-      this._popoverAnchorBox._highlightDescriptor =
-          this.textEditor.highlightRange(highlightRange, 'source-frame-eval-expression');
-      fulfill(target.runtimeModel.createRemoteObject(result));
-    }
-  }
-
-  /**
-   * @param {!AnchorBox|!Element} anchorBox
-   * @param {!UI.GlassPane} popover
-   * @return {!Promise<boolean>}
-   */
-  _showObjectPopover(anchorBox, popover) {
-    return this._resolveObjectForPopover(/** @type {!AnchorBox} */ (anchorBox)).then(object => {
-      if (!object)
-        return false;
-      return ObjectUI.ObjectPopoverHelper.buildObjectPopover(object, popover).then(objectPopoverHelper => {
-        if (!objectPopoverHelper) {
-          this._onHidePopover();  // Cleanup artifacts from _resolveObjectForPopover.
+    return {
+      box: anchorBox,
+      show: async popover => {
+        var selectedCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
+        if (!selectedCallFrame)
+          return false;
+        var evaluationText = this.textEditor.line(lineNumber).substring(startHighlight, endHighlight + 1);
+        var resolvedText = await Sources.SourceMapNamesResolver.resolveExpression(
+            selectedCallFrame, evaluationText, this._debuggerSourceCode, lineNumber, startHighlight, endHighlight);
+        var remoteObject = await selectedCallFrame.evaluatePromise(
+            resolvedText || evaluationText, 'popover', false, true, false, false);
+        if (!remoteObject)
+          return false;
+        objectPopoverHelper = await ObjectUI.ObjectPopoverHelper.buildObjectPopover(remoteObject, popover);
+        var potentiallyUpdatedCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame);
+        if (!objectPopoverHelper || selectedCallFrame !== potentiallyUpdatedCallFrame) {
+          target.runtimeModel.releaseObjectGroup('popover');
+          if (objectPopoverHelper)
+            objectPopoverHelper.dispose();
           return false;
         }
-        this._objectPopoverHelper = objectPopoverHelper;
+        var highlightRange = new Common.TextRange(lineNumber, startHighlight, lineNumber, endHighlight);
+        highlightDescriptor = this.textEditor.highlightRange(highlightRange, 'source-frame-eval-expression');
         return true;
-      });
-    });
-  }
-
-  _onHidePopover() {
-    if (this._objectPopoverHelper) {
-      this._objectPopoverHelper.dispose();
-      delete this._objectPopoverHelper;
-    }
-    if (this._popoverTarget) {
-      this._popoverTarget.runtimeModel.releaseObjectGroup('popover');
-      delete this._popoverTarget;
-    }
-    if (this._popoverAnchorBox) {
-      if (this._popoverAnchorBox._highlightDescriptor)
-        this.textEditor.removeHighlight(this._popoverAnchorBox._highlightDescriptor);
-      delete this._popoverAnchorBox;
-    }
+      },
+      hide: () => {
+        objectPopoverHelper.dispose();
+        target.runtimeModel.releaseObjectGroup('popover');
+        this.textEditor.removeHighlight(highlightDescriptor);
+      }
+    };
   }
 
   _onKeyDown(event) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
index 614b5099..ee01b9a 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -694,7 +694,7 @@
       var url = TimelineModel.TimelineData.forEvent(event).url;
       event[Timeline.TimelineUIUtils._previewElementSymbol] = await new Promise(fulfill => {
         if (url)
-          Components.DOMPresentationUtils.buildImagePreviewContents(target, url, false, fulfill);
+          Components.DOMPresentationUtils.buildImagePreviewContents(target, url, false).then(fulfill);
         else if (TimelineModel.TimelineData.forEvent(event).picture)
           Timeline.TimelineUIUtils.buildPicturePreviewContent(event, target, fulfill);
         else
@@ -1131,13 +1131,15 @@
      * @param {function(?Element)} fulfill
      */
     function action(fulfill) {
-      Components.DOMPresentationUtils.buildImagePreviewContents(
-          /** @type {!SDK.Target} */ (target), request.url, false, saveImage);
+      Components.DOMPresentationUtils
+          .buildImagePreviewContents(
+              /** @type {!SDK.Target} */ (target), request.url, false)
+          .then(saveImage);
       /**
-       * @param {!Element=} element
+       * @param {?Element} element
        */
       function saveImage(element) {
-        request.previewElement = element || null;
+        request.previewElement = element;
         fulfill(request.previewElement);
       }
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Popover.js b/third_party/WebKit/Source/devtools/front_end/ui/Popover.js
index 5bc0a5f..e96c3d01 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Popover.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Popover.js
@@ -33,30 +33,23 @@
  */
 UI.PopoverHelper = class {
   /**
-   * @param {!Element} panelElement
-   * @param {boolean=} disableOnClick
+   * @param {!Element} container
+   * @param {function(!Event):?UI.PopoverRequest} getRequest
    */
-  constructor(panelElement, disableOnClick) {
-    this._disableOnClick = !!disableOnClick;
+  constructor(container, getRequest) {
+    this._disableOnClick = false;
     this._hasPadding = false;
-    panelElement.addEventListener('mousedown', this._mouseDown.bind(this), false);
-    panelElement.addEventListener('mousemove', this._mouseMove.bind(this), false);
-    panelElement.addEventListener('mouseout', this._mouseOut.bind(this), false);
+    this._getRequest = getRequest;
+    this._scheduledRequest = null;
+    /** @type {?function()} */
+    this._hidePopoverCallback = null;
+    container.addEventListener('mousedown', this._mouseDown.bind(this), false);
+    container.addEventListener('mousemove', this._mouseMove.bind(this), false);
+    container.addEventListener('mouseout', this._mouseOut.bind(this), false);
     this.setTimeout(1000, 500);
   }
 
   /**
-   * @param {function(!Element, !Event):(!Element|!AnchorBox|undefined)} getAnchor
-   * @param {function((!Element|!AnchorBox), !UI.GlassPane):!Promise<boolean>} showPopover
-   * @param {function()=} onHide
-   */
-  initializeCallbacks(getAnchor, showPopover, onHide) {
-    this._getAnchor = getAnchor;
-    this._showPopover = showPopover;
-    this._onHide = onHide;
-  }
-
-  /**
    * @param {number} timeout
    * @param {number=} hideTimeout
    */
@@ -76,147 +69,182 @@
   }
 
   /**
-   * @param {!MouseEvent} event
-   * @return {boolean}
+   * @param {boolean} disableOnClick
    */
-  _eventInHoverElement(event) {
-    if (!this._hoverElement)
-      return false;
-    var box = this._hoverElement instanceof AnchorBox ? this._hoverElement : this._hoverElement.boxInWindow();
-    return (
-        box.x <= event.clientX && event.clientX <= box.x + box.width && box.y <= event.clientY &&
-        event.clientY <= box.y + box.height);
+  setDisableOnClick(disableOnClick) {
+    this._disableOnClick = disableOnClick;
   }
 
+  /**
+   * @param {!Event} event
+   * @return {boolean}
+   */
+  _eventInScheduledContent(event) {
+    return this._scheduledRequest ? this._scheduledRequest.box.contains(event.clientX, event.clientY) : false;
+  }
+
+  /**
+   * @param {!Event} event
+   */
   _mouseDown(event) {
-    if (this._disableOnClick || !this._eventInHoverElement(event)) {
+    if (this._disableOnClick || !this._eventInScheduledContent(event)) {
       this.hidePopover();
     } else {
-      this._killHidePopoverTimer();
-      this._handleMouseAction(event, true);
+      this._stopHidePopoverTimer();
+      this._stopShowPopoverTimer();
+      this._startShowPopoverTimer(event, 0);
     }
   }
 
+  /**
+   * @param {!Event} event
+   */
   _mouseMove(event) {
     // Pretend that nothing has happened.
-    if (this._eventInHoverElement(event))
+    if (this._eventInScheduledContent(event))
       return;
 
     this._startHidePopoverTimer();
-    this._handleMouseAction(event, false);
+    this._stopShowPopoverTimer();
+    if (event.which && this._disableOnClick)
+      return;
+    this._startShowPopoverTimer(
+        event, this.isPopoverVisible() ? Math.max(this._timeout * 0.6, this._hideTimeout) : this._timeout);
   }
 
-  _popoverMouseOut(event) {
-    if (!this.isPopoverVisible())
+  /**
+   * @param {!Event} event
+   */
+  _popoverMouseMove(event) {
+    this._stopHidePopoverTimer();
+  }
+
+  /**
+   * @param {!UI.GlassPane} popover
+   * @param {!Event} event
+   */
+  _popoverMouseOut(popover, event) {
+    if (!popover.isShowing())
       return;
-    if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(this._popover.contentElement))
+    if (event.relatedTarget && !event.relatedTarget.isSelfOrDescendant(popover.contentElement))
       this._startHidePopoverTimer();
   }
 
+  /**
+   * @param {!Event} event
+   */
   _mouseOut(event) {
     if (!this.isPopoverVisible())
       return;
-    if (!this._eventInHoverElement(event))
+    if (!this._eventInScheduledContent(event))
       this._startHidePopoverTimer();
   }
 
   _startHidePopoverTimer() {
-    // User has 500ms (this._hideTimeout) to reach the popup.
-    if (!this._popover || this._hidePopoverTimer)
+    // User has this._hideTimeout to reach the popup.
+    if (!this._hidePopoverCallback || this._hidePopoverTimer)
       return;
 
-    /**
-     * @this {UI.PopoverHelper}
-     */
-    function doHide() {
+    this._hidePopoverTimer = setTimeout(() => {
       this._hidePopover();
       delete this._hidePopoverTimer;
-    }
-    this._hidePopoverTimer = setTimeout(doHide.bind(this), this._hideTimeout);
+    }, this._hideTimeout);
   }
 
-  _handleMouseAction(event, isMouseDown) {
-    this._resetHoverTimer();
-    if (event.which && this._disableOnClick)
+  /**
+   * @param {!Event} event
+   * @param {number} timeout
+   */
+  _startShowPopoverTimer(event, timeout) {
+    this._scheduledRequest = this._getRequest.call(null, event);
+    if (!this._scheduledRequest)
       return;
-    this._hoverElement = this._getAnchor(event.target, event);
-    if (!this._hoverElement)
-      return;
-    const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout);
-    this._hoverTimer =
-        setTimeout(this._mouseHover.bind(this, this._hoverElement, event.target.ownerDocument), toolTipDelay);
+
+    this._showPopoverTimer = setTimeout(() => {
+      delete this._showPopoverTimer;
+      this._showPopover(event.target.ownerDocument);
+    }, timeout);
   }
 
-  _resetHoverTimer() {
-    if (this._hoverTimer) {
-      clearTimeout(this._hoverTimer);
-      delete this._hoverTimer;
-    }
+  _stopShowPopoverTimer() {
+    if (!this._showPopoverTimer)
+      return;
+    clearTimeout(this._showPopoverTimer);
+    delete this._showPopoverTimer;
   }
 
   /**
    * @return {boolean}
    */
   isPopoverVisible() {
-    return !!this._popover;
+    return !!this._hidePopoverCallback;
   }
 
   hidePopover() {
-    this._resetHoverTimer();
+    this._stopShowPopoverTimer();
     this._hidePopover();
   }
 
   _hidePopover() {
-    if (!this._popover)
+    if (!this._hidePopoverCallback)
       return;
-
-    delete UI.PopoverHelper._popover;
-    if (this._onHide)
-      this._onHide();
-
-    if (this._popover.isShowing())
-      this._popover.hide();
-    delete this._popover;
-    this._hoverElement = null;
+    this._hidePopoverCallback.call(null);
+    this._hidePopoverCallback = null;
   }
 
-  _mouseHover(element, document) {
-    delete this._hoverTimer;
-    this._hidePopover();
-    this._hoverElement = element;
+  /**
+   * @param {!Document} document
+   */
+  _showPopover(document) {
+    var popover = new UI.GlassPane();
+    popover.registerRequiredCSS('ui/popover.css');
+    popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
+    popover.setBlockPointerEvents(false);
+    popover.setShowArrow(true);
+    var request = this._scheduledRequest;
+    request.show.call(null, popover).then(success => {
+      if (!success)
+        return;
 
-    this._popover = new UI.GlassPane();
-    this._popover.registerRequiredCSS('ui/popover.css');
-    this._popover.setBlockPointerEvents(false);
-    this._popover.setSizeBehavior(UI.GlassPane.SizeBehavior.MeasureContent);
-    this._popover.setShowArrow(true);
-    this._popover.contentElement.classList.toggle('has-padding', this._hasPadding);
-    this._popover.contentElement.addEventListener('mousemove', this._killHidePopoverTimer.bind(this), true);
-    this._popover.contentElement.addEventListener('mouseout', this._popoverMouseOut.bind(this), true);
-    this._popover.setContentAnchorBox(
-        this._hoverElement instanceof AnchorBox ? this._hoverElement : this._hoverElement.boxInWindow());
+      if (this._scheduledRequest !== request) {
+        if (request.hide)
+          request.hide.call(null);
+        return;
+      }
 
-    // This should not happen, but we hide previous popover to be on the safe side.
-    if (UI.PopoverHelper._popover) {
-      console.error('One popover is already visible');
-      UI.PopoverHelper._popover.hide();
-    }
-    UI.PopoverHelper._popover = this._popover;
-    var popover = this._popover;
-    this._showPopover(element, this._popover).then(success => {
-      if (success && this._popover === popover && this._hoverElement === element)
-        popover.show(document);
+      // This should not happen, but we hide previous popover to be on the safe side.
+      if (UI.PopoverHelper._popoverHelper) {
+        console.error('One popover is already visible');
+        UI.PopoverHelper._popoverHelper.hidePopover();
+      }
+      UI.PopoverHelper._popoverHelper = this;
+
+      popover.contentElement.classList.toggle('has-padding', this._hasPadding);
+      popover.contentElement.addEventListener('mousemove', this._popoverMouseMove.bind(this), true);
+      popover.contentElement.addEventListener('mouseout', this._popoverMouseOut.bind(this, popover), true);
+      popover.setContentAnchorBox(request.box);
+      popover.show(document);
+
+      this._hidePopoverCallback = () => {
+        if (request.hide)
+          request.hide.call(null);
+        popover.hide();
+        delete UI.PopoverHelper._popoverHelper;
+      };
     });
   }
 
-  _killHidePopoverTimer() {
-    if (this._hidePopoverTimer) {
-      clearTimeout(this._hidePopoverTimer);
-      delete this._hidePopoverTimer;
+  _stopHidePopoverTimer() {
+    if (!this._hidePopoverTimer)
+      return;
+    clearTimeout(this._hidePopoverTimer);
+    delete this._hidePopoverTimer;
 
-      // We know that we reached the popup, but we might have moved over other elements.
-      // Discard pending command.
-      this._resetHoverTimer();
-    }
+    // We know that we reached the popup, but we might have moved over other elements.
+    // Discard pending command.
+    this._stopShowPopoverTimer();
   }
 };
+
+/** @typedef {{box: !AnchorBox, show:(function(!UI.GlassPane):!Promise<boolean>), hide:(function()|undefined)}} */
+UI.PopoverRequest;
diff --git a/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.idl b/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.idl
index 6aa0ce7..1d2f914 100644
--- a/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.idl
+++ b/third_party/WebKit/Source/modules/installedapp/NavigatorInstalledApp.idl
@@ -8,5 +8,5 @@
 [
     RuntimeEnabled=InstalledApp,
 ] partial interface Navigator {
-    [SecureContext, CallWith=ScriptState] Promise<RelatedApplication> getInstalledRelatedApps();
+    [SecureContext, CallWith=ScriptState, Measure] Promise<RelatedApplication> getInstalledRelatedApps();
 };
diff --git a/third_party/WebKit/Source/modules/shapedetection/BUILD.gn b/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
index 8102c764..663f27599 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
+++ b/third_party/WebKit/Source/modules/shapedetection/BUILD.gn
@@ -24,5 +24,6 @@
 
   public_deps = [
     "//services/shape_detection/public/interfaces:interfaces_blink",
+    "//skia/public/interfaces:interfaces_blink",
   ]
 }
diff --git a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
index a78d39b..6e9abeb 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.cpp
@@ -26,11 +26,8 @@
                 wrapWeakPersistent(this))));
 }
 
-ScriptPromise BarcodeDetector::doDetect(
-    ScriptPromiseResolver* resolver,
-    mojo::ScopedSharedBufferHandle sharedBufferHandle,
-    int imageWidth,
-    int imageHeight) {
+ScriptPromise BarcodeDetector::doDetect(ScriptPromiseResolver* resolver,
+                                        skia::mojom::blink::BitmapPtr bitmap) {
   ScriptPromise promise = resolver->promise();
   if (!m_barcodeService) {
     resolver->reject(DOMException::create(
@@ -39,10 +36,9 @@
   }
   m_barcodeServiceRequests.insert(resolver);
   m_barcodeService->Detect(
-      std::move(sharedBufferHandle), imageWidth, imageHeight,
-      convertToBaseCallback(WTF::bind(&BarcodeDetector::onDetectBarcodes,
-                                      wrapPersistent(this),
-                                      wrapPersistent(resolver))));
+      std::move(bitmap), convertToBaseCallback(WTF::bind(
+                             &BarcodeDetector::onDetectBarcodes,
+                             wrapPersistent(this), wrapPersistent(resolver))));
   return promise;
 }
 
diff --git a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
index 2d0e5986..7e3fa4af8 100644
--- a/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/BarcodeDetector.h
@@ -29,9 +29,7 @@
   ~BarcodeDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         mojo::ScopedSharedBufferHandle,
-                         int imageWidth,
-                         int imageHeight) override;
+                         skia::mojom::blink::BitmapPtr) override;
   void onDetectBarcodes(
       ScriptPromiseResolver*,
       Vector<shape_detection::mojom::blink::BarcodeDetectionResultPtr>);
diff --git a/third_party/WebKit/Source/modules/shapedetection/DEPS b/third_party/WebKit/Source/modules/shapedetection/DEPS
index 372894a..76ba38ac 100644
--- a/third_party/WebKit/Source/modules/shapedetection/DEPS
+++ b/third_party/WebKit/Source/modules/shapedetection/DEPS
@@ -10,6 +10,7 @@
     "+platform",
     "+public/platform",
     "+services/shape_detection",
+    "+skia/public/interfaces/bitmap.mojom-blink.h",
     "+third_party/skia/include/core/SkImage.h",
     "+third_party/skia/include/core/SkImageInfo.h",
     "+ui/gfx/geometry",
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
index 8593617..ca0b77b8 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.cpp
@@ -35,11 +35,8 @@
       &FaceDetector::onFaceServiceConnectionError, wrapWeakPersistent(this))));
 }
 
-ScriptPromise FaceDetector::doDetect(
-    ScriptPromiseResolver* resolver,
-    mojo::ScopedSharedBufferHandle sharedBufferHandle,
-    int imageWidth,
-    int imageHeight) {
+ScriptPromise FaceDetector::doDetect(ScriptPromiseResolver* resolver,
+                                     skia::mojom::blink::BitmapPtr bitmap) {
   ScriptPromise promise = resolver->promise();
   if (!m_faceService) {
     resolver->reject(DOMException::create(
@@ -47,7 +44,7 @@
     return promise;
   }
   m_faceServiceRequests.insert(resolver);
-  m_faceService->Detect(std::move(sharedBufferHandle), imageWidth, imageHeight,
+  m_faceService->Detect(std::move(bitmap),
                         convertToBaseCallback(WTF::bind(
                             &FaceDetector::onDetectFaces, wrapPersistent(this),
                             wrapPersistent(resolver))));
diff --git a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
index 84f6b9f..2047879c 100644
--- a/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/FaceDetector.h
@@ -31,9 +31,7 @@
   ~FaceDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         mojo::ScopedSharedBufferHandle,
-                         int imageWidth,
-                         int imageHeight) override;
+                         skia::mojom::blink::BitmapPtr) override;
   void onDetectFaces(ScriptPromiseResolver*,
                      shape_detection::mojom::blink::FaceDetectionResultPtr);
   void onFaceServiceConnectionError();
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
index fd3119d..259193e 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.cpp
@@ -22,28 +22,19 @@
 
 namespace {
 
-mojo::ScopedSharedBufferHandle getSharedBufferOnData(
-    ScriptPromiseResolver* resolver,
-    uint8_t* data,
-    int size) {
-  DCHECK(data);
-  DCHECK(size);
-  ScriptPromise promise = resolver->promise();
+skia::mojom::blink::BitmapPtr createBitmapFromData(int width,
+                                                   int height,
+                                                   Vector<uint8_t> bitmapData) {
+  skia::mojom::blink::BitmapPtr bitmap = skia::mojom::blink::Bitmap::New();
 
-  mojo::ScopedSharedBufferHandle sharedBufferHandle =
-      mojo::SharedBufferHandle::Create(size);
-  if (!sharedBufferHandle->is_valid()) {
-    resolver->reject(
-        DOMException::create(InvalidStateError, "Internal allocation error"));
-    return sharedBufferHandle;
-  }
+  bitmap->color_type = (kN32_SkColorType == kRGBA_8888_SkColorType)
+                           ? skia::mojom::ColorType::RGBA_8888
+                           : skia::mojom::ColorType::BGRA_8888;
+  bitmap->width = width;
+  bitmap->height = height;
+  bitmap->pixel_data = std::move(bitmapData);
 
-  const mojo::ScopedSharedBufferMapping mappedBuffer =
-      sharedBufferHandle->Map(size);
-  DCHECK(mappedBuffer.get());
-  memcpy(mappedBuffer.get(), data, size);
-
-  return sharedBufferHandle;
+  return bitmap;
 }
 
 }  // anonymous namespace
@@ -134,13 +125,13 @@
     return promise;
   }
 
-  mojo::ScopedSharedBufferHandle sharedBufferHandle = getSharedBufferOnData(
-      resolver, pixelDataPtr, allocationSize.ValueOrDefault(0));
-  if (!sharedBufferHandle->is_valid())
-    return promise;
+  WTF::Vector<uint8_t> bitmapData;
+  bitmapData.append(pixelDataPtr,
+                    static_cast<int>(allocationSize.ValueOrDefault(0)));
 
-  return doDetect(resolver, std::move(sharedBufferHandle), image->width(),
-                  image->height());
+  return doDetect(resolver,
+                  createBitmapFromData(image->width(), image->height(),
+                                       std::move(bitmapData)));
 }
 
 ScriptPromise ShapeDetector::detectShapesOnImageData(
@@ -155,14 +146,12 @@
 
   uint8_t* const data = imageData->data()->data();
   WTF::CheckedNumeric<int> allocationSize = imageData->size().area() * 4;
+  WTF::Vector<uint8_t> bitmapData;
+  bitmapData.append(data, static_cast<int>(allocationSize.ValueOrDefault(0)));
 
-  mojo::ScopedSharedBufferHandle sharedBufferHandle =
-      getSharedBufferOnData(resolver, data, allocationSize.ValueOrDefault(0));
-  if (!sharedBufferHandle->is_valid())
-    return promise;
-
-  return doDetect(resolver, std::move(sharedBufferHandle), imageData->width(),
-                  imageData->height());
+  return doDetect(resolver,
+                  createBitmapFromData(imageData->width(), imageData->height(),
+                                       std::move(bitmapData)));
 }
 
 ScriptPromise ShapeDetector::detectShapesOnImageElement(
@@ -201,26 +190,10 @@
 
   const SkImageInfo skiaInfo =
       SkImageInfo::MakeN32(image->width(), image->height(), image->alphaType());
+  size_t rowBytes = skiaInfo.minRowBytes();
 
-  const uint32_t allocationSize = skiaInfo.getSafeSize(skiaInfo.minRowBytes());
-
-  mojo::ScopedSharedBufferHandle sharedBufferHandle =
-      mojo::SharedBufferHandle::Create(allocationSize);
-  if (!sharedBufferHandle.is_valid()) {
-    DLOG(ERROR) << "Requested allocation : " << allocationSize
-                << "B, larger than |mojo::edk::kMaxSharedBufferSize| == 16MB ";
-    // TODO(xianglu): For now we reject the promise if the image is too large.
-    // But consider resizing the image to remove restriction on the user side.
-    // Also, add LayoutTests for this case later.
-    resolver->reject(
-        DOMException::create(InvalidStateError, "Image exceeds size limit."));
-    return promise;
-  }
-
-  const mojo::ScopedSharedBufferMapping mappedBuffer =
-      sharedBufferHandle->Map(allocationSize);
-
-  const SkPixmap pixmap(skiaInfo, mappedBuffer.get(), skiaInfo.minRowBytes());
+  Vector<uint8_t> bitmapData(skiaInfo.getSafeSize(rowBytes));
+  const SkPixmap pixmap(skiaInfo, bitmapData.data(), rowBytes);
   if (!image->readPixels(pixmap, 0, 0)) {
     resolver->reject(DOMException::create(
         InvalidStateError,
@@ -228,8 +201,9 @@
     return promise;
   }
 
-  return doDetect(resolver, std::move(sharedBufferHandle), img->naturalWidth(),
-                  img->naturalHeight());
+  return doDetect(
+      resolver, createBitmapFromData(img->naturalWidth(), img->naturalHeight(),
+                                     std::move(bitmapData)));
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
index 74b8e70e..cd55e5cc 100644
--- a/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/ShapeDetector.h
@@ -10,6 +10,7 @@
 #include "core/imagebitmap/ImageBitmapFactories.h"
 #include "modules/ModulesExport.h"
 #include "modules/canvas2d/CanvasRenderingContext2D.h"
+#include "skia/public/interfaces/bitmap.mojom-blink.h"
 
 namespace blink {
 
@@ -27,9 +28,7 @@
                                            const HTMLImageElement*);
 
   virtual ScriptPromise doDetect(ScriptPromiseResolver*,
-                                 mojo::ScopedSharedBufferHandle,
-                                 int imageWidth,
-                                 int imageHeight) = 0;
+                                 skia::mojom::blink::BitmapPtr) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp b/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
index 1b365ac..5b845570 100644
--- a/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
+++ b/third_party/WebKit/Source/modules/shapedetection/TextDetector.cpp
@@ -24,11 +24,8 @@
       &TextDetector::onTextServiceConnectionError, wrapWeakPersistent(this))));
 }
 
-ScriptPromise TextDetector::doDetect(
-    ScriptPromiseResolver* resolver,
-    mojo::ScopedSharedBufferHandle sharedBufferHandle,
-    int imageWidth,
-    int imageHeight) {
+ScriptPromise TextDetector::doDetect(ScriptPromiseResolver* resolver,
+                                     skia::mojom::blink::BitmapPtr bitmap) {
   ScriptPromise promise = resolver->promise();
   if (!m_textService) {
     resolver->reject(DOMException::create(
@@ -36,7 +33,7 @@
     return promise;
   }
   m_textServiceRequests.insert(resolver);
-  m_textService->Detect(std::move(sharedBufferHandle), imageWidth, imageHeight,
+  m_textService->Detect(std::move(bitmap),
                         convertToBaseCallback(WTF::bind(
                             &TextDetector::onDetectText, wrapPersistent(this),
                             wrapPersistent(resolver))));
diff --git a/third_party/WebKit/Source/modules/shapedetection/TextDetector.h b/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
index 64791e3..800893c 100644
--- a/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
+++ b/third_party/WebKit/Source/modules/shapedetection/TextDetector.h
@@ -29,9 +29,7 @@
   ~TextDetector() override = default;
 
   ScriptPromise doDetect(ScriptPromiseResolver*,
-                         mojo::ScopedSharedBufferHandle,
-                         int imageWidth,
-                         int imageHeight) override;
+                         skia::mojom::blink::BitmapPtr) override;
   void onDetectText(
       ScriptPromiseResolver*,
       Vector<shape_detection::mojom::blink::TextDetectionResultPtr>);
diff --git a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
index f208ee6..0b78131 100644
--- a/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/OfflineAudioContext.cpp
@@ -90,6 +90,7 @@
 
   OfflineAudioContext* audioContext = new OfflineAudioContext(
       document, numberOfChannels, numberOfFrames, sampleRate, exceptionState);
+  audioContext->suspendIfNeeded();
 
   if (!audioContext->destination()) {
     exceptionState.throwDOMException(
@@ -123,7 +124,6 @@
   offlineContextLengthHistogram.count(numberOfFrames);
   offlineContextSampleRateHistogram.count(sampleRate);
 
-  audioContext->suspendIfNeeded();
   return audioContext;
 }
 
diff --git a/third_party/WebKit/Source/platform/audio/AudioDestinationConsumer.h b/third_party/WebKit/Source/platform/audio/AudioDestinationConsumer.h
index 99c2b5f..849fef2 100644
--- a/third_party/WebKit/Source/platform/audio/AudioDestinationConsumer.h
+++ b/third_party/WebKit/Source/platform/audio/AudioDestinationConsumer.h
@@ -31,20 +31,17 @@
 #ifndef AudioDestinationConsumer_h
 #define AudioDestinationConsumer_h
 
+#include <memory>
 #include "platform/PlatformExport.h"
-#include "platform/heap/Handle.h"
 
 namespace blink {
 
 class AudioBus;
 
-class PLATFORM_EXPORT AudioDestinationConsumer
-    : public GarbageCollected<AudioDestinationConsumer> {
+class PLATFORM_EXPORT AudioDestinationConsumer {
  public:
   virtual void setFormat(size_t numberOfChannels, float sampleRate) = 0;
   virtual void consumeAudio(AudioBus*, size_t numberOfFrames) = 0;
-
-  DEFINE_INLINE_VIRTUAL_TRACE() {}
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp b/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
index 56e5e5a70..5e19c39 100644
--- a/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
+++ b/third_party/WebKit/Source/platform/exported/WebMediaStreamSource.cpp
@@ -148,6 +148,8 @@
 }
 
 class ConsumerWrapper final : public AudioDestinationConsumer {
+  USING_FAST_MALLOC(ConsumerWrapper);
+
  public:
   static ConsumerWrapper* create(WebAudioDestinationConsumer* consumer) {
     return new ConsumerWrapper(consumer);
@@ -196,12 +198,10 @@
   ASSERT(isMainThread());
   ASSERT(!m_private.isNull() && consumer);
 
-  const HeapHashSet<Member<AudioDestinationConsumer>>& consumers =
+  const HashSet<AudioDestinationConsumer*>& consumers =
       m_private->audioConsumers();
-  for (HeapHashSet<Member<AudioDestinationConsumer>>::const_iterator it =
-           consumers.begin();
-       it != consumers.end(); ++it) {
-    ConsumerWrapper* wrapper = static_cast<ConsumerWrapper*>(it->get());
+  for (AudioDestinationConsumer* it : consumers) {
+    ConsumerWrapper* wrapper = static_cast<ConsumerWrapper*>(it);
     if (wrapper->consumer() == consumer) {
       m_private->removeAudioConsumer(wrapper);
       return true;
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
index fe6021b24..ca12e1c 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.cpp
@@ -85,8 +85,7 @@
     AudioDestinationConsumer* consumer) {
   ASSERT(m_requiresConsumer);
   MutexLocker locker(m_audioConsumersLock);
-  HeapHashSet<Member<AudioDestinationConsumer>>::iterator it =
-      m_audioConsumers.find(consumer);
+  auto it = m_audioConsumers.find(consumer);
   if (it == m_audioConsumers.end())
     return false;
   m_audioConsumers.erase(it);
@@ -101,10 +100,8 @@
                                        float sampleRate) {
   ASSERT(m_requiresConsumer);
   MutexLocker locker(m_audioConsumersLock);
-  for (HeapHashSet<Member<AudioDestinationConsumer>>::iterator it =
-           m_audioConsumers.begin();
-       it != m_audioConsumers.end(); ++it)
-    (*it)->setFormat(numberOfChannels, sampleRate);
+  for (AudioDestinationConsumer* consumer : m_audioConsumers)
+    consumer->setFormat(numberOfChannels, sampleRate);
 }
 
 void MediaStreamSource::consumeAudio(AudioBus* bus, size_t numberOfFrames) {
@@ -113,15 +110,12 @@
   // Prevent GCs from going ahead while this iteration runs, attempting to
   // pinpoint crbug.com/682945 failures.
   ThreadState::MainThreadGCForbiddenScope scope;
-  for (HeapHashSet<Member<AudioDestinationConsumer>>::iterator it =
-           m_audioConsumers.begin();
-       it != m_audioConsumers.end(); ++it)
-    (*it)->consumeAudio(bus, numberOfFrames);
+  for (AudioDestinationConsumer* consumer : m_audioConsumers)
+    consumer->consumeAudio(bus, numberOfFrames);
 }
 
 DEFINE_TRACE(MediaStreamSource) {
   visitor->trace(m_observers);
-  visitor->trace(m_audioConsumers);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
index d05fc45e6..e41f74b 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamSource.h
@@ -102,7 +102,7 @@
   bool requiresAudioConsumer() const { return m_requiresConsumer; }
   void addAudioConsumer(AudioDestinationConsumer*);
   bool removeAudioConsumer(AudioDestinationConsumer*);
-  const HeapHashSet<Member<AudioDestinationConsumer>>& audioConsumers() {
+  const HashSet<AudioDestinationConsumer*>& audioConsumers() {
     return m_audioConsumers;
   }
 
@@ -126,7 +126,7 @@
   bool m_requiresConsumer;
   HeapHashSet<WeakMember<Observer>> m_observers;
   Mutex m_audioConsumersLock;
-  HeapHashSet<Member<AudioDestinationConsumer>> m_audioConsumers;
+  HashSet<AudioDestinationConsumer*> m_audioConsumers;
   std::unique_ptr<ExtraData> m_extraData;
   WebMediaConstraints m_constraints;
 };
diff --git a/third_party/WebKit/Source/wtf/Assertions.cpp b/third_party/WebKit/Source/platform/wtf/Assertions.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/Assertions.cpp
rename to third_party/WebKit/Source/platform/wtf/Assertions.cpp
index 26ba322..ddcd361a 100644
--- a/third_party/WebKit/Source/wtf/Assertions.cpp
+++ b/third_party/WebKit/Source/platform/wtf/Assertions.cpp
@@ -32,12 +32,12 @@
 // we need to place this directive before any data or functions are defined.
 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
 
-#include "wtf/Assertions.h"
+#include "platform/wtf/Assertions.h"
 
-#include "wtf/Compiler.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/ThreadSpecific.h"
-#include "wtf/Threading.h"
+#include "platform/wtf/Compiler.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/ThreadSpecific.h"
+#include "platform/wtf/Threading.h"
 #include <memory>
 #include <stdarg.h>
 #include <stdio.h>
diff --git a/third_party/WebKit/Source/platform/wtf/BUILD.gn b/third_party/WebKit/Source/platform/wtf/BUILD.gn
index 10ef3960..0aaac6d 100644
--- a/third_party/WebKit/Source/platform/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/platform/wtf/BUILD.gn
@@ -64,6 +64,7 @@
     "AddressSanitizer.h",
     "Alignment.h",
     "Allocator.h",
+    "Assertions.cpp",
     "Assertions.h",
     "Atomics.h",
     "AutoReset.h",
@@ -81,21 +82,38 @@
     "DynamicAnnotations.cpp",
     "DynamicAnnotations.h",
     "Forward.h",
+    "Functional.h",
     "GetPtr.h",
+    "HashTableDeletedValueType.h",
+    "InstanceCounter.h",
     "LeakAnnotations.h",
+    "Locker.h",
     "NonCopyingSort.h",
     "Noncopyable.h",
     "NotFound.h",
     "Optional.h",
+    "PassRefPtr.h",
+    "PtrUtil.h",
+    "RefCounted.h",
+    "RefPtr.h",
     "SizeAssertions.h",
     "SpinLock.h",
+    "StackUtil.h",
     "StaticConstructors.h",
+    "StdLibExtras.h",
     "StringExtras.h",
+    "ThreadRestrictionVerifier.h",
+    "ThreadSafeRefCounted.h",
+    "ThreadSpecific.h",
+    "Threading.h",
+    "ThreadingPrimitives.h",
     "Time.h",
+    "TreeNode.h",
     "TriState.h",
     "TypeTraits.h",
     "WTF.h",
     "WTFExport.h",
+    "WeakPtr.h",
     "allocator/PartitionAllocator.cpp",
     "allocator/PartitionAllocator.h",
     "allocator/Partitions.cpp",
diff --git a/third_party/WebKit/Source/platform/wtf/Functional.h b/third_party/WebKit/Source/platform/wtf/Functional.h
new file mode 100644
index 0000000..a6f1cb3
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/Functional.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2011 Apple 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:
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
+ */
+
+#ifndef WTF_Functional_h
+#define WTF_Functional_h
+
+#include "base/bind.h"
+#include "base/threading/thread_checker.h"
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/PtrUtil.h"
+#include "platform/wtf/RefPtr.h"
+#include "platform/wtf/ThreadSafeRefCounted.h"
+#include "platform/wtf/TypeTraits.h"
+#include <utility>
+
+namespace blink {
+template <typename T>
+class Member;
+template <typename T>
+class WeakMember;
+}
+
+namespace WTF {
+
+// Functional.h provides a very simple way to bind a function pointer and
+// arguments together into a function object that can be stored, copied and
+// invoked, similar to boost::bind and std::bind in C++11.
+
+// Thread Safety:
+//
+// WTF::bind() and WTF::Closure should be used for same-thread closures
+// only, i.e. the closures must be created, executed and destructed on
+// the same thread.
+// Use crossThreadBind() and CrossThreadClosure if the function/task is called
+// or destructed on a (potentially) different thread from the current thread.
+
+// WTF::bind() and move semantics
+// ==============================
+//
+// For unbound parameters (arguments supplied later on the bound functor
+// directly), there are two ways to pass movable arguments:
+//
+//     1) Pass by rvalue reference.
+//
+//            void yourFunction(Argument&& argument) { ... }
+//            std::unique_ptr<Function<void(Argument&&)>> functor =
+//                bind<Argument&&>(yourFunction);
+//
+//     2) Pass by value.
+//
+//            void yourFunction(Argument argument) { ... }
+//            std::unique_ptr<Function<void(Argument)>> functor =
+//                bind<Argument>(yourFunction);
+//
+// Note that with the latter there will be *two* move constructions happening,
+// because there needs to be at least one intermediary function call taking an
+// argument of type "Argument" (i.e. passed by value). The former case does not
+// require any move constructions inbetween.
+//
+// For bound parameters (arguments supplied on the creation of a functor), you
+// can move your argument into the internal storage of the functor by supplying
+// an rvalue to that argument (this is done in wrap() of ParamStorageTraits).
+// However, to make the functor be able to get called multiple times, the
+// stored object does not get moved out automatically when the underlying
+// function is actually invoked. If you want to make an argument "auto-passed",
+// you can do so by wrapping your bound argument with WTF::passed() function, as
+// shown below:
+//
+//     void yourFunction(Argument argument)
+//     {
+//         // |argument| is passed from the internal storage of functor.
+//         ...
+//     }
+//
+//     ...
+//     std::unique_ptr<Function<void()>> functor = bind(yourFunction,
+//         WTF::passed(Argument()));
+//     ...
+//     (*functor)();
+//
+// The underlying function must receive the argument wrapped by WTF::passed() by
+// rvalue reference or by value.
+//
+// Obviously, if you create a functor this way, you shouldn't call the functor
+// twice or more; after the second call, the passed argument may be invalid.
+
+enum FunctionThreadAffinity { CrossThreadAffinity, SameThreadAffinity };
+
+template <typename T>
+class PassedWrapper final {
+ public:
+  explicit PassedWrapper(T&& scoper) : m_scoper(std::move(scoper)) {}
+  PassedWrapper(PassedWrapper&& other) : m_scoper(std::move(other.m_scoper)) {}
+  T moveOut() const { return std::move(m_scoper); }
+
+ private:
+  mutable T m_scoper;
+};
+
+template <typename T>
+PassedWrapper<T> passed(T&& value) {
+  static_assert(
+      !std::is_reference<T>::value,
+      "You must pass an rvalue to WTF::passed() so it can be moved. Add "
+      "std::move() if necessary.");
+  static_assert(!std::is_const<T>::value,
+                "|value| must not be const so it can be moved.");
+  return PassedWrapper<T>(std::move(value));
+}
+
+template <typename T, FunctionThreadAffinity threadAffinity>
+class UnretainedWrapper final {
+ public:
+  explicit UnretainedWrapper(T* ptr) : m_ptr(ptr) {}
+  T* value() const { return m_ptr; }
+
+ private:
+  T* m_ptr;
+};
+
+template <typename T>
+UnretainedWrapper<T, SameThreadAffinity> unretained(T* value) {
+  static_assert(!WTF::IsGarbageCollectedType<T>::value,
+                "WTF::unretained() + GCed type is forbidden");
+  return UnretainedWrapper<T, SameThreadAffinity>(value);
+}
+
+template <typename T>
+UnretainedWrapper<T, CrossThreadAffinity> crossThreadUnretained(T* value) {
+  static_assert(!WTF::IsGarbageCollectedType<T>::value,
+                "crossThreadUnretained() + GCed type is forbidden");
+  return UnretainedWrapper<T, CrossThreadAffinity>(value);
+}
+
+template <typename T>
+struct ParamStorageTraits {
+  typedef T StorageType;
+
+  static_assert(!std::is_pointer<T>::value,
+                "Raw pointers are not allowed to bind into WTF::Function. Wrap "
+                "it with either wrapPersistent, wrapWeakPersistent, "
+                "wrapCrossThreadPersistent, wrapCrossThreadWeakPersistent, "
+                "RefPtr or unretained.");
+  static_assert(!IsSubclassOfTemplate<T, blink::Member>::value &&
+                    !IsSubclassOfTemplate<T, blink::WeakMember>::value,
+                "Member and WeakMember are not allowed to bind into "
+                "WTF::Function. Wrap it with either wrapPersistent, "
+                "wrapWeakPersistent, wrapCrossThreadPersistent or "
+                "wrapCrossThreadWeakPersistent.");
+};
+
+template <typename T>
+struct ParamStorageTraits<PassRefPtr<T>> {
+  typedef RefPtr<T> StorageType;
+};
+
+template <typename T>
+struct ParamStorageTraits<RefPtr<T>> {
+  typedef RefPtr<T> StorageType;
+};
+
+template <typename>
+class RetainPtr;
+
+template <typename T>
+struct ParamStorageTraits<RetainPtr<T>> {
+  typedef RetainPtr<T> StorageType;
+};
+
+template <typename T>
+struct ParamStorageTraits<PassedWrapper<T>> {
+  typedef PassedWrapper<T> StorageType;
+};
+
+template <typename T, FunctionThreadAffinity threadAffinity>
+struct ParamStorageTraits<UnretainedWrapper<T, threadAffinity>> {
+  typedef UnretainedWrapper<T, threadAffinity> StorageType;
+};
+
+template <typename Signature,
+          FunctionThreadAffinity threadAffinity = SameThreadAffinity>
+class Function;
+
+template <typename R, typename... Args, FunctionThreadAffinity threadAffinity>
+class Function<R(Args...), threadAffinity> {
+  USING_FAST_MALLOC(Function);
+  WTF_MAKE_NONCOPYABLE(Function);
+
+ public:
+  Function(base::Callback<R(Args...)> callback)
+      : m_callback(std::move(callback)) {}
+
+  ~Function() { DCHECK(m_threadChecker.CalledOnValidThread()); }
+
+  R operator()(Args... args) {
+    DCHECK(m_threadChecker.CalledOnValidThread());
+    return m_callback.Run(std::forward<Args>(args)...);
+  }
+
+  bool isCancelled() const { return m_callback.IsCancelled(); }
+
+  friend base::Callback<R(Args...)> convertToBaseCallback(
+      std::unique_ptr<Function> function) {
+    if (function)
+      return std::move(function->m_callback);
+    return base::Callback<R(Args...)>();
+  }
+
+ private:
+  using MaybeThreadChecker =
+      typename std::conditional<threadAffinity == SameThreadAffinity,
+                                base::ThreadChecker,
+                                base::ThreadCheckerDoNothing>::type;
+  MaybeThreadChecker m_threadChecker;
+  base::Callback<R(Args...)> m_callback;
+};
+
+template <FunctionThreadAffinity threadAffinity,
+          typename FunctionType,
+          typename... BoundParameters>
+std::unique_ptr<
+    Function<base::MakeUnboundRunType<FunctionType, BoundParameters...>,
+             threadAffinity>>
+bindInternal(FunctionType function, BoundParameters&&... boundParameters) {
+  using UnboundRunType =
+      base::MakeUnboundRunType<FunctionType, BoundParameters...>;
+  return WTF::wrapUnique(new Function<UnboundRunType,
+                                      threadAffinity>(base::Bind(
+      function,
+      typename ParamStorageTraits<typename std::decay<BoundParameters>::type>::
+          StorageType(std::forward<BoundParameters>(boundParameters))...)));
+}
+
+template <typename FunctionType, typename... BoundParameters>
+std::unique_ptr<
+    Function<base::MakeUnboundRunType<FunctionType, BoundParameters...>,
+             SameThreadAffinity>>
+bind(FunctionType function, BoundParameters&&... boundParameters) {
+  return bindInternal<SameThreadAffinity>(
+      function, std::forward<BoundParameters>(boundParameters)...);
+}
+
+typedef Function<void(), SameThreadAffinity> Closure;
+typedef Function<void(), CrossThreadAffinity> CrossThreadClosure;
+
+}  // namespace WTF
+
+namespace base {
+
+template <typename T>
+struct BindUnwrapTraits<WTF::RefPtr<T>> {
+  static T* Unwrap(const WTF::RefPtr<T>& wrapped) { return wrapped.get(); }
+};
+
+template <typename T>
+struct BindUnwrapTraits<WTF::PassedWrapper<T>> {
+  static T Unwrap(const WTF::PassedWrapper<T>& wrapped) {
+    return wrapped.moveOut();
+  }
+};
+
+template <typename T, WTF::FunctionThreadAffinity threadAffinity>
+struct BindUnwrapTraits<WTF::UnretainedWrapper<T, threadAffinity>> {
+  static T* Unwrap(const WTF::UnretainedWrapper<T, threadAffinity>& wrapped) {
+    return wrapped.value();
+  }
+};
+
+}  // namespace base
+
+using WTF::crossThreadUnretained;
+
+using WTF::Function;
+using WTF::CrossThreadClosure;
+
+#endif  // WTF_Functional_h
diff --git a/third_party/WebKit/Source/platform/wtf/HashTableDeletedValueType.h b/third_party/WebKit/Source/platform/wtf/HashTableDeletedValueType.h
new file mode 100644
index 0000000..06b5e5e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/HashTableDeletedValueType.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef HashTableDeletedValueType_h
+#define HashTableDeletedValueType_h
+
+namespace WTF {
+
+enum HashTableDeletedValueType { HashTableDeletedValue };
+
+}  // namespace WTF
+
+#endif  // HashTableDeletedValueType_h
diff --git a/third_party/WebKit/Source/platform/wtf/InstanceCounter.h b/third_party/WebKit/Source/platform/wtf/InstanceCounter.h
new file mode 100644
index 0000000..35db9a1
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/InstanceCounter.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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:
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef InstanceCounter_h
+#define InstanceCounter_h
+
+#include "platform/wtf/TypeTraits.h"
+#include "platform/wtf/WTFExport.h"
+#include "platform/wtf/build_config.h"
+
+namespace WTF {
+
+class String;
+WTF_EXPORT String dumpRefCountedInstanceCounts();
+
+#if ENABLE(INSTANCE_COUNTER)
+WTF_EXPORT void incrementInstanceCount(const char* stringWithTypeName,
+                                       void* ptr);
+WTF_EXPORT void decrementInstanceCount(const char* stringWithTypeName,
+                                       void* ptr);
+
+WTF_EXPORT String extractTypeNameFromFunctionName(const char* funcName);
+
+template <typename T>
+inline void incrementInstanceCount(T* p) {
+  incrementInstanceCount(getStringWithTypeName<T>(), p);
+}
+
+template <typename T>
+inline void decrementInstanceCount(T* p) {
+  decrementInstanceCount(getStringWithTypeName<T>(), p);
+}
+
+#endif  // ENABLE(INSTANCE_COUNTER)
+
+}  // namespace WTF
+
+#endif
diff --git a/third_party/WebKit/Source/platform/wtf/Locker.h b/third_party/WebKit/Source/platform/wtf/Locker.h
new file mode 100644
index 0000000..4d29807e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/Locker.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ *
+ * 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.
+ */
+#ifndef Locker_h
+#define Locker_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Noncopyable.h"
+
+namespace WTF {
+
+template <typename T>
+class Locker final {
+  STACK_ALLOCATED();
+  WTF_MAKE_NONCOPYABLE(Locker);
+
+ public:
+  Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
+  ~Locker() { m_lockable.unlock(); }
+
+ private:
+  T& m_lockable;
+};
+
+}  // namespace WTF
+
+using WTF::Locker;
+
+#endif
diff --git a/third_party/WebKit/Source/platform/wtf/PassRefPtr.h b/third_party/WebKit/Source/platform/wtf/PassRefPtr.h
new file mode 100644
index 0000000..68a421e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/PassRefPtr.h
@@ -0,0 +1,224 @@
+/*
+ *  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc.
+ *  All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+// PassRefPtr will soon be deleted.
+// New code should instead pass ownership of the contents of a RefPtr using
+// std::move().
+
+#ifndef WTF_PassRefPtr_h
+#define WTF_PassRefPtr_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/Compiler.h"
+#include "platform/wtf/TypeTraits.h"
+
+namespace WTF {
+
+template <typename T>
+class RefPtr;
+template <typename T>
+class PassRefPtr;
+template <typename T>
+PassRefPtr<T> adoptRef(T*);
+
+inline void adopted(const void*) {}
+
+// requireAdoption() is not overloaded for WTF::RefCounted, which has a built-in
+// assumption that adoption is required. requireAdoption() is for bootstrapping
+// alternate reference count classes that are compatible with ReftPtr/PassRefPtr
+// but cannot have adoption checks enabled by default, such as skia's
+// SkRefCnt. The purpose of requireAdoption() is to enable adoption checks only
+// once it is known that the object will be used with RefPtr/PassRefPtr.
+inline void requireAdoption(const void*) {}
+
+template <typename T>
+ALWAYS_INLINE void refIfNotNull(T* ptr) {
+  if (LIKELY(ptr != 0)) {
+    requireAdoption(ptr);
+    ptr->ref();
+  }
+}
+
+template <typename T>
+ALWAYS_INLINE void derefIfNotNull(T* ptr) {
+  if (LIKELY(ptr != 0))
+    ptr->deref();
+}
+
+template <typename T>
+class PassRefPtr {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
+ public:
+  PassRefPtr() : m_ptr(nullptr) {}
+  PassRefPtr(std::nullptr_t) : m_ptr(nullptr) {}
+  PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
+  PassRefPtr(PassRefPtr&& o) : m_ptr(o.leakRef()) {}
+  template <typename U>
+  PassRefPtr(const PassRefPtr<U>& o, EnsurePtrConvertibleArgDecl(U, T))
+      : m_ptr(o.leakRef()) {}
+
+  ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull(m_ptr); }
+
+  template <typename U>
+  PassRefPtr(const RefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
+  template <typename U>
+  PassRefPtr(RefPtr<U>&&, EnsurePtrConvertibleArgDecl(U, T));
+
+  T* get() const { return m_ptr; }
+
+  WARN_UNUSED_RESULT T* leakRef() const;
+
+  T& operator*() const { return *m_ptr; }
+  T* operator->() const { return m_ptr; }
+
+  bool operator!() const { return !m_ptr; }
+  explicit operator bool() const { return m_ptr != nullptr; }
+
+  friend PassRefPtr adoptRef<T>(T*);
+
+ private:
+  enum AdoptRefTag { AdoptRef };
+  PassRefPtr(T* ptr, AdoptRefTag) : m_ptr(ptr) {}
+
+  PassRefPtr& operator=(const PassRefPtr&) {
+    static_assert(!sizeof(T*), "PassRefPtr should never be assigned to");
+    return *this;
+  }
+
+  mutable T* m_ptr;
+};
+
+template <typename T>
+PassRefPtr<T> wrapPassRefPtr(T* ptr) {
+  return PassRefPtr<T>(ptr);
+}
+
+template <typename T>
+template <typename U>
+inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o,
+                                 EnsurePtrConvertibleArgDefn(U, T))
+    : m_ptr(o.get()) {
+  T* ptr = m_ptr;
+  refIfNotNull(ptr);
+}
+
+template <typename T>
+template <typename U>
+inline PassRefPtr<T>::PassRefPtr(RefPtr<U>&& o,
+                                 EnsurePtrConvertibleArgDefn(U, T))
+    : m_ptr(o.leakRef()) {}
+
+template <typename T>
+inline T* PassRefPtr<T>::leakRef() const {
+  T* ptr = m_ptr;
+  m_ptr = nullptr;
+  return ptr;
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.get() == b.get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b) {
+  return a.get() == b.get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.get() == b.get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const PassRefPtr<T>& a, U* b) {
+  return a.get() == b;
+}
+
+template <typename T, typename U>
+inline bool operator==(T* a, const PassRefPtr<U>& b) {
+  return a == b.get();
+}
+
+template <typename T>
+inline bool operator==(const PassRefPtr<T>& a, std::nullptr_t) {
+  return !a.get();
+}
+
+template <typename T>
+inline bool operator==(std::nullptr_t, const PassRefPtr<T>& b) {
+  return !b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.get() != b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b) {
+  return a.get() != b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b) {
+  return a.get() != b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const PassRefPtr<T>& a, U* b) {
+  return a.get() != b;
+}
+
+template <typename T, typename U>
+inline bool operator!=(T* a, const PassRefPtr<U>& b) {
+  return a != b.get();
+}
+
+template <typename T>
+inline bool operator!=(const PassRefPtr<T>& a, std::nullptr_t) {
+  return a.get();
+}
+
+template <typename T>
+inline bool operator!=(std::nullptr_t, const PassRefPtr<T>& b) {
+  return b.get();
+}
+
+template <typename T>
+PassRefPtr<T> adoptRef(T* p) {
+  adopted(p);
+  return PassRefPtr<T>(p, PassRefPtr<T>::AdoptRef);
+}
+
+template <typename T>
+inline T* getPtr(const PassRefPtr<T>& p) {
+  return p.get();
+}
+
+}  // namespace WTF
+
+using WTF::PassRefPtr;
+using WTF::adoptRef;
+
+#endif  // WTF_PassRefPtr_h
diff --git a/third_party/WebKit/Source/platform/wtf/PtrUtil.h b/third_party/WebKit/Source/platform/wtf/PtrUtil.h
new file mode 100644
index 0000000..57ba0a8
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/PtrUtil.h
@@ -0,0 +1,53 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef PtrUtil_h
+#define PtrUtil_h
+
+#include "base/memory/ptr_util.h"
+#include "platform/wtf/TypeTraits.h"
+
+#include <memory>
+
+namespace WTF {
+
+template <typename T>
+std::unique_ptr<T> wrapUnique(T* ptr) {
+  static_assert(
+      !WTF::IsGarbageCollectedType<T>::value,
+      "Garbage collected types should not be stored in std::unique_ptr!");
+  return std::unique_ptr<T>(ptr);
+}
+
+template <typename T>
+std::unique_ptr<T[]> wrapArrayUnique(T* ptr) {
+  static_assert(
+      !WTF::IsGarbageCollectedType<T>::value,
+      "Garbage collected types should not be stored in std::unique_ptr!");
+  return std::unique_ptr<T[]>(ptr);
+}
+
+// WTF::makeUnique is base::MakeUnique. See base/ptr_util.h for documentation.
+template <typename T, typename... Args>
+auto makeUnique(Args&&... args)
+    -> decltype(base::MakeUnique<T>(std::forward<Args>(args)...)) {
+  static_assert(
+      !WTF::IsGarbageCollectedType<T>::value,
+      "Garbage collected types should not be stored in std::unique_ptr!");
+  return base::MakeUnique<T>(std::forward<Args>(args)...);
+}
+
+template <typename T>
+auto makeUnique(size_t size) -> decltype(base::MakeUnique<T>(size)) {
+  static_assert(
+      !WTF::IsGarbageCollectedType<T>::value,
+      "Garbage collected types should not be stored in std::unique_ptr!");
+  return base::MakeUnique<T>(size);
+}
+
+}  // namespace WTF
+
+using WTF::wrapArrayUnique;
+
+#endif  // PtrUtil_h
diff --git a/third_party/WebKit/Source/platform/wtf/RefCounted.h b/third_party/WebKit/Source/platform/wtf/RefCounted.h
new file mode 100644
index 0000000..357e294
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/RefCounted.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef RefCounted_h
+#define RefCounted_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/Noncopyable.h"
+#include "platform/wtf/WTFExport.h"
+
+#if ENABLE(INSTANCE_COUNTER)
+#include "platform/wtf/InstanceCounter.h"
+#endif
+
+#if DCHECK_IS_ON()
+#define CHECK_REF_COUNTED_LIFECYCLE 1
+#include "platform/wtf/ThreadRestrictionVerifier.h"
+#else
+#define CHECK_REF_COUNTED_LIFECYCLE 0
+#endif
+
+namespace WTF {
+
+// This base class holds the non-template methods and attributes.
+// The RefCounted class inherits from it reducing the template bloat
+// generated by the compiler (technique called template hoisting).
+class WTF_EXPORT RefCountedBase {
+ public:
+  void ref() const {
+#if CHECK_REF_COUNTED_LIFECYCLE
+    SECURITY_DCHECK(m_verifier.onRef(m_refCount));
+    DCHECK(!m_adoptionIsRequired);
+#endif
+    SECURITY_DCHECK(!m_deletionHasBegun);
+    ++m_refCount;
+  }
+
+  bool hasOneRef() const {
+    SECURITY_DCHECK(!m_deletionHasBegun);
+#if CHECK_REF_COUNTED_LIFECYCLE
+    SECURITY_DCHECK(m_verifier.isSafeToUse());
+#endif
+    return m_refCount == 1;
+  }
+
+  int refCount() const {
+#if CHECK_REF_COUNTED_LIFECYCLE
+    SECURITY_DCHECK(m_verifier.isSafeToUse());
+#endif
+    return m_refCount;
+  }
+
+ protected:
+  RefCountedBase()
+      : m_refCount(1)
+#if ENABLE(SECURITY_ASSERT)
+        ,
+        m_deletionHasBegun(false)
+#endif
+#if CHECK_REF_COUNTED_LIFECYCLE
+        ,
+        m_adoptionIsRequired(true)
+#endif
+  {
+  }
+
+  ~RefCountedBase() {
+    SECURITY_DCHECK(m_deletionHasBegun);
+#if CHECK_REF_COUNTED_LIFECYCLE
+    DCHECK(!m_adoptionIsRequired);
+#endif
+  }
+
+  // Returns whether the pointer should be freed or not.
+  bool derefBase() const {
+    SECURITY_DCHECK(!m_deletionHasBegun);
+#if CHECK_REF_COUNTED_LIFECYCLE
+    SECURITY_DCHECK(m_verifier.onDeref(m_refCount));
+    DCHECK(!m_adoptionIsRequired);
+#endif
+
+    DCHECK_GT(m_refCount, 0);
+    --m_refCount;
+    if (!m_refCount) {
+#if ENABLE(SECURITY_ASSERT)
+      m_deletionHasBegun = true;
+#endif
+      return true;
+    }
+
+    return false;
+  }
+
+#if CHECK_REF_COUNTED_LIFECYCLE
+  bool deletionHasBegun() const { return m_deletionHasBegun; }
+#endif
+
+ private:
+#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
+  friend void adopted(RefCountedBase*);
+#endif
+
+  mutable int m_refCount;
+#if ENABLE(SECURITY_ASSERT)
+  mutable bool m_deletionHasBegun;
+#endif
+#if CHECK_REF_COUNTED_LIFECYCLE
+  mutable bool m_adoptionIsRequired;
+  mutable ThreadRestrictionVerifier m_verifier;
+#endif
+};
+
+#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
+inline void adopted(RefCountedBase* object) {
+  if (!object)
+    return;
+  SECURITY_DCHECK(!object->m_deletionHasBegun);
+#if CHECK_REF_COUNTED_LIFECYCLE
+  object->m_adoptionIsRequired = false;
+#endif
+}
+#endif
+
+template <typename T>
+class RefCounted : public RefCountedBase {
+  WTF_MAKE_NONCOPYABLE(RefCounted);
+
+  // Put |T| in here instead of |RefCounted| so the heap profiler reports |T|
+  // instead of |RefCounted<T>|. This does not affect overloading of operator
+  // new.
+  USING_FAST_MALLOC(T);
+
+ public:
+  void deref() const {
+    if (derefBase())
+      delete static_cast<const T*>(this);
+  }
+
+ protected:
+#if ENABLE(INSTANCE_COUNTER)
+  RefCounted() { incrementInstanceCount<T>(static_cast<T*>(this)); }
+
+  ~RefCounted() { decrementInstanceCount<T>(static_cast<T*>(this)); }
+#else
+  RefCounted() {}
+#endif
+};
+
+}  // namespace WTF
+
+using WTF::RefCounted;
+
+#endif  // RefCounted_h
diff --git a/third_party/WebKit/Source/platform/wtf/RefPtr.h b/third_party/WebKit/Source/platform/wtf/RefPtr.h
new file mode 100644
index 0000000..0b15fb0
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/RefPtr.h
@@ -0,0 +1,222 @@
+/*
+ *  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc.
+ *  All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Library General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this library; see the file COPYING.LIB.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef WTF_RefPtr_h
+#define WTF_RefPtr_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/HashTableDeletedValueType.h"
+#include "platform/wtf/PassRefPtr.h"
+#include "platform/wtf/allocator/PartitionAllocator.h"
+#include <algorithm>
+#include <utility>
+
+namespace WTF {
+
+template <typename T>
+class PassRefPtr;
+template <typename T>
+class RefPtrValuePeeker;
+
+template <typename T>
+class RefPtr {
+  USING_FAST_MALLOC(RefPtr);
+
+ public:
+  ALWAYS_INLINE RefPtr() : m_ptr(nullptr) {}
+  ALWAYS_INLINE RefPtr(std::nullptr_t) : m_ptr(nullptr) {}
+  ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
+  ALWAYS_INLINE explicit RefPtr(T& ref) : m_ptr(&ref) { m_ptr->ref(); }
+  ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) {
+    refIfNotNull(m_ptr);
+  }
+  template <typename U>
+  RefPtr(const RefPtr<U>& o, EnsurePtrConvertibleArgDecl(U, T))
+      : m_ptr(o.get()) {
+    refIfNotNull(m_ptr);
+  }
+  RefPtr(RefPtr&& o) : m_ptr(o.m_ptr) { o.m_ptr = nullptr; }
+
+  // See comments in PassRefPtr.h for an explanation of why this takes a const
+  // reference.
+  template <typename U>
+  RefPtr(const PassRefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
+
+  // Hash table deleted values, which are only constructed and never copied or
+  // destroyed.
+  RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) {}
+  bool isHashTableDeletedValue() const {
+    return m_ptr == hashTableDeletedValue();
+  }
+
+  ALWAYS_INLINE ~RefPtr() { derefIfNotNull(m_ptr); }
+
+  ALWAYS_INLINE T* get() const { return m_ptr; }
+  T* leakRef() WARN_UNUSED_RESULT;
+  void clear();
+  PassRefPtr<T> release() {
+    PassRefPtr<T> tmp = adoptRef(m_ptr);
+    m_ptr = nullptr;
+    return tmp;
+  }
+
+  T& operator*() const { return *m_ptr; }
+  ALWAYS_INLINE T* operator->() const { return m_ptr; }
+
+  bool operator!() const { return !m_ptr; }
+  explicit operator bool() const { return m_ptr != nullptr; }
+
+  RefPtr& operator=(RefPtr o) {
+    swap(o);
+    return *this;
+  }
+  RefPtr& operator=(std::nullptr_t) {
+    clear();
+    return *this;
+  }
+  // This is required by HashMap<RefPtr>>.
+  template <typename U>
+  RefPtr& operator=(RefPtrValuePeeker<U>);
+
+  void swap(RefPtr&);
+
+  static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
+
+ private:
+  T* m_ptr;
+};
+
+template <typename T>
+template <typename U>
+inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o,
+                         EnsurePtrConvertibleArgDefn(U, T))
+    : m_ptr(o.leakRef()) {}
+
+template <typename T>
+inline T* RefPtr<T>::leakRef() {
+  T* ptr = m_ptr;
+  m_ptr = nullptr;
+  return ptr;
+}
+
+template <typename T>
+inline void RefPtr<T>::clear() {
+  T* ptr = m_ptr;
+  m_ptr = nullptr;
+  derefIfNotNull(ptr);
+}
+
+template <typename T>
+template <typename U>
+inline RefPtr<T>& RefPtr<T>::operator=(RefPtrValuePeeker<U> optr) {
+  RefPtr ptr = static_cast<U*>(optr);
+  swap(ptr);
+  return *this;
+}
+
+template <class T>
+inline void RefPtr<T>::swap(RefPtr& o) {
+  std::swap(m_ptr, o.m_ptr);
+}
+
+template <class T>
+inline void swap(RefPtr<T>& a, RefPtr<T>& b) {
+  a.swap(b);
+}
+
+template <typename T, typename U>
+inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b) {
+  return a.get() == b.get();
+}
+
+template <typename T, typename U>
+inline bool operator==(const RefPtr<T>& a, U* b) {
+  return a.get() == b;
+}
+
+template <typename T, typename U>
+inline bool operator==(T* a, const RefPtr<U>& b) {
+  return a == b.get();
+}
+
+template <typename T>
+inline bool operator==(const RefPtr<T>& a, std::nullptr_t) {
+  return !a.get();
+}
+
+template <typename T>
+inline bool operator==(std::nullptr_t, const RefPtr<T>& b) {
+  return !b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b) {
+  return a.get() != b.get();
+}
+
+template <typename T, typename U>
+inline bool operator!=(const RefPtr<T>& a, U* b) {
+  return a.get() != b;
+}
+
+template <typename T, typename U>
+inline bool operator!=(T* a, const RefPtr<U>& b) {
+  return a != b.get();
+}
+
+template <typename T>
+inline bool operator!=(const RefPtr<T>& a, std::nullptr_t) {
+  return a.get();
+}
+
+template <typename T>
+inline bool operator!=(std::nullptr_t, const RefPtr<T>& b) {
+  return b.get();
+}
+
+template <typename T>
+inline T* getPtr(const RefPtr<T>& p) {
+  return p.get();
+}
+
+template <typename T>
+class RefPtrValuePeeker {
+  DISALLOW_NEW();
+
+ public:
+  ALWAYS_INLINE RefPtrValuePeeker(T* p) : m_ptr(p) {}
+  ALWAYS_INLINE RefPtrValuePeeker(std::nullptr_t) : m_ptr(nullptr) {}
+  template <typename U>
+  RefPtrValuePeeker(const RefPtr<U>& p) : m_ptr(p.get()) {}
+  template <typename U>
+  RefPtrValuePeeker(const PassRefPtr<U>& p) : m_ptr(p.get()) {}
+
+  ALWAYS_INLINE operator T*() const { return m_ptr; }
+
+ private:
+  T* m_ptr;
+};
+
+}  // namespace WTF
+
+using WTF::RefPtr;
+
+#endif  // WTF_RefPtr_h
diff --git a/third_party/WebKit/Source/platform/wtf/StackUtil.h b/third_party/WebKit/Source/platform/wtf/StackUtil.h
new file mode 100644
index 0000000..3bf25de
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/StackUtil.h
@@ -0,0 +1,49 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef StackUtil_h
+#define StackUtil_h
+
+#include "platform/wtf/Compiler.h"
+#include "platform/wtf/WTFExport.h"
+#include "platform/wtf/build_config.h"
+#include <stddef.h>
+#include <stdint.h>
+
+namespace WTF {
+
+WTF_EXPORT size_t getUnderestimatedStackSize();
+WTF_EXPORT void* getStackStart();
+
+namespace internal {
+
+WTF_EXPORT extern uintptr_t s_mainThreadStackStart;
+WTF_EXPORT extern uintptr_t s_mainThreadUnderestimatedStackSize;
+
+WTF_EXPORT void initializeMainThreadStackEstimate();
+
+#if OS(WIN) && COMPILER(MSVC)
+size_t threadStackSize();
+#endif
+
+}  // namespace internal
+
+// Returns true if the function is not called on the main thread. Note carefully
+// that this function may have false positives, i.e. it can return true even if
+// we are on the main thread. If the function returns false, we are certainly
+// on the main thread.
+inline bool mayNotBeMainThread() {
+  uintptr_t dummy;
+  uintptr_t addressDiff =
+      internal::s_mainThreadStackStart - reinterpret_cast<uintptr_t>(&dummy);
+  // This is a fast way to judge if we are in the main thread.
+  // If |&dummy| is within |s_mainThreadUnderestimatedStackSize| byte from
+  // the stack start of the main thread, we judge that we are in
+  // the main thread.
+  return addressDiff >= internal::s_mainThreadUnderestimatedStackSize;
+}
+
+}  // namespace WTF
+
+#endif  // StackUtil_h
diff --git a/third_party/WebKit/Source/platform/wtf/StdLibExtras.h b/third_party/WebKit/Source/platform/wtf/StdLibExtras.h
new file mode 100644
index 0000000..8a99619
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/StdLibExtras.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2008 Apple 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:
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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.
+ */
+
+#ifndef WTF_StdLibExtras_h
+#define WTF_StdLibExtras_h
+
+#include <cstddef>
+#include "base/numerics/safe_conversions.h"
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/CPU.h"
+#include "platform/wtf/LeakAnnotations.h"
+#include "platform/wtf/Noncopyable.h"
+#include "platform/wtf/TypeTraits.h"
+
+#if DCHECK_IS_ON()
+#include "platform/wtf/Threading.h"
+#endif
+
+// Use |DEFINE_STATIC_LOCAL()| to declare and define a static local variable
+// (|static T;|) so that it is leaked and its destructors are not called at
+// exit. T may also be a Blink garbage collected object, in which case it is
+// wrapped up by an off-heap |Persistent<T>| reference to the object, keeping
+// it alive across GCs.
+//
+// A |DEFINE_STATIC_LOCAL()| static should only be used on the thread it was
+// created on.
+//
+#define DEFINE_STATIC_LOCAL(Type, Name, Arguments)            \
+  static WTF::StaticSingleton<Type> s_##Name(                 \
+      new WTF::StaticSingleton<Type>::WrapperType Arguments); \
+  Type& Name = s_##Name.get(false)
+
+// |DEFINE_THREAD_SAFE_STATIC_LOCAL()| is the cross-thread accessible variant
+// of |DEFINE_STATIC_LOCAL()|; use it if the singleton can be accessed by
+// multiple threads.
+//
+// TODO: rename as DEFINE_CROSS_THREAD_STATIC_LOCAL() ?
+#define DEFINE_THREAD_SAFE_STATIC_LOCAL(Type, Name, Initializer) \
+  static WTF::StaticSingleton<Type> s_##Name(Initializer);       \
+  Type& Name = s_##Name.get(true)
+
+namespace blink {
+template <typename T>
+class Persistent;
+
+}  // namespace blink
+
+namespace WTF {
+
+template <typename Type>
+class StaticSingleton final {
+  WTF_MAKE_NONCOPYABLE(StaticSingleton);
+
+ public:
+  template <typename T,
+            bool = WTF::IsGarbageCollectedType<T>::value &&
+                   !WTF::IsPersistentReferenceType<T>::value>
+  struct Wrapper {
+    using type = T;
+
+    static T& unwrap(T* singleton) { return *singleton; }
+  };
+
+  template <typename T>
+  struct Wrapper<T, true> {
+    using type = blink::Persistent<T>;
+
+    static T& unwrap(blink::Persistent<T>* singleton) {
+      DCHECK(singleton);
+      // If this assert triggers, you're supplying an empty ("()") 'Arguments'
+      // argument to DEFINE_STATIC_LOCAL() - it must be the heap object you wish
+      // to create as a static singleton and wrapped up with a Persistent
+      // reference.
+      DCHECK(*singleton);
+      return **singleton;
+    }
+  };
+
+  using WrapperType = typename Wrapper<Type>::type;
+
+  // To cooperate with leak detection(LSan) for Blink garbage collected objects,
+  // the objects owned by persistent local statics will in some cases have to be
+  // finalized prior to leak checking. This only applies to static references to
+  // Blink heap objects and what they transitively hold on to. Hence the
+  // LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy
+  // details.
+
+  explicit StaticSingleton(WrapperType* instance)
+      : m_instance(LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance))
+#if DCHECK_IS_ON()
+        ,
+        m_safelyInitialized(WTF::isBeforeThreadCreated()),
+        m_thread(WTF::internal::currentThreadSyscall())
+#endif
+  {
+  }
+
+  Type& get(bool allowCrossThreadUse) const {
+#if DCHECK_IS_ON()
+    DCHECK(isNotRacy(allowCrossThreadUse));
+#endif
+    ALLOW_UNUSED_LOCAL(allowCrossThreadUse);
+    return Wrapper<Type>::unwrap(m_instance);
+  }
+
+  operator Type&() { return get(); }
+
+ private:
+#if DCHECK_IS_ON()
+
+  bool isNotRacy(bool allowCrossThreadUse) const {
+    // Make sure that singleton is safely initialized, or
+    // keeps being called on the same thread if cross-thread
+    // use is not permitted.
+    return allowCrossThreadUse || m_safelyInitialized ||
+           m_thread == WTF::internal::currentThreadSyscall();
+  }
+#endif
+
+  WrapperType* m_instance;
+#if DCHECK_IS_ON()
+  bool m_safelyInitialized;
+  ThreadIdentifier m_thread;
+#endif
+};
+
+}  // namespace WTF
+
+// Use this to declare and define a static local pointer to a ref-counted object
+// so that it is leaked so that the object's destructors are not called at
+// exit.  This macro should be used with ref-counted objects rather than
+// DEFINE_STATIC_LOCAL macro, as this macro does not lead to an extra memory
+// allocation.
+#define DEFINE_STATIC_REF(type, name, arguments) \
+  static type* name = PassRefPtr<type>(arguments).leakRef();
+
+/*
+ * The reinterpret_cast<Type1*>([pointer to Type2]) expressions - where
+ * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC:
+ * increases required alignment of target type.
+ *
+ * An implicit or an extra static_cast<void*> bypasses the warning.
+ * For more info see the following bugzilla entries:
+ * - https://bugs.webkit.org/show_bug.cgi?id=38045
+ * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976
+ */
+#if CPU(ARM) && COMPILER(GCC)
+template <typename Type>
+bool isPointerTypeAlignmentOkay(Type* ptr) {
+  return !(reinterpret_cast<intptr_t>(ptr) % __alignof__(Type));
+}
+
+template <typename TypePtr>
+TypePtr reinterpret_cast_ptr(void* ptr) {
+  DCHECK(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
+  return reinterpret_cast<TypePtr>(ptr);
+}
+
+template <typename TypePtr>
+TypePtr reinterpret_cast_ptr(const void* ptr) {
+  DCHECK(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
+  return reinterpret_cast<TypePtr>(ptr);
+}
+#else
+template <typename Type>
+bool isPointerTypeAlignmentOkay(Type*) {
+  return true;
+}
+#define reinterpret_cast_ptr reinterpret_cast
+#endif
+
+namespace WTF {
+
+/*
+ * C++'s idea of a reinterpret_cast lacks sufficient cojones.
+ */
+template <typename TO, typename FROM>
+inline TO bitwiseCast(FROM from) {
+  static_assert(sizeof(TO) == sizeof(FROM),
+                "WTF::bitwiseCast sizeof casted types should be equal");
+  union {
+    FROM from;
+    TO to;
+  } u;
+  u.from = from;
+  return u.to;
+}
+
+template <typename To, typename From>
+inline To safeCast(From value) {
+  return base::checked_cast<To>(value);
+}
+
+// Use the following macros to prevent errors caused by accidental
+// implicit casting of function arguments.  For example, this can
+// be used to prevent overflows from non-promoting conversions.
+//
+// Example:
+//
+// HAS_STRICTLY_TYPED_ARG
+// void sendData(void* data, STRICTLY_TYPED_ARG(size))
+// {
+//    ALLOW_NUMERIC_ARG_TYPES_PROMOTABLE_TO(size_t);
+//    ...
+// }
+//
+// The previous example will prevent callers from passing, for example, an
+// 'int'. On a 32-bit build, it will prevent use of an 'unsigned long long'.
+#define HAS_STRICTLY_TYPED_ARG template <typename ActualArgType>
+#define STRICTLY_TYPED_ARG(argName) ActualArgType argName
+#define STRICT_ARG_TYPE(ExpectedArgType)                                     \
+  static_assert(std::is_same<ActualArgType, ExpectedArgType>::value,         \
+                "Strictly typed argument must be of type '" #ExpectedArgType \
+                "'.")
+#define ALLOW_NUMERIC_ARG_TYPES_PROMOTABLE_TO(ExpectedArgType)              \
+  static_assert(                                                            \
+      std::numeric_limits<ExpectedArgType>::is_integer ==                   \
+          std::numeric_limits<ActualArgType>::is_integer,                   \
+      "Conversion between integer and non-integer types not allowed.");     \
+  static_assert(sizeof(ExpectedArgType) >= sizeof(ActualArgType),           \
+                "Truncating conversions not allowed.");                     \
+  static_assert(!std::numeric_limits<ActualArgType>::is_signed ||           \
+                    std::numeric_limits<ExpectedArgType>::is_signed,        \
+                "Signed to unsigned conversion not allowed.");              \
+  static_assert((sizeof(ExpectedArgType) != sizeof(ActualArgType)) ||       \
+                    (std::numeric_limits<ActualArgType>::is_signed ==       \
+                     std::numeric_limits<ExpectedArgType>::is_signed),      \
+                "Unsigned to signed conversion not allowed for types with " \
+                "identical size (could overflow).");
+
+// Macro that returns a compile time constant with the length of an array, but
+// gives an error if passed a non-array.
+template <typename T, size_t Size>
+char (&ArrayLengthHelperFunction(T (&)[Size]))[Size];
+// GCC needs some help to deduce a 0 length array.
+#if COMPILER(GCC)
+template <typename T>
+char (&ArrayLengthHelperFunction(T (&)[0]))[0];
+#endif
+#define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array))
+
+}  // namespace WTF
+
+using WTF::bitwiseCast;
+using WTF::safeCast;
+
+#endif  // WTF_StdLibExtras_h
diff --git a/third_party/WebKit/Source/platform/wtf/ThreadRestrictionVerifier.h b/third_party/WebKit/Source/platform/wtf/ThreadRestrictionVerifier.h
new file mode 100644
index 0000000..44d1b16
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/ThreadRestrictionVerifier.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef ThreadRestrictionVerifier_h
+#define ThreadRestrictionVerifier_h
+
+#include "platform/wtf/Assertions.h"
+
+#if DCHECK_IS_ON()
+
+#include "platform/wtf/Threading.h"
+
+namespace WTF {
+
+// Verifies that a class is used in a way that respects its lack of
+// thread-safety.  The default mode is to verify that the object will only be
+// used on a single thread. The thread gets captured when setShared(true) is
+// called.  The mode may be changed by calling useMutexMode (or
+// turnOffVerification).
+class ThreadRestrictionVerifier {
+ public:
+  ThreadRestrictionVerifier() : m_shared(false), m_owningThread(0) {}
+
+  // Call onRef() before refCount is incremented in ref(). Returns whether the
+  // ref() is safe.
+  template <typename COUNTERTYPE>
+  bool onRef(COUNTERTYPE refCount) {
+    // Start thread verification as soon as the ref count gets to 2. This
+    // heuristic reflects the fact that items are often created on one
+    // thread and then given to another thread to be used.
+    // FIXME: Make this restriction tigher. Especially as we move to more
+    // common methods for sharing items across threads like
+    // CrossThreadCopier.h
+    // We should be able to add a "detachFromThread" method to make this
+    // explicit.
+    if (refCount == 1)
+      setShared(true);
+    return isSafeToUse();
+  }
+
+  // Call onDeref() before refCount is decremented in deref(). Returns whether
+  // the deref() is safe.
+  template <typename COUNTERTYPE>
+  bool onDeref(COUNTERTYPE refCount) {
+    bool safe = isSafeToUse();
+    // Stop thread verification when the ref goes to 1 because it
+    // is safe to be passed to another thread at this point.
+    if (refCount == 2)
+      setShared(false);
+    return safe;
+  }
+
+  // Is it OK to use the object at this moment on the current thread?
+  bool isSafeToUse() const {
+    return !m_shared || m_owningThread == currentThread();
+  }
+
+ private:
+  // Indicates that the object may (or may not) be owned by more than one place.
+  void setShared(bool shared) {
+    bool previouslyShared = m_shared;
+    m_shared = shared;
+
+    if (!m_shared)
+      return;
+
+    DCHECK_NE(shared, previouslyShared);
+    // Capture the current thread to verify that subsequent ref/deref happen on
+    // this thread.
+    m_owningThread = currentThread();
+  }
+
+  bool m_shared;
+
+  ThreadIdentifier m_owningThread;
+};
+
+}  // namespace WTF
+
+#endif  // DCHECK_IS_ON()
+#endif  // ThreadRestrictionVerifier_h
diff --git a/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h b/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h
new file mode 100644
index 0000000..3e49e99
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/ThreadSafeRefCounted.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ */
+
+#ifndef ThreadSafeRefCounted_h
+#define ThreadSafeRefCounted_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Atomics.h"
+#include "platform/wtf/DynamicAnnotations.h"
+#include "platform/wtf/Noncopyable.h"
+#include "platform/wtf/WTFExport.h"
+
+namespace WTF {
+
+class WTF_EXPORT ThreadSafeRefCountedBase {
+  WTF_MAKE_NONCOPYABLE(ThreadSafeRefCountedBase);
+  USING_FAST_MALLOC(ThreadSafeRefCountedBase);
+
+ public:
+  ThreadSafeRefCountedBase(int initialRefCount = 1)
+      : m_refCount(initialRefCount) {}
+
+  void ref() { atomicIncrement(&m_refCount); }
+
+  bool hasOneRef() { return refCount() == 1; }
+
+  int refCount() const { return static_cast<int const volatile&>(m_refCount); }
+
+ protected:
+  // Returns whether the pointer should be freed or not.
+  bool derefBase() {
+    WTF_ANNOTATE_HAPPENS_BEFORE(&m_refCount);
+    if (atomicDecrement(&m_refCount) <= 0) {
+      WTF_ANNOTATE_HAPPENS_AFTER(&m_refCount);
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  int m_refCount;
+};
+
+template <class T>
+class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
+ public:
+  void deref() {
+    if (derefBase())
+      delete static_cast<T*>(this);
+  }
+
+ protected:
+  ThreadSafeRefCounted() {}
+};
+
+}  // namespace WTF
+
+using WTF::ThreadSafeRefCounted;
+
+#endif  // ThreadSafeRefCounted_h
diff --git a/third_party/WebKit/Source/platform/wtf/ThreadSpecific.h b/third_party/WebKit/Source/platform/wtf/ThreadSpecific.h
new file mode 100644
index 0000000..ec237358
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/ThreadSpecific.h
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Jian Li <jianli@chromium.org>
+ * Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com>
+ *
+ * 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.
+ */
+
+/* Thread local storage is implemented by using either pthread API or Windows
+ * native API. There is subtle semantic discrepancy for the cleanup function
+ * implementation as noted below:
+ *   @ In pthread implementation, the destructor function will be called
+ *     repeatedly if there is still non-NULL value associated with the function.
+ *   @ In Windows native implementation, the destructor function will be called
+ *     only once.
+ * This semantic discrepancy does not impose any problem because nowhere in
+ * WebKit the repeated call bahavior is utilized.
+ */
+
+#ifndef WTF_ThreadSpecific_h
+#define WTF_ThreadSpecific_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Noncopyable.h"
+#include "platform/wtf/StackUtil.h"
+#include "platform/wtf/StdLibExtras.h"
+#include "platform/wtf/WTF.h"
+#include "platform/wtf/WTFExport.h"
+#include "platform/wtf/allocator/PartitionAllocator.h"
+#include "platform/wtf/allocator/Partitions.h"
+
+#if OS(POSIX)
+#include <pthread.h>
+#elif OS(WIN)
+#include <windows.h>
+#endif
+
+namespace WTF {
+
+#if OS(WIN)
+// ThreadSpecificThreadExit should be called each time when a thread is
+// detached.
+// This is done automatically for threads created with WTF::createThread.
+WTF_EXPORT void ThreadSpecificThreadExit();
+#endif
+
+template <typename T>
+class ThreadSpecific {
+  USING_FAST_MALLOC(ThreadSpecific);
+  WTF_MAKE_NONCOPYABLE(ThreadSpecific);
+
+ public:
+  ThreadSpecific();
+  bool
+  isSet();  // Useful as a fast check to see if this thread has set this value.
+  T* operator->();
+  operator T*();
+  T& operator*();
+
+ private:
+#if OS(WIN)
+  WTF_EXPORT friend void ThreadSpecificThreadExit();
+#endif
+
+  // Not implemented. It's technically possible to destroy a thread specific
+  // key, but one would need to make sure that all values have been destroyed
+  // already (usually, that all threads that used it have exited). It's
+  // unlikely that any user of this call will be in that situation - and having
+  // a destructor defined can be confusing, given that it has such strong
+  // pre-requisites to work correctly.
+  ~ThreadSpecific();
+
+  T* get();
+  void set(T*);
+  void static destroy(void* ptr);
+
+  struct Data {
+    WTF_MAKE_NONCOPYABLE(Data);
+
+   public:
+    Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
+
+    T* value;
+    ThreadSpecific<T>* owner;
+#if OS(WIN)
+    void (*destructor)(void*);
+#endif
+  };
+
+#if OS(POSIX)
+  pthread_key_t m_key;
+#elif OS(WIN)
+  int m_index;
+#endif
+  // This member must only be accessed or modified on the main thread.
+  T* m_mainThreadStorage = nullptr;
+};
+
+#if OS(POSIX)
+
+typedef pthread_key_t ThreadSpecificKey;
+
+inline void threadSpecificKeyCreate(ThreadSpecificKey* key,
+                                    void (*destructor)(void*)) {
+  int error = pthread_key_create(key, destructor);
+  if (error)
+    CRASH();
+}
+
+inline void threadSpecificKeyDelete(ThreadSpecificKey key) {
+  int error = pthread_key_delete(key);
+  if (error)
+    CRASH();
+}
+
+inline void threadSpecificSet(ThreadSpecificKey key, void* value) {
+  pthread_setspecific(key, value);
+}
+
+inline void* threadSpecificGet(ThreadSpecificKey key) {
+  return pthread_getspecific(key);
+}
+
+template <typename T>
+inline ThreadSpecific<T>::ThreadSpecific() {
+  int error = pthread_key_create(&m_key, destroy);
+  if (error)
+    CRASH();
+}
+
+template <typename T>
+inline T* ThreadSpecific<T>::get() {
+  Data* data = static_cast<Data*>(pthread_getspecific(m_key));
+  return data ? data->value : 0;
+}
+
+template <typename T>
+inline void ThreadSpecific<T>::set(T* ptr) {
+  DCHECK(!get());
+  pthread_setspecific(m_key, new Data(ptr, this));
+}
+
+#elif OS(WIN)
+
+// TLS_OUT_OF_INDEXES is not defined on WinCE.
+#ifndef TLS_OUT_OF_INDEXES
+#define TLS_OUT_OF_INDEXES 0xffffffff
+#endif
+
+// The maximum number of TLS keys that can be created. For simplification, we
+// assume that:
+// 1) Once the instance of ThreadSpecific<> is created, it will not be
+//    destructed until the program dies.
+// 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed
+//    number should be far enough.
+const int kMaxTlsKeySize = 256;
+
+WTF_EXPORT long& tlsKeyCount();
+WTF_EXPORT DWORD* tlsKeys();
+
+class PlatformThreadSpecificKey;
+typedef PlatformThreadSpecificKey* ThreadSpecificKey;
+
+WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void*));
+WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey);
+WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*);
+WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey);
+
+template <typename T>
+inline ThreadSpecific<T>::ThreadSpecific() : m_index(-1) {
+  DWORD tlsKey = TlsAlloc();
+  if (tlsKey == TLS_OUT_OF_INDEXES)
+    CRASH();
+
+  m_index = InterlockedIncrement(&tlsKeyCount()) - 1;
+  if (m_index >= kMaxTlsKeySize)
+    CRASH();
+  tlsKeys()[m_index] = tlsKey;
+}
+
+template <typename T>
+inline ThreadSpecific<T>::~ThreadSpecific() {
+  // Does not invoke destructor functions. They will be called from
+  // ThreadSpecificThreadExit when the thread is detached.
+  TlsFree(tlsKeys()[m_index]);
+}
+
+template <typename T>
+inline T* ThreadSpecific<T>::get() {
+  Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index]));
+  return data ? data->value : 0;
+}
+
+template <typename T>
+inline void ThreadSpecific<T>::set(T* ptr) {
+  DCHECK(!get());
+  Data* data = new Data(ptr, this);
+  data->destructor = &ThreadSpecific<T>::destroy;
+  TlsSetValue(tlsKeys()[m_index], data);
+}
+
+#else
+#error ThreadSpecific is not implemented for this platform.
+#endif
+
+template <typename T>
+inline void ThreadSpecific<T>::destroy(void* ptr) {
+  Data* data = static_cast<Data*>(ptr);
+
+#if OS(POSIX)
+  // We want get() to keep working while data destructor works, because it can
+  // be called indirectly by the destructor.  Some pthreads implementations
+  // zero out the pointer before calling destroy(), so we temporarily reset it.
+  pthread_setspecific(data->owner->m_key, ptr);
+#endif
+
+  // Never call destructors on the main thread. This is fine because Blink no
+  // longer has a graceful shutdown sequence. Be careful to call this function
+  // (which can be re-entrant) while the pointer is still set, to avoid lazily
+  // allocating WTFThreadData after it is destroyed.
+  if (isMainThread())
+    return;
+
+  data->value->~T();
+  Partitions::fastFree(data->value);
+
+#if OS(POSIX)
+  pthread_setspecific(data->owner->m_key, 0);
+#elif OS(WIN)
+  TlsSetValue(tlsKeys()[data->owner->m_index], 0);
+#else
+#error ThreadSpecific is not implemented for this platform.
+#endif
+
+  delete data;
+}
+
+template <typename T>
+inline bool ThreadSpecific<T>::isSet() {
+  return !!get();
+}
+
+template <typename T>
+inline ThreadSpecific<T>::operator T*() {
+  T* offThreadPtr;
+#if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD)
+  // TLS is fast on these platforms.
+  // TODO(csharrison): Qualify this statement for Android.
+  const bool mainThreadAlwaysChecksTLS = true;
+  T** ptr = &offThreadPtr;
+  offThreadPtr = static_cast<T*>(get());
+#else
+  const bool mainThreadAlwaysChecksTLS = false;
+  T** ptr = &m_mainThreadStorage;
+  if (UNLIKELY(mayNotBeMainThread())) {
+    offThreadPtr = static_cast<T*>(get());
+    ptr = &offThreadPtr;
+  }
+#endif
+  // Set up thread-specific value's memory pointer before invoking constructor,
+  // in case any function it calls needs to access the value, to avoid
+  // recursion.
+  if (UNLIKELY(!*ptr)) {
+    *ptr = static_cast<T*>(Partitions::fastZeroedMalloc(
+        sizeof(T), WTF_HEAP_PROFILER_TYPE_NAME(T)));
+
+    // Even if we didn't realize we're on the main thread, we might still be.
+    // We need to double-check so that |m_mainThreadStorage| is populated.
+    if (!mainThreadAlwaysChecksTLS && UNLIKELY(ptr != &m_mainThreadStorage) &&
+        isMainThread()) {
+      m_mainThreadStorage = *ptr;
+    }
+
+    set(*ptr);
+    new (NotNull, *ptr) T;
+  }
+  return *ptr;
+}
+
+template <typename T>
+inline T* ThreadSpecific<T>::operator->() {
+  return operator T*();
+}
+
+template <typename T>
+inline T& ThreadSpecific<T>::operator*() {
+  return *operator T*();
+}
+
+}  // namespace WTF
+
+using WTF::ThreadSpecific;
+
+#endif  // WTF_ThreadSpecific_h
diff --git a/third_party/WebKit/Source/platform/wtf/Threading.h b/third_party/WebKit/Source/platform/wtf/Threading.h
new file mode 100644
index 0000000..9fa2f3b
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/Threading.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ */
+
+#ifndef Threading_h
+#define Threading_h
+
+#include "platform/wtf/Atomics.h"
+#include "platform/wtf/TypeTraits.h"
+#include "platform/wtf/WTFExport.h"
+#include <stdint.h>
+
+namespace WTF {
+
+#if OS(WIN)
+typedef uint32_t ThreadIdentifier;
+#else
+typedef intptr_t ThreadIdentifier;
+#endif
+
+namespace internal {
+WTF_EXPORT ThreadIdentifier currentThreadSyscall();
+}  // namespace internal
+
+// Initializes global state required by |currentThread|.
+// Needs to be called once during program execution, before |currentThread|.
+WTF_EXPORT void initializeCurrentThread();
+
+WTF_EXPORT ThreadIdentifier currentThread();
+
+#if DCHECK_IS_ON()
+WTF_EXPORT bool isBeforeThreadCreated();
+WTF_EXPORT void willCreateThread();
+#endif
+
+}  // namespace WTF
+
+using WTF::ThreadIdentifier;
+using WTF::currentThread;
+
+#endif  // Threading_h
diff --git a/third_party/WebKit/Source/platform/wtf/ThreadingPrimitives.h b/third_party/WebKit/Source/platform/wtf/ThreadingPrimitives.h
new file mode 100644
index 0000000..d9335b3
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/ThreadingPrimitives.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ *
+ */
+
+#ifndef ThreadingPrimitives_h
+#define ThreadingPrimitives_h
+
+#include "platform/wtf/Allocator.h"
+#include "platform/wtf/Assertions.h"
+#include "platform/wtf/Locker.h"
+#include "platform/wtf/Noncopyable.h"
+#include "platform/wtf/WTFExport.h"
+
+#if OS(WIN)
+#include <windows.h>
+#endif
+
+#if OS(POSIX)
+#include <pthread.h>
+#endif
+
+namespace WTF {
+
+#if OS(POSIX)
+struct PlatformMutex {
+  pthread_mutex_t m_internalMutex;
+#if DCHECK_IS_ON()
+  size_t m_recursionCount;
+#endif
+};
+typedef pthread_cond_t PlatformCondition;
+#elif OS(WIN)
+struct PlatformMutex {
+  CRITICAL_SECTION m_internalMutex;
+  size_t m_recursionCount;
+};
+struct PlatformCondition {
+  size_t m_waitersGone;
+  size_t m_waitersBlocked;
+  size_t m_waitersToUnblock;
+  HANDLE m_blockLock;
+  HANDLE m_blockQueue;
+  HANDLE m_unblockLock;
+
+  bool timedWait(PlatformMutex&, DWORD durationMilliseconds);
+  void signal(bool unblockAll);
+};
+#else
+typedef void* PlatformMutex;
+typedef void* PlatformCondition;
+#endif
+
+class WTF_EXPORT MutexBase {
+  WTF_MAKE_NONCOPYABLE(MutexBase);
+  USING_FAST_MALLOC(MutexBase);
+
+ public:
+  ~MutexBase();
+
+  void lock();
+  void unlock();
+#if DCHECK_IS_ON()
+  bool locked() { return m_mutex.m_recursionCount > 0; }
+#endif
+
+ public:
+  PlatformMutex& impl() { return m_mutex; }
+
+ protected:
+  MutexBase(bool recursive);
+
+  PlatformMutex m_mutex;
+};
+
+class WTF_EXPORT Mutex : public MutexBase {
+ public:
+  Mutex() : MutexBase(false) {}
+  bool tryLock();
+};
+
+class WTF_EXPORT RecursiveMutex : public MutexBase {
+ public:
+  RecursiveMutex() : MutexBase(true) {}
+  bool tryLock();
+};
+
+typedef Locker<MutexBase> MutexLocker;
+
+class MutexTryLocker final {
+  STACK_ALLOCATED();
+  WTF_MAKE_NONCOPYABLE(MutexTryLocker);
+
+ public:
+  MutexTryLocker(Mutex& mutex) : m_mutex(mutex), m_locked(mutex.tryLock()) {}
+  ~MutexTryLocker() {
+    if (m_locked)
+      m_mutex.unlock();
+  }
+
+  bool locked() const { return m_locked; }
+
+ private:
+  Mutex& m_mutex;
+  bool m_locked;
+};
+
+class WTF_EXPORT ThreadCondition final {
+  USING_FAST_MALLOC(ThreadCondition);  // Only HeapTest.cpp requires.
+  WTF_MAKE_NONCOPYABLE(ThreadCondition);
+
+ public:
+  ThreadCondition();
+  ~ThreadCondition();
+
+  void wait(MutexBase&);
+  // Returns true if the condition was signaled before absoluteTime, false if
+  // the absoluteTime was reached or is in the past.
+  // The absoluteTime is in seconds, starting on January 1, 1970. The time is
+  // assumed to use the same time zone as WTF::currentTime().
+  bool timedWait(MutexBase&, double absoluteTime);
+  void signal();
+  void broadcast();
+
+ private:
+  PlatformCondition m_condition;
+};
+
+#if OS(WIN)
+// The absoluteTime is in seconds, starting on January 1, 1970. The time is
+// assumed to use the same time zone as WTF::currentTime().
+// Returns an interval in milliseconds suitable for passing to one of the Win32
+// wait functions (e.g., ::WaitForSingleObject).
+DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime);
+#endif
+
+}  // namespace WTF
+
+using WTF::MutexBase;
+using WTF::Mutex;
+using WTF::RecursiveMutex;
+using WTF::MutexLocker;
+using WTF::MutexTryLocker;
+using WTF::ThreadCondition;
+
+#if OS(WIN)
+using WTF::absoluteTimeToWaitTimeoutInterval;
+#endif
+
+#endif  // ThreadingPrimitives_h
diff --git a/third_party/WebKit/Source/platform/wtf/TreeNode.h b/third_party/WebKit/Source/platform/wtf/TreeNode.h
new file mode 100644
index 0000000..7c46f5f2
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/TreeNode.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef TreeNode_h
+#define TreeNode_h
+
+#include "platform/wtf/Assertions.h"
+
+namespace WTF {
+
+//
+// TreeNode is generic, ContainerNode-like linked tree data structure.
+// There are a few notable difference between TreeNode and Node:
+//
+//  * Each TreeNode node is NOT ref counted. The user have to retain its
+//    lifetime somehow.
+//    FIXME: lifetime management could be parameterized so that ref counted
+//    implementations can be used.
+//  * It checks invalid input. The callers have to ensure that given
+//    parameter is sound.
+//  * There is no branch-leaf difference. Every node can be a parent of other
+//    node.
+//
+// FIXME: oilpan: Trace tree node edges to ensure we don't have dangling
+// pointers.
+// As it is used in HTMLImport it is safe since they all die together.
+template <class T>
+class TreeNode {
+ public:
+  typedef T NodeType;
+
+  TreeNode()
+      : m_next(0),
+        m_previous(0),
+        m_parent(0),
+        m_firstChild(0),
+        m_lastChild(0) {}
+
+  NodeType* next() const { return m_next; }
+  NodeType* previous() const { return m_previous; }
+  NodeType* parent() const { return m_parent; }
+  NodeType* firstChild() const { return m_firstChild; }
+  NodeType* lastChild() const { return m_lastChild; }
+  NodeType* here() const {
+    return static_cast<NodeType*>(const_cast<TreeNode*>(this));
+  }
+
+  bool orphan() const {
+    return !m_parent && !m_next && !m_previous && !m_firstChild && !m_lastChild;
+  }
+  bool hasChildren() const { return m_firstChild; }
+
+  void insertBefore(NodeType* newChild, NodeType* refChild) {
+    DCHECK(!newChild->parent());
+    DCHECK(!newChild->next());
+    DCHECK(!newChild->previous());
+
+    DCHECK(!refChild || this == refChild->parent());
+
+    if (!refChild) {
+      appendChild(newChild);
+      return;
+    }
+
+    NodeType* newPrevious = refChild->previous();
+    newChild->m_parent = here();
+    newChild->m_next = refChild;
+    newChild->m_previous = newPrevious;
+    refChild->m_previous = newChild;
+    if (newPrevious)
+      newPrevious->m_next = newChild;
+    else
+      m_firstChild = newChild;
+  }
+
+  void appendChild(NodeType* child) {
+    DCHECK(!child->parent());
+    DCHECK(!child->next());
+    DCHECK(!child->previous());
+
+    child->m_parent = here();
+
+    if (!m_lastChild) {
+      DCHECK(!m_firstChild);
+      m_lastChild = m_firstChild = child;
+      return;
+    }
+
+    DCHECK(!m_lastChild->m_next);
+    NodeType* oldLast = m_lastChild;
+    m_lastChild = child;
+
+    child->m_previous = oldLast;
+    oldLast->m_next = child;
+  }
+
+  NodeType* removeChild(NodeType* child) {
+    DCHECK_EQ(child->parent(), this);
+
+    if (m_firstChild == child)
+      m_firstChild = child->next();
+    if (m_lastChild == child)
+      m_lastChild = child->previous();
+
+    NodeType* oldNext = child->next();
+    NodeType* oldPrevious = child->previous();
+    child->m_parent = child->m_next = child->m_previous = 0;
+
+    if (oldNext)
+      oldNext->m_previous = oldPrevious;
+    if (oldPrevious)
+      oldPrevious->m_next = oldNext;
+
+    return child;
+  }
+
+  void takeChildrenFrom(NodeType* oldParent) {
+    DCHECK_NE(oldParent, this);
+    while (oldParent->hasChildren()) {
+      NodeType* child = oldParent->firstChild();
+      oldParent->removeChild(child);
+      this->appendChild(child);
+    }
+  }
+
+ private:
+  NodeType* m_next;
+  NodeType* m_previous;
+  NodeType* m_parent;
+  NodeType* m_firstChild;
+  NodeType* m_lastChild;
+};
+
+template <class T>
+inline typename TreeNode<T>::NodeType* traverseNext(
+    const TreeNode<T>* current,
+    const TreeNode<T>* stayWithin = 0) {
+  if (typename TreeNode<T>::NodeType* next = current->firstChild())
+    return next;
+  if (current == stayWithin)
+    return 0;
+  if (typename TreeNode<T>::NodeType* next = current->next())
+    return next;
+  for (typename TreeNode<T>::NodeType* parent = current->parent(); parent;
+       parent = parent->parent()) {
+    if (parent == stayWithin)
+      return 0;
+    if (typename TreeNode<T>::NodeType* next = parent->next())
+      return next;
+  }
+
+  return 0;
+}
+
+template <class T>
+inline typename TreeNode<T>::NodeType* traverseFirstPostOrder(
+    const TreeNode<T>* current) {
+  typename TreeNode<T>::NodeType* first = current->here();
+  while (first->firstChild())
+    first = first->firstChild();
+  return first;
+}
+
+template <class T>
+inline typename TreeNode<T>::NodeType* traverseNextPostOrder(
+    const TreeNode<T>* current,
+    const TreeNode<T>* stayWithin = 0) {
+  if (current == stayWithin)
+    return 0;
+
+  typename TreeNode<T>::NodeType* next = current->next();
+  if (!next)
+    return current->parent();
+  while (next->firstChild())
+    next = next->firstChild();
+  return next;
+}
+
+}  // namespace WTF
+
+using WTF::TreeNode;
+using WTF::traverseNext;
+using WTF::traverseNextPostOrder;
+
+#endif
diff --git a/third_party/WebKit/Source/platform/wtf/WeakPtr.h b/third_party/WebKit/Source/platform/wtf/WeakPtr.h
new file mode 100644
index 0000000..57b2e50c
--- /dev/null
+++ b/third_party/WebKit/Source/platform/wtf/WeakPtr.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2013 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:
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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.
+ */
+
+#ifndef WTF_WeakPtr_h
+#define WTF_WeakPtr_h
+
+#include "base/memory/weak_ptr.h"
+#include "platform/wtf/Noncopyable.h"
+
+namespace WTF {
+
+template <typename T>
+using WeakPtr = base::WeakPtr<T>;
+
+template <typename T>
+class WeakPtrFactory {
+  WTF_MAKE_NONCOPYABLE(WeakPtrFactory<T>);
+  USING_FAST_MALLOC(WeakPtrFactory);
+
+ public:
+  explicit WeakPtrFactory(T* ptr) : m_factory(ptr) {}
+
+  WeakPtr<T> createWeakPtr() { return m_factory.GetWeakPtr(); }
+
+  void revokeAll() { m_factory.InvalidateWeakPtrs(); }
+
+  bool hasWeakPtrs() const { return m_factory.HasWeakPtrs(); }
+
+ private:
+  base::WeakPtrFactory<T> m_factory;
+};
+
+}  // namespace WTF
+
+using WTF::WeakPtr;
+using WTF::WeakPtrFactory;
+
+#endif
diff --git a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp
index 461ec069..09c5493 100644
--- a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp
@@ -5,7 +5,6 @@
 #include "bindings/core/v8/NodeOrString.h"
 #include "core/dom/ClientRect.h"
 #include "core/frame/BrowserControls.h"
-#include "core/frame/FrameHost.h"
 #include "core/frame/FrameView.h"
 #include "core/frame/RootFrameViewport.h"
 #include "core/frame/VisualViewport.h"
@@ -101,8 +100,6 @@
 
   Page& page() const { return *m_helper.webView()->page(); }
 
-  FrameHost& frameHost() const { return page().frameHost(); }
-
   LocalFrame* mainFrame() const {
     return webViewImpl()->mainFrameImpl()->frame();
   }
diff --git a/third_party/WebKit/Source/wtf/BUILD.gn b/third_party/WebKit/Source/wtf/BUILD.gn
index 6972003..fb01a91 100644
--- a/third_party/WebKit/Source/wtf/BUILD.gn
+++ b/third_party/WebKit/Source/wtf/BUILD.gn
@@ -22,7 +22,6 @@
     "AddressSanitizer.h",
     "Alignment.h",
     "Allocator.h",
-    "Assertions.cpp",
     "Assertions.h",
     "Atomics.h",
     "AutoReset.h",
diff --git a/third_party/WebKit/Source/wtf/BitwiseOperations.h b/third_party/WebKit/Source/wtf/BitwiseOperations.h
index 9e313a571..f4ae1084 100644
--- a/third_party/WebKit/Source/wtf/BitwiseOperations.h
+++ b/third_party/WebKit/Source/wtf/BitwiseOperations.h
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "platform/wtf/WTFExport.h"
+#include "platform/wtf/BitwiseOperations.h"
 
 // The contents of this header was moved to platform/wtf as part of
 // WTF migration project. See the following post for details:
diff --git a/third_party/WebKit/Source/wtf/Functional.h b/third_party/WebKit/Source/wtf/Functional.h
index 93e827da..c550eef 100644
--- a/third_party/WebKit/Source/wtf/Functional.h
+++ b/third_party/WebKit/Source/wtf/Functional.h
@@ -1,300 +1,9 @@
-/*
- * Copyright (C) 2011 Apple 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:
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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.
- */
+// 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 WTF_Functional_h
-#define WTF_Functional_h
+#include "platform/wtf/Functional.h"
 
-#include "base/bind.h"
-#include "base/threading/thread_checker.h"
-#include "wtf/Allocator.h"
-#include "wtf/Assertions.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/PtrUtil.h"
-#include "wtf/RefPtr.h"
-#include "wtf/ThreadSafeRefCounted.h"
-#include "wtf/TypeTraits.h"
-#include <utility>
-
-namespace blink {
-template <typename T>
-class Member;
-template <typename T>
-class WeakMember;
-}
-
-namespace WTF {
-
-// Functional.h provides a very simple way to bind a function pointer and
-// arguments together into a function object that can be stored, copied and
-// invoked, similar to boost::bind and std::bind in C++11.
-
-// Thread Safety:
-//
-// WTF::bind() and WTF::Closure should be used for same-thread closures
-// only, i.e. the closures must be created, executed and destructed on
-// the same thread.
-// Use crossThreadBind() and CrossThreadClosure if the function/task is called
-// or destructed on a (potentially) different thread from the current thread.
-
-// WTF::bind() and move semantics
-// ==============================
-//
-// For unbound parameters (arguments supplied later on the bound functor
-// directly), there are two ways to pass movable arguments:
-//
-//     1) Pass by rvalue reference.
-//
-//            void yourFunction(Argument&& argument) { ... }
-//            std::unique_ptr<Function<void(Argument&&)>> functor =
-//                bind<Argument&&>(yourFunction);
-//
-//     2) Pass by value.
-//
-//            void yourFunction(Argument argument) { ... }
-//            std::unique_ptr<Function<void(Argument)>> functor =
-//                bind<Argument>(yourFunction);
-//
-// Note that with the latter there will be *two* move constructions happening,
-// because there needs to be at least one intermediary function call taking an
-// argument of type "Argument" (i.e. passed by value). The former case does not
-// require any move constructions inbetween.
-//
-// For bound parameters (arguments supplied on the creation of a functor), you
-// can move your argument into the internal storage of the functor by supplying
-// an rvalue to that argument (this is done in wrap() of ParamStorageTraits).
-// However, to make the functor be able to get called multiple times, the
-// stored object does not get moved out automatically when the underlying
-// function is actually invoked. If you want to make an argument "auto-passed",
-// you can do so by wrapping your bound argument with WTF::passed() function, as
-// shown below:
-//
-//     void yourFunction(Argument argument)
-//     {
-//         // |argument| is passed from the internal storage of functor.
-//         ...
-//     }
-//
-//     ...
-//     std::unique_ptr<Function<void()>> functor = bind(yourFunction,
-//         WTF::passed(Argument()));
-//     ...
-//     (*functor)();
-//
-// The underlying function must receive the argument wrapped by WTF::passed() by
-// rvalue reference or by value.
-//
-// Obviously, if you create a functor this way, you shouldn't call the functor
-// twice or more; after the second call, the passed argument may be invalid.
-
-enum FunctionThreadAffinity { CrossThreadAffinity, SameThreadAffinity };
-
-template <typename T>
-class PassedWrapper final {
- public:
-  explicit PassedWrapper(T&& scoper) : m_scoper(std::move(scoper)) {}
-  PassedWrapper(PassedWrapper&& other) : m_scoper(std::move(other.m_scoper)) {}
-  T moveOut() const { return std::move(m_scoper); }
-
- private:
-  mutable T m_scoper;
-};
-
-template <typename T>
-PassedWrapper<T> passed(T&& value) {
-  static_assert(
-      !std::is_reference<T>::value,
-      "You must pass an rvalue to WTF::passed() so it can be moved. Add "
-      "std::move() if necessary.");
-  static_assert(!std::is_const<T>::value,
-                "|value| must not be const so it can be moved.");
-  return PassedWrapper<T>(std::move(value));
-}
-
-template <typename T, FunctionThreadAffinity threadAffinity>
-class UnretainedWrapper final {
- public:
-  explicit UnretainedWrapper(T* ptr) : m_ptr(ptr) {}
-  T* value() const { return m_ptr; }
-
- private:
-  T* m_ptr;
-};
-
-template <typename T>
-UnretainedWrapper<T, SameThreadAffinity> unretained(T* value) {
-  static_assert(!WTF::IsGarbageCollectedType<T>::value,
-                "WTF::unretained() + GCed type is forbidden");
-  return UnretainedWrapper<T, SameThreadAffinity>(value);
-}
-
-template <typename T>
-UnretainedWrapper<T, CrossThreadAffinity> crossThreadUnretained(T* value) {
-  static_assert(!WTF::IsGarbageCollectedType<T>::value,
-                "crossThreadUnretained() + GCed type is forbidden");
-  return UnretainedWrapper<T, CrossThreadAffinity>(value);
-}
-
-template <typename T>
-struct ParamStorageTraits {
-  typedef T StorageType;
-
-  static_assert(!std::is_pointer<T>::value,
-                "Raw pointers are not allowed to bind into WTF::Function. Wrap "
-                "it with either wrapPersistent, wrapWeakPersistent, "
-                "wrapCrossThreadPersistent, wrapCrossThreadWeakPersistent, "
-                "RefPtr or unretained.");
-  static_assert(!IsSubclassOfTemplate<T, blink::Member>::value &&
-                    !IsSubclassOfTemplate<T, blink::WeakMember>::value,
-                "Member and WeakMember are not allowed to bind into "
-                "WTF::Function. Wrap it with either wrapPersistent, "
-                "wrapWeakPersistent, wrapCrossThreadPersistent or "
-                "wrapCrossThreadWeakPersistent.");
-};
-
-template <typename T>
-struct ParamStorageTraits<PassRefPtr<T>> {
-  typedef RefPtr<T> StorageType;
-};
-
-template <typename T>
-struct ParamStorageTraits<RefPtr<T>> {
-  typedef RefPtr<T> StorageType;
-};
-
-template <typename>
-class RetainPtr;
-
-template <typename T>
-struct ParamStorageTraits<RetainPtr<T>> {
-  typedef RetainPtr<T> StorageType;
-};
-
-template <typename T>
-struct ParamStorageTraits<PassedWrapper<T>> {
-  typedef PassedWrapper<T> StorageType;
-};
-
-template <typename T, FunctionThreadAffinity threadAffinity>
-struct ParamStorageTraits<UnretainedWrapper<T, threadAffinity>> {
-  typedef UnretainedWrapper<T, threadAffinity> StorageType;
-};
-
-template <typename Signature,
-          FunctionThreadAffinity threadAffinity = SameThreadAffinity>
-class Function;
-
-template <typename R, typename... Args, FunctionThreadAffinity threadAffinity>
-class Function<R(Args...), threadAffinity> {
-  USING_FAST_MALLOC(Function);
-  WTF_MAKE_NONCOPYABLE(Function);
-
- public:
-  Function(base::Callback<R(Args...)> callback)
-      : m_callback(std::move(callback)) {}
-
-  ~Function() { DCHECK(m_threadChecker.CalledOnValidThread()); }
-
-  R operator()(Args... args) {
-    DCHECK(m_threadChecker.CalledOnValidThread());
-    return m_callback.Run(std::forward<Args>(args)...);
-  }
-
-  bool isCancelled() const { return m_callback.IsCancelled(); }
-
-  friend base::Callback<R(Args...)> convertToBaseCallback(
-      std::unique_ptr<Function> function) {
-    if (function)
-      return std::move(function->m_callback);
-    return base::Callback<R(Args...)>();
-  }
-
- private:
-  using MaybeThreadChecker =
-      typename std::conditional<threadAffinity == SameThreadAffinity,
-                                base::ThreadChecker,
-                                base::ThreadCheckerDoNothing>::type;
-  MaybeThreadChecker m_threadChecker;
-  base::Callback<R(Args...)> m_callback;
-};
-
-template <FunctionThreadAffinity threadAffinity,
-          typename FunctionType,
-          typename... BoundParameters>
-std::unique_ptr<
-    Function<base::MakeUnboundRunType<FunctionType, BoundParameters...>,
-             threadAffinity>>
-bindInternal(FunctionType function, BoundParameters&&... boundParameters) {
-  using UnboundRunType =
-      base::MakeUnboundRunType<FunctionType, BoundParameters...>;
-  return WTF::wrapUnique(new Function<UnboundRunType,
-                                      threadAffinity>(base::Bind(
-      function,
-      typename ParamStorageTraits<typename std::decay<BoundParameters>::type>::
-          StorageType(std::forward<BoundParameters>(boundParameters))...)));
-}
-
-template <typename FunctionType, typename... BoundParameters>
-std::unique_ptr<
-    Function<base::MakeUnboundRunType<FunctionType, BoundParameters...>,
-             SameThreadAffinity>>
-bind(FunctionType function, BoundParameters&&... boundParameters) {
-  return bindInternal<SameThreadAffinity>(
-      function, std::forward<BoundParameters>(boundParameters)...);
-}
-
-typedef Function<void(), SameThreadAffinity> Closure;
-typedef Function<void(), CrossThreadAffinity> CrossThreadClosure;
-
-}  // namespace WTF
-
-namespace base {
-
-template <typename T>
-struct BindUnwrapTraits<WTF::RefPtr<T>> {
-  static T* Unwrap(const WTF::RefPtr<T>& wrapped) { return wrapped.get(); }
-};
-
-template <typename T>
-struct BindUnwrapTraits<WTF::PassedWrapper<T>> {
-  static T Unwrap(const WTF::PassedWrapper<T>& wrapped) {
-    return wrapped.moveOut();
-  }
-};
-
-template <typename T, WTF::FunctionThreadAffinity threadAffinity>
-struct BindUnwrapTraits<WTF::UnretainedWrapper<T, threadAffinity>> {
-  static T* Unwrap(const WTF::UnretainedWrapper<T, threadAffinity>& wrapped) {
-    return wrapped.value();
-  }
-};
-
-}  // namespace base
-
-using WTF::crossThreadUnretained;
-
-using WTF::Function;
-using WTF::CrossThreadClosure;
-
-#endif  // WTF_Functional_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/HashTableDeletedValueType.h b/third_party/WebKit/Source/wtf/HashTableDeletedValueType.h
index 06b5e5e..7a358fd2 100644
--- a/third_party/WebKit/Source/wtf/HashTableDeletedValueType.h
+++ b/third_party/WebKit/Source/wtf/HashTableDeletedValueType.h
@@ -1,40 +1,9 @@
-/*
- * Copyright (C) 2013 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.
- */
+// 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 HashTableDeletedValueType_h
-#define HashTableDeletedValueType_h
+#include "platform/wtf/HashTableDeletedValueType.h"
 
-namespace WTF {
-
-enum HashTableDeletedValueType { HashTableDeletedValue };
-
-}  // namespace WTF
-
-#endif  // HashTableDeletedValueType_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/InstanceCounter.h b/third_party/WebKit/Source/wtf/InstanceCounter.h
index 8937de0..f5e7612d 100644
--- a/third_party/WebKit/Source/wtf/InstanceCounter.h
+++ b/third_party/WebKit/Source/wtf/InstanceCounter.h
@@ -1,60 +1,9 @@
-/*
- * Copyright (C) 2013 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:
- *
- * 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.
- *
- * 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.
- */
+// 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 InstanceCounter_h
-#define InstanceCounter_h
+#include "platform/wtf/InstanceCounter.h"
 
-#include "wtf/TypeTraits.h"
-#include "wtf/WTFExport.h"
-#include "wtf/build_config.h"
-
-namespace WTF {
-
-class String;
-WTF_EXPORT String dumpRefCountedInstanceCounts();
-
-#if ENABLE(INSTANCE_COUNTER)
-WTF_EXPORT void incrementInstanceCount(const char* stringWithTypeName,
-                                       void* ptr);
-WTF_EXPORT void decrementInstanceCount(const char* stringWithTypeName,
-                                       void* ptr);
-
-WTF_EXPORT String extractTypeNameFromFunctionName(const char* funcName);
-
-template <typename T>
-inline void incrementInstanceCount(T* p) {
-  incrementInstanceCount(getStringWithTypeName<T>(), p);
-}
-
-template <typename T>
-inline void decrementInstanceCount(T* p) {
-  decrementInstanceCount(getStringWithTypeName<T>(), p);
-}
-
-#endif  // ENABLE(INSTANCE_COUNTER)
-
-}  // namespace WTF
-
-#endif
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Locker.h b/third_party/WebKit/Source/wtf/Locker.h
index 9e7381d..de56036 100644
--- a/third_party/WebKit/Source/wtf/Locker.h
+++ b/third_party/WebKit/Source/wtf/Locker.h
@@ -1,53 +1,9 @@
-/*
- * Copyright (C) 2008 Apple 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:
- *
- * 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.
- */
-#ifndef Locker_h
-#define Locker_h
+// 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 "wtf/Allocator.h"
-#include "wtf/Noncopyable.h"
+#include "platform/wtf/Locker.h"
 
-namespace WTF {
-
-template <typename T>
-class Locker final {
-  STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(Locker);
-
- public:
-  Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
-  ~Locker() { m_lockable.unlock(); }
-
- private:
-  T& m_lockable;
-};
-
-}  // namespace WTF
-
-using WTF::Locker;
-
-#endif
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/PassRefPtr.h b/third_party/WebKit/Source/wtf/PassRefPtr.h
index a65d744..0623e52b 100644
--- a/third_party/WebKit/Source/wtf/PassRefPtr.h
+++ b/third_party/WebKit/Source/wtf/PassRefPtr.h
@@ -1,224 +1,9 @@
-/*
- *  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc.
- *  All rights reserved.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public License
- *  along with this library; see the file COPYING.LIB.  If not, write to
- *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- *  Boston, MA 02110-1301, USA.
- *
- */
+// 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.
 
-// PassRefPtr will soon be deleted.
-// New code should instead pass ownership of the contents of a RefPtr using
-// std::move().
+#include "platform/wtf/PassRefPtr.h"
 
-#ifndef WTF_PassRefPtr_h
-#define WTF_PassRefPtr_h
-
-#include "wtf/Allocator.h"
-#include "wtf/Assertions.h"
-#include "wtf/Compiler.h"
-#include "wtf/TypeTraits.h"
-
-namespace WTF {
-
-template <typename T>
-class RefPtr;
-template <typename T>
-class PassRefPtr;
-template <typename T>
-PassRefPtr<T> adoptRef(T*);
-
-inline void adopted(const void*) {}
-
-// requireAdoption() is not overloaded for WTF::RefCounted, which has a built-in
-// assumption that adoption is required. requireAdoption() is for bootstrapping
-// alternate reference count classes that are compatible with ReftPtr/PassRefPtr
-// but cannot have adoption checks enabled by default, such as skia's
-// SkRefCnt. The purpose of requireAdoption() is to enable adoption checks only
-// once it is known that the object will be used with RefPtr/PassRefPtr.
-inline void requireAdoption(const void*) {}
-
-template <typename T>
-ALWAYS_INLINE void refIfNotNull(T* ptr) {
-  if (LIKELY(ptr != 0)) {
-    requireAdoption(ptr);
-    ptr->ref();
-  }
-}
-
-template <typename T>
-ALWAYS_INLINE void derefIfNotNull(T* ptr) {
-  if (LIKELY(ptr != 0))
-    ptr->deref();
-}
-
-template <typename T>
-class PassRefPtr {
-  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-
- public:
-  PassRefPtr() : m_ptr(nullptr) {}
-  PassRefPtr(std::nullptr_t) : m_ptr(nullptr) {}
-  PassRefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
-  PassRefPtr(PassRefPtr&& o) : m_ptr(o.leakRef()) {}
-  template <typename U>
-  PassRefPtr(const PassRefPtr<U>& o, EnsurePtrConvertibleArgDecl(U, T))
-      : m_ptr(o.leakRef()) {}
-
-  ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull(m_ptr); }
-
-  template <typename U>
-  PassRefPtr(const RefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
-  template <typename U>
-  PassRefPtr(RefPtr<U>&&, EnsurePtrConvertibleArgDecl(U, T));
-
-  T* get() const { return m_ptr; }
-
-  WARN_UNUSED_RESULT T* leakRef() const;
-
-  T& operator*() const { return *m_ptr; }
-  T* operator->() const { return m_ptr; }
-
-  bool operator!() const { return !m_ptr; }
-  explicit operator bool() const { return m_ptr != nullptr; }
-
-  friend PassRefPtr adoptRef<T>(T*);
-
- private:
-  enum AdoptRefTag { AdoptRef };
-  PassRefPtr(T* ptr, AdoptRefTag) : m_ptr(ptr) {}
-
-  PassRefPtr& operator=(const PassRefPtr&) {
-    static_assert(!sizeof(T*), "PassRefPtr should never be assigned to");
-    return *this;
-  }
-
-  mutable T* m_ptr;
-};
-
-template <typename T>
-PassRefPtr<T> wrapPassRefPtr(T* ptr) {
-  return PassRefPtr<T>(ptr);
-}
-
-template <typename T>
-template <typename U>
-inline PassRefPtr<T>::PassRefPtr(const RefPtr<U>& o,
-                                 EnsurePtrConvertibleArgDefn(U, T))
-    : m_ptr(o.get()) {
-  T* ptr = m_ptr;
-  refIfNotNull(ptr);
-}
-
-template <typename T>
-template <typename U>
-inline PassRefPtr<T>::PassRefPtr(RefPtr<U>&& o,
-                                 EnsurePtrConvertibleArgDefn(U, T))
-    : m_ptr(o.leakRef()) {}
-
-template <typename T>
-inline T* PassRefPtr<T>::leakRef() const {
-  T* ptr = m_ptr;
-  m_ptr = nullptr;
-  return ptr;
-}
-
-template <typename T, typename U>
-inline bool operator==(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
-  return a.get() == b.get();
-}
-
-template <typename T, typename U>
-inline bool operator==(const PassRefPtr<T>& a, const RefPtr<U>& b) {
-  return a.get() == b.get();
-}
-
-template <typename T, typename U>
-inline bool operator==(const RefPtr<T>& a, const PassRefPtr<U>& b) {
-  return a.get() == b.get();
-}
-
-template <typename T, typename U>
-inline bool operator==(const PassRefPtr<T>& a, U* b) {
-  return a.get() == b;
-}
-
-template <typename T, typename U>
-inline bool operator==(T* a, const PassRefPtr<U>& b) {
-  return a == b.get();
-}
-
-template <typename T>
-inline bool operator==(const PassRefPtr<T>& a, std::nullptr_t) {
-  return !a.get();
-}
-
-template <typename T>
-inline bool operator==(std::nullptr_t, const PassRefPtr<T>& b) {
-  return !b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const PassRefPtr<T>& a, const PassRefPtr<U>& b) {
-  return a.get() != b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const PassRefPtr<T>& a, const RefPtr<U>& b) {
-  return a.get() != b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const RefPtr<T>& a, const PassRefPtr<U>& b) {
-  return a.get() != b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const PassRefPtr<T>& a, U* b) {
-  return a.get() != b;
-}
-
-template <typename T, typename U>
-inline bool operator!=(T* a, const PassRefPtr<U>& b) {
-  return a != b.get();
-}
-
-template <typename T>
-inline bool operator!=(const PassRefPtr<T>& a, std::nullptr_t) {
-  return a.get();
-}
-
-template <typename T>
-inline bool operator!=(std::nullptr_t, const PassRefPtr<T>& b) {
-  return b.get();
-}
-
-template <typename T>
-PassRefPtr<T> adoptRef(T* p) {
-  adopted(p);
-  return PassRefPtr<T>(p, PassRefPtr<T>::AdoptRef);
-}
-
-template <typename T>
-inline T* getPtr(const PassRefPtr<T>& p) {
-  return p.get();
-}
-
-}  // namespace WTF
-
-using WTF::PassRefPtr;
-using WTF::adoptRef;
-
-#endif  // WTF_PassRefPtr_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/PtrUtil.h b/third_party/WebKit/Source/wtf/PtrUtil.h
index 5184733..b61a57b 100644
--- a/third_party/WebKit/Source/wtf/PtrUtil.h
+++ b/third_party/WebKit/Source/wtf/PtrUtil.h
@@ -1,53 +1,9 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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 PtrUtil_h
-#define PtrUtil_h
+#include "platform/wtf/PtrUtil.h"
 
-#include "base/memory/ptr_util.h"
-#include "wtf/TypeTraits.h"
-
-#include <memory>
-
-namespace WTF {
-
-template <typename T>
-std::unique_ptr<T> wrapUnique(T* ptr) {
-  static_assert(
-      !WTF::IsGarbageCollectedType<T>::value,
-      "Garbage collected types should not be stored in std::unique_ptr!");
-  return std::unique_ptr<T>(ptr);
-}
-
-template <typename T>
-std::unique_ptr<T[]> wrapArrayUnique(T* ptr) {
-  static_assert(
-      !WTF::IsGarbageCollectedType<T>::value,
-      "Garbage collected types should not be stored in std::unique_ptr!");
-  return std::unique_ptr<T[]>(ptr);
-}
-
-// WTF::makeUnique is base::MakeUnique. See base/ptr_util.h for documentation.
-template <typename T, typename... Args>
-auto makeUnique(Args&&... args)
-    -> decltype(base::MakeUnique<T>(std::forward<Args>(args)...)) {
-  static_assert(
-      !WTF::IsGarbageCollectedType<T>::value,
-      "Garbage collected types should not be stored in std::unique_ptr!");
-  return base::MakeUnique<T>(std::forward<Args>(args)...);
-}
-
-template <typename T>
-auto makeUnique(size_t size) -> decltype(base::MakeUnique<T>(size)) {
-  static_assert(
-      !WTF::IsGarbageCollectedType<T>::value,
-      "Garbage collected types should not be stored in std::unique_ptr!");
-  return base::MakeUnique<T>(size);
-}
-
-}  // namespace WTF
-
-using WTF::wrapArrayUnique;
-
-#endif  // PtrUtil_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/RefCounted.h b/third_party/WebKit/Source/wtf/RefCounted.h
index a2820ea..18654e4 100644
--- a/third_party/WebKit/Source/wtf/RefCounted.h
+++ b/third_party/WebKit/Source/wtf/RefCounted.h
@@ -1,171 +1,9 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB.  If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
+// 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 RefCounted_h
-#define RefCounted_h
+#include "platform/wtf/RefCounted.h"
 
-#include "wtf/Allocator.h"
-#include "wtf/Assertions.h"
-#include "wtf/Noncopyable.h"
-#include "wtf/WTFExport.h"
-
-#if ENABLE(INSTANCE_COUNTER)
-#include "wtf/InstanceCounter.h"
-#endif
-
-#if DCHECK_IS_ON()
-#define CHECK_REF_COUNTED_LIFECYCLE 1
-#include "wtf/ThreadRestrictionVerifier.h"
-#else
-#define CHECK_REF_COUNTED_LIFECYCLE 0
-#endif
-
-namespace WTF {
-
-// This base class holds the non-template methods and attributes.
-// The RefCounted class inherits from it reducing the template bloat
-// generated by the compiler (technique called template hoisting).
-class WTF_EXPORT RefCountedBase {
- public:
-  void ref() const {
-#if CHECK_REF_COUNTED_LIFECYCLE
-    SECURITY_DCHECK(m_verifier.onRef(m_refCount));
-    DCHECK(!m_adoptionIsRequired);
-#endif
-    SECURITY_DCHECK(!m_deletionHasBegun);
-    ++m_refCount;
-  }
-
-  bool hasOneRef() const {
-    SECURITY_DCHECK(!m_deletionHasBegun);
-#if CHECK_REF_COUNTED_LIFECYCLE
-    SECURITY_DCHECK(m_verifier.isSafeToUse());
-#endif
-    return m_refCount == 1;
-  }
-
-  int refCount() const {
-#if CHECK_REF_COUNTED_LIFECYCLE
-    SECURITY_DCHECK(m_verifier.isSafeToUse());
-#endif
-    return m_refCount;
-  }
-
- protected:
-  RefCountedBase()
-      : m_refCount(1)
-#if ENABLE(SECURITY_ASSERT)
-        ,
-        m_deletionHasBegun(false)
-#endif
-#if CHECK_REF_COUNTED_LIFECYCLE
-        ,
-        m_adoptionIsRequired(true)
-#endif
-  {
-  }
-
-  ~RefCountedBase() {
-    SECURITY_DCHECK(m_deletionHasBegun);
-#if CHECK_REF_COUNTED_LIFECYCLE
-    DCHECK(!m_adoptionIsRequired);
-#endif
-  }
-
-  // Returns whether the pointer should be freed or not.
-  bool derefBase() const {
-    SECURITY_DCHECK(!m_deletionHasBegun);
-#if CHECK_REF_COUNTED_LIFECYCLE
-    SECURITY_DCHECK(m_verifier.onDeref(m_refCount));
-    DCHECK(!m_adoptionIsRequired);
-#endif
-
-    DCHECK_GT(m_refCount, 0);
-    --m_refCount;
-    if (!m_refCount) {
-#if ENABLE(SECURITY_ASSERT)
-      m_deletionHasBegun = true;
-#endif
-      return true;
-    }
-
-    return false;
-  }
-
-#if CHECK_REF_COUNTED_LIFECYCLE
-  bool deletionHasBegun() const { return m_deletionHasBegun; }
-#endif
-
- private:
-#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
-  friend void adopted(RefCountedBase*);
-#endif
-
-  mutable int m_refCount;
-#if ENABLE(SECURITY_ASSERT)
-  mutable bool m_deletionHasBegun;
-#endif
-#if CHECK_REF_COUNTED_LIFECYCLE
-  mutable bool m_adoptionIsRequired;
-  mutable ThreadRestrictionVerifier m_verifier;
-#endif
-};
-
-#if CHECK_REF_COUNTED_LIFECYCLE || ENABLE(SECURITY_ASSERT)
-inline void adopted(RefCountedBase* object) {
-  if (!object)
-    return;
-  SECURITY_DCHECK(!object->m_deletionHasBegun);
-#if CHECK_REF_COUNTED_LIFECYCLE
-  object->m_adoptionIsRequired = false;
-#endif
-}
-#endif
-
-template <typename T>
-class RefCounted : public RefCountedBase {
-  WTF_MAKE_NONCOPYABLE(RefCounted);
-
-  // Put |T| in here instead of |RefCounted| so the heap profiler reports |T|
-  // instead of |RefCounted<T>|. This does not affect overloading of operator
-  // new.
-  USING_FAST_MALLOC(T);
-
- public:
-  void deref() const {
-    if (derefBase())
-      delete static_cast<const T*>(this);
-  }
-
- protected:
-#if ENABLE(INSTANCE_COUNTER)
-  RefCounted() { incrementInstanceCount<T>(static_cast<T*>(this)); }
-
-  ~RefCounted() { decrementInstanceCount<T>(static_cast<T*>(this)); }
-#else
-  RefCounted() {}
-#endif
-};
-
-}  // namespace WTF
-
-using WTF::RefCounted;
-
-#endif  // RefCounted_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/RefPtr.h b/third_party/WebKit/Source/wtf/RefPtr.h
index 6dca0985..4fd6f10 100644
--- a/third_party/WebKit/Source/wtf/RefPtr.h
+++ b/third_party/WebKit/Source/wtf/RefPtr.h
@@ -1,222 +1,9 @@
-/*
- *  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc.
- *  All rights reserved.
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Library General Public
- *  License as published by the Free Software Foundation; either
- *  version 2 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Library General Public License for more details.
- *
- *  You should have received a copy of the GNU Library General Public License
- *  along with this library; see the file COPYING.LIB.  If not, write to
- *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- *  Boston, MA 02110-1301, USA.
- *
- */
+// 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 WTF_RefPtr_h
-#define WTF_RefPtr_h
+#include "platform/wtf/RefPtr.h"
 
-#include "wtf/Allocator.h"
-#include "wtf/HashTableDeletedValueType.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/allocator/PartitionAllocator.h"
-#include <algorithm>
-#include <utility>
-
-namespace WTF {
-
-template <typename T>
-class PassRefPtr;
-template <typename T>
-class RefPtrValuePeeker;
-
-template <typename T>
-class RefPtr {
-  USING_FAST_MALLOC(RefPtr);
-
- public:
-  ALWAYS_INLINE RefPtr() : m_ptr(nullptr) {}
-  ALWAYS_INLINE RefPtr(std::nullptr_t) : m_ptr(nullptr) {}
-  ALWAYS_INLINE RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(ptr); }
-  ALWAYS_INLINE explicit RefPtr(T& ref) : m_ptr(&ref) { m_ptr->ref(); }
-  ALWAYS_INLINE RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) {
-    refIfNotNull(m_ptr);
-  }
-  template <typename U>
-  RefPtr(const RefPtr<U>& o, EnsurePtrConvertibleArgDecl(U, T))
-      : m_ptr(o.get()) {
-    refIfNotNull(m_ptr);
-  }
-  RefPtr(RefPtr&& o) : m_ptr(o.m_ptr) { o.m_ptr = nullptr; }
-
-  // See comments in PassRefPtr.h for an explanation of why this takes a const
-  // reference.
-  template <typename U>
-  RefPtr(const PassRefPtr<U>&, EnsurePtrConvertibleArgDecl(U, T));
-
-  // Hash table deleted values, which are only constructed and never copied or
-  // destroyed.
-  RefPtr(HashTableDeletedValueType) : m_ptr(hashTableDeletedValue()) {}
-  bool isHashTableDeletedValue() const {
-    return m_ptr == hashTableDeletedValue();
-  }
-
-  ALWAYS_INLINE ~RefPtr() { derefIfNotNull(m_ptr); }
-
-  ALWAYS_INLINE T* get() const { return m_ptr; }
-  T* leakRef() WARN_UNUSED_RESULT;
-  void clear();
-  PassRefPtr<T> release() {
-    PassRefPtr<T> tmp = adoptRef(m_ptr);
-    m_ptr = nullptr;
-    return tmp;
-  }
-
-  T& operator*() const { return *m_ptr; }
-  ALWAYS_INLINE T* operator->() const { return m_ptr; }
-
-  bool operator!() const { return !m_ptr; }
-  explicit operator bool() const { return m_ptr != nullptr; }
-
-  RefPtr& operator=(RefPtr o) {
-    swap(o);
-    return *this;
-  }
-  RefPtr& operator=(std::nullptr_t) {
-    clear();
-    return *this;
-  }
-  // This is required by HashMap<RefPtr>>.
-  template <typename U>
-  RefPtr& operator=(RefPtrValuePeeker<U>);
-
-  void swap(RefPtr&);
-
-  static T* hashTableDeletedValue() { return reinterpret_cast<T*>(-1); }
-
- private:
-  T* m_ptr;
-};
-
-template <typename T>
-template <typename U>
-inline RefPtr<T>::RefPtr(const PassRefPtr<U>& o,
-                         EnsurePtrConvertibleArgDefn(U, T))
-    : m_ptr(o.leakRef()) {}
-
-template <typename T>
-inline T* RefPtr<T>::leakRef() {
-  T* ptr = m_ptr;
-  m_ptr = nullptr;
-  return ptr;
-}
-
-template <typename T>
-inline void RefPtr<T>::clear() {
-  T* ptr = m_ptr;
-  m_ptr = nullptr;
-  derefIfNotNull(ptr);
-}
-
-template <typename T>
-template <typename U>
-inline RefPtr<T>& RefPtr<T>::operator=(RefPtrValuePeeker<U> optr) {
-  RefPtr ptr = static_cast<U*>(optr);
-  swap(ptr);
-  return *this;
-}
-
-template <class T>
-inline void RefPtr<T>::swap(RefPtr& o) {
-  std::swap(m_ptr, o.m_ptr);
-}
-
-template <class T>
-inline void swap(RefPtr<T>& a, RefPtr<T>& b) {
-  a.swap(b);
-}
-
-template <typename T, typename U>
-inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b) {
-  return a.get() == b.get();
-}
-
-template <typename T, typename U>
-inline bool operator==(const RefPtr<T>& a, U* b) {
-  return a.get() == b;
-}
-
-template <typename T, typename U>
-inline bool operator==(T* a, const RefPtr<U>& b) {
-  return a == b.get();
-}
-
-template <typename T>
-inline bool operator==(const RefPtr<T>& a, std::nullptr_t) {
-  return !a.get();
-}
-
-template <typename T>
-inline bool operator==(std::nullptr_t, const RefPtr<T>& b) {
-  return !b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b) {
-  return a.get() != b.get();
-}
-
-template <typename T, typename U>
-inline bool operator!=(const RefPtr<T>& a, U* b) {
-  return a.get() != b;
-}
-
-template <typename T, typename U>
-inline bool operator!=(T* a, const RefPtr<U>& b) {
-  return a != b.get();
-}
-
-template <typename T>
-inline bool operator!=(const RefPtr<T>& a, std::nullptr_t) {
-  return a.get();
-}
-
-template <typename T>
-inline bool operator!=(std::nullptr_t, const RefPtr<T>& b) {
-  return b.get();
-}
-
-template <typename T>
-inline T* getPtr(const RefPtr<T>& p) {
-  return p.get();
-}
-
-template <typename T>
-class RefPtrValuePeeker {
-  DISALLOW_NEW();
-
- public:
-  ALWAYS_INLINE RefPtrValuePeeker(T* p) : m_ptr(p) {}
-  ALWAYS_INLINE RefPtrValuePeeker(std::nullptr_t) : m_ptr(nullptr) {}
-  template <typename U>
-  RefPtrValuePeeker(const RefPtr<U>& p) : m_ptr(p.get()) {}
-  template <typename U>
-  RefPtrValuePeeker(const PassRefPtr<U>& p) : m_ptr(p.get()) {}
-
-  ALWAYS_INLINE operator T*() const { return m_ptr; }
-
- private:
-  T* m_ptr;
-};
-
-}  // namespace WTF
-
-using WTF::RefPtr;
-
-#endif  // WTF_RefPtr_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/StackUtil.h b/third_party/WebKit/Source/wtf/StackUtil.h
index c9b9e84..7c0be57 100644
--- a/third_party/WebKit/Source/wtf/StackUtil.h
+++ b/third_party/WebKit/Source/wtf/StackUtil.h
@@ -2,48 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef StackUtil_h
-#define StackUtil_h
+#include "platform/wtf/StackUtil.h"
 
-#include "wtf/Compiler.h"
-#include "wtf/WTFExport.h"
-#include "wtf/build_config.h"
-#include <stddef.h>
-#include <stdint.h>
-
-namespace WTF {
-
-WTF_EXPORT size_t getUnderestimatedStackSize();
-WTF_EXPORT void* getStackStart();
-
-namespace internal {
-
-WTF_EXPORT extern uintptr_t s_mainThreadStackStart;
-WTF_EXPORT extern uintptr_t s_mainThreadUnderestimatedStackSize;
-
-WTF_EXPORT void initializeMainThreadStackEstimate();
-
-#if OS(WIN) && COMPILER(MSVC)
-size_t threadStackSize();
-#endif
-
-}  // namespace internal
-
-// Returns true if the function is not called on the main thread. Note carefully
-// that this function may have false positives, i.e. it can return true even if
-// we are on the main thread. If the function returns false, we are certainly
-// on the main thread.
-inline bool mayNotBeMainThread() {
-  uintptr_t dummy;
-  uintptr_t addressDiff =
-      internal::s_mainThreadStackStart - reinterpret_cast<uintptr_t>(&dummy);
-  // This is a fast way to judge if we are in the main thread.
-  // If |&dummy| is within |s_mainThreadUnderestimatedStackSize| byte from
-  // the stack start of the main thread, we judge that we are in
-  // the main thread.
-  return addressDiff >= internal::s_mainThreadUnderestimatedStackSize;
-}
-
-}  // namespace WTF
-
-#endif  // StackUtil_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/StdLibExtras.h b/third_party/WebKit/Source/wtf/StdLibExtras.h
index b83d321a..ec81685 100644
--- a/third_party/WebKit/Source/wtf/StdLibExtras.h
+++ b/third_party/WebKit/Source/wtf/StdLibExtras.h
@@ -1,269 +1,9 @@
-/*
- * Copyright (C) 2008 Apple 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:
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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.
- */
+// 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 WTF_StdLibExtras_h
-#define WTF_StdLibExtras_h
+#include "platform/wtf/StdLibExtras.h"
 
-#include <cstddef>
-#include "base/numerics/safe_conversions.h"
-#include "wtf/Assertions.h"
-#include "wtf/CPU.h"
-#include "wtf/LeakAnnotations.h"
-#include "wtf/Noncopyable.h"
-#include "wtf/TypeTraits.h"
-
-#if DCHECK_IS_ON()
-#include "wtf/Threading.h"
-#endif
-
-// Use |DEFINE_STATIC_LOCAL()| to declare and define a static local variable
-// (|static T;|) so that it is leaked and its destructors are not called at
-// exit. T may also be a Blink garbage collected object, in which case it is
-// wrapped up by an off-heap |Persistent<T>| reference to the object, keeping
-// it alive across GCs.
-//
-// A |DEFINE_STATIC_LOCAL()| static should only be used on the thread it was
-// created on.
-//
-#define DEFINE_STATIC_LOCAL(Type, Name, Arguments)            \
-  static WTF::StaticSingleton<Type> s_##Name(                 \
-      new WTF::StaticSingleton<Type>::WrapperType Arguments); \
-  Type& Name = s_##Name.get(false)
-
-// |DEFINE_THREAD_SAFE_STATIC_LOCAL()| is the cross-thread accessible variant
-// of |DEFINE_STATIC_LOCAL()|; use it if the singleton can be accessed by
-// multiple threads.
-//
-// TODO: rename as DEFINE_CROSS_THREAD_STATIC_LOCAL() ?
-#define DEFINE_THREAD_SAFE_STATIC_LOCAL(Type, Name, Initializer) \
-  static WTF::StaticSingleton<Type> s_##Name(Initializer);       \
-  Type& Name = s_##Name.get(true)
-
-namespace blink {
-template <typename T>
-class Persistent;
-
-}  // namespace blink
-
-namespace WTF {
-
-template <typename Type>
-class StaticSingleton final {
-  WTF_MAKE_NONCOPYABLE(StaticSingleton);
-
- public:
-  template <typename T,
-            bool = WTF::IsGarbageCollectedType<T>::value &&
-                   !WTF::IsPersistentReferenceType<T>::value>
-  struct Wrapper {
-    using type = T;
-
-    static T& unwrap(T* singleton) { return *singleton; }
-  };
-
-  template <typename T>
-  struct Wrapper<T, true> {
-    using type = blink::Persistent<T>;
-
-    static T& unwrap(blink::Persistent<T>* singleton) {
-      DCHECK(singleton);
-      // If this assert triggers, you're supplying an empty ("()") 'Arguments'
-      // argument to DEFINE_STATIC_LOCAL() - it must be the heap object you wish
-      // to create as a static singleton and wrapped up with a Persistent
-      // reference.
-      DCHECK(*singleton);
-      return **singleton;
-    }
-  };
-
-  using WrapperType = typename Wrapper<Type>::type;
-
-  // To cooperate with leak detection(LSan) for Blink garbage collected objects,
-  // the objects owned by persistent local statics will in some cases have to be
-  // finalized prior to leak checking. This only applies to static references to
-  // Blink heap objects and what they transitively hold on to. Hence the
-  // LEAK_SANITIZER_REGISTER_STATIC_LOCAL() use, it taking care of the grungy
-  // details.
-
-  explicit StaticSingleton(WrapperType* instance)
-      : m_instance(LEAK_SANITIZER_REGISTER_STATIC_LOCAL(WrapperType, instance))
-#if DCHECK_IS_ON()
-        ,
-        m_safelyInitialized(WTF::isBeforeThreadCreated()),
-        m_thread(WTF::internal::currentThreadSyscall())
-#endif
-  {
-  }
-
-  Type& get(bool allowCrossThreadUse) const {
-#if DCHECK_IS_ON()
-    DCHECK(isNotRacy(allowCrossThreadUse));
-#endif
-    ALLOW_UNUSED_LOCAL(allowCrossThreadUse);
-    return Wrapper<Type>::unwrap(m_instance);
-  }
-
-  operator Type&() { return get(); }
-
- private:
-#if DCHECK_IS_ON()
-
-  bool isNotRacy(bool allowCrossThreadUse) const {
-    // Make sure that singleton is safely initialized, or
-    // keeps being called on the same thread if cross-thread
-    // use is not permitted.
-    return allowCrossThreadUse || m_safelyInitialized ||
-           m_thread == WTF::internal::currentThreadSyscall();
-  }
-#endif
-
-  WrapperType* m_instance;
-#if DCHECK_IS_ON()
-  bool m_safelyInitialized;
-  ThreadIdentifier m_thread;
-#endif
-};
-
-}  // namespace WTF
-
-// Use this to declare and define a static local pointer to a ref-counted object
-// so that it is leaked so that the object's destructors are not called at
-// exit.  This macro should be used with ref-counted objects rather than
-// DEFINE_STATIC_LOCAL macro, as this macro does not lead to an extra memory
-// allocation.
-#define DEFINE_STATIC_REF(type, name, arguments) \
-  static type* name = PassRefPtr<type>(arguments).leakRef();
-
-/*
- * The reinterpret_cast<Type1*>([pointer to Type2]) expressions - where
- * sizeof(Type1) > sizeof(Type2) - cause the following warning on ARM with GCC:
- * increases required alignment of target type.
- *
- * An implicit or an extra static_cast<void*> bypasses the warning.
- * For more info see the following bugzilla entries:
- * - https://bugs.webkit.org/show_bug.cgi?id=38045
- * - http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43976
- */
-#if CPU(ARM) && COMPILER(GCC)
-template <typename Type>
-bool isPointerTypeAlignmentOkay(Type* ptr) {
-  return !(reinterpret_cast<intptr_t>(ptr) % __alignof__(Type));
-}
-
-template <typename TypePtr>
-TypePtr reinterpret_cast_ptr(void* ptr) {
-  DCHECK(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
-  return reinterpret_cast<TypePtr>(ptr);
-}
-
-template <typename TypePtr>
-TypePtr reinterpret_cast_ptr(const void* ptr) {
-  DCHECK(isPointerTypeAlignmentOkay(reinterpret_cast<TypePtr>(ptr)));
-  return reinterpret_cast<TypePtr>(ptr);
-}
-#else
-template <typename Type>
-bool isPointerTypeAlignmentOkay(Type*) {
-  return true;
-}
-#define reinterpret_cast_ptr reinterpret_cast
-#endif
-
-namespace WTF {
-
-/*
- * C++'s idea of a reinterpret_cast lacks sufficient cojones.
- */
-template <typename TO, typename FROM>
-inline TO bitwiseCast(FROM from) {
-  static_assert(sizeof(TO) == sizeof(FROM),
-                "WTF::bitwiseCast sizeof casted types should be equal");
-  union {
-    FROM from;
-    TO to;
-  } u;
-  u.from = from;
-  return u.to;
-}
-
-template <typename To, typename From>
-inline To safeCast(From value) {
-  return base::checked_cast<To>(value);
-}
-
-// Use the following macros to prevent errors caused by accidental
-// implicit casting of function arguments.  For example, this can
-// be used to prevent overflows from non-promoting conversions.
-//
-// Example:
-//
-// HAS_STRICTLY_TYPED_ARG
-// void sendData(void* data, STRICTLY_TYPED_ARG(size))
-// {
-//    ALLOW_NUMERIC_ARG_TYPES_PROMOTABLE_TO(size_t);
-//    ...
-// }
-//
-// The previous example will prevent callers from passing, for example, an
-// 'int'. On a 32-bit build, it will prevent use of an 'unsigned long long'.
-#define HAS_STRICTLY_TYPED_ARG template <typename ActualArgType>
-#define STRICTLY_TYPED_ARG(argName) ActualArgType argName
-#define STRICT_ARG_TYPE(ExpectedArgType)                                     \
-  static_assert(std::is_same<ActualArgType, ExpectedArgType>::value,         \
-                "Strictly typed argument must be of type '" #ExpectedArgType \
-                "'.")
-#define ALLOW_NUMERIC_ARG_TYPES_PROMOTABLE_TO(ExpectedArgType)              \
-  static_assert(                                                            \
-      std::numeric_limits<ExpectedArgType>::is_integer ==                   \
-          std::numeric_limits<ActualArgType>::is_integer,                   \
-      "Conversion between integer and non-integer types not allowed.");     \
-  static_assert(sizeof(ExpectedArgType) >= sizeof(ActualArgType),           \
-                "Truncating conversions not allowed.");                     \
-  static_assert(!std::numeric_limits<ActualArgType>::is_signed ||           \
-                    std::numeric_limits<ExpectedArgType>::is_signed,        \
-                "Signed to unsigned conversion not allowed.");              \
-  static_assert((sizeof(ExpectedArgType) != sizeof(ActualArgType)) ||       \
-                    (std::numeric_limits<ActualArgType>::is_signed ==       \
-                     std::numeric_limits<ExpectedArgType>::is_signed),      \
-                "Unsigned to signed conversion not allowed for types with " \
-                "identical size (could overflow).");
-
-// Macro that returns a compile time constant with the length of an array, but
-// gives an error if passed a non-array.
-template <typename T, size_t Size>
-char (&ArrayLengthHelperFunction(T (&)[Size]))[Size];
-// GCC needs some help to deduce a 0 length array.
-#if COMPILER(GCC)
-template <typename T>
-char (&ArrayLengthHelperFunction(T (&)[0]))[0];
-#endif
-#define WTF_ARRAY_LENGTH(array) sizeof(::WTF::ArrayLengthHelperFunction(array))
-
-}  // namespace WTF
-
-using WTF::bitwiseCast;
-using WTF::safeCast;
-
-#endif  // WTF_StdLibExtras_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h b/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h
index 5af787c..fb22bea 100644
--- a/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h
+++ b/third_party/WebKit/Source/wtf/ThreadRestrictionVerifier.h
@@ -1,108 +1,9 @@
-/*
- * Copyright (C) 2011 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.
- */
+// 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 ThreadRestrictionVerifier_h
-#define ThreadRestrictionVerifier_h
+#include "platform/wtf/ThreadRestrictionVerifier.h"
 
-#include "wtf/Assertions.h"
-
-#if DCHECK_IS_ON()
-
-#include "wtf/Threading.h"
-
-namespace WTF {
-
-// Verifies that a class is used in a way that respects its lack of
-// thread-safety.  The default mode is to verify that the object will only be
-// used on a single thread. The thread gets captured when setShared(true) is
-// called.  The mode may be changed by calling useMutexMode (or
-// turnOffVerification).
-class ThreadRestrictionVerifier {
- public:
-  ThreadRestrictionVerifier() : m_shared(false), m_owningThread(0) {}
-
-  // Call onRef() before refCount is incremented in ref(). Returns whether the
-  // ref() is safe.
-  template <typename COUNTERTYPE>
-  bool onRef(COUNTERTYPE refCount) {
-    // Start thread verification as soon as the ref count gets to 2. This
-    // heuristic reflects the fact that items are often created on one
-    // thread and then given to another thread to be used.
-    // FIXME: Make this restriction tigher. Especially as we move to more
-    // common methods for sharing items across threads like
-    // CrossThreadCopier.h
-    // We should be able to add a "detachFromThread" method to make this
-    // explicit.
-    if (refCount == 1)
-      setShared(true);
-    return isSafeToUse();
-  }
-
-  // Call onDeref() before refCount is decremented in deref(). Returns whether
-  // the deref() is safe.
-  template <typename COUNTERTYPE>
-  bool onDeref(COUNTERTYPE refCount) {
-    bool safe = isSafeToUse();
-    // Stop thread verification when the ref goes to 1 because it
-    // is safe to be passed to another thread at this point.
-    if (refCount == 2)
-      setShared(false);
-    return safe;
-  }
-
-  // Is it OK to use the object at this moment on the current thread?
-  bool isSafeToUse() const {
-    return !m_shared || m_owningThread == currentThread();
-  }
-
- private:
-  // Indicates that the object may (or may not) be owned by more than one place.
-  void setShared(bool shared) {
-    bool previouslyShared = m_shared;
-    m_shared = shared;
-
-    if (!m_shared)
-      return;
-
-    DCHECK_NE(shared, previouslyShared);
-    // Capture the current thread to verify that subsequent ref/deref happen on
-    // this thread.
-    m_owningThread = currentThread();
-  }
-
-  bool m_shared;
-
-  ThreadIdentifier m_owningThread;
-};
-
-}  // namespace WTF
-
-#endif  // DCHECK_IS_ON()
-#endif  // ThreadRestrictionVerifier_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ThreadSafeRefCounted.h b/third_party/WebKit/Source/wtf/ThreadSafeRefCounted.h
index c7814bd..e6252f9 100644
--- a/third_party/WebKit/Source/wtf/ThreadSafeRefCounted.h
+++ b/third_party/WebKit/Source/wtf/ThreadSafeRefCounted.h
@@ -1,86 +1,9 @@
-/*
- * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- *
- * 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.
- */
+// 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 ThreadSafeRefCounted_h
-#define ThreadSafeRefCounted_h
+#include "platform/wtf/ThreadSafeRefCounted.h"
 
-#include "wtf/Allocator.h"
-#include "wtf/Atomics.h"
-#include "wtf/DynamicAnnotations.h"
-#include "wtf/Noncopyable.h"
-#include "wtf/WTFExport.h"
-
-namespace WTF {
-
-class WTF_EXPORT ThreadSafeRefCountedBase {
-  WTF_MAKE_NONCOPYABLE(ThreadSafeRefCountedBase);
-  USING_FAST_MALLOC(ThreadSafeRefCountedBase);
-
- public:
-  ThreadSafeRefCountedBase(int initialRefCount = 1)
-      : m_refCount(initialRefCount) {}
-
-  void ref() { atomicIncrement(&m_refCount); }
-
-  bool hasOneRef() { return refCount() == 1; }
-
-  int refCount() const { return static_cast<int const volatile&>(m_refCount); }
-
- protected:
-  // Returns whether the pointer should be freed or not.
-  bool derefBase() {
-    WTF_ANNOTATE_HAPPENS_BEFORE(&m_refCount);
-    if (atomicDecrement(&m_refCount) <= 0) {
-      WTF_ANNOTATE_HAPPENS_AFTER(&m_refCount);
-      return true;
-    }
-    return false;
-  }
-
- private:
-  int m_refCount;
-};
-
-template <class T>
-class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {
- public:
-  void deref() {
-    if (derefBase())
-      delete static_cast<T*>(this);
-  }
-
- protected:
-  ThreadSafeRefCounted() {}
-};
-
-}  // namespace WTF
-
-using WTF::ThreadSafeRefCounted;
-
-#endif  // ThreadSafeRefCounted_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecific.h b/third_party/WebKit/Source/wtf/ThreadSpecific.h
index 57c6392..25935b0c 100644
--- a/third_party/WebKit/Source/wtf/ThreadSpecific.h
+++ b/third_party/WebKit/Source/wtf/ThreadSpecific.h
@@ -1,316 +1,9 @@
-/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2009 Jian Li <jianli@chromium.org>
- * Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com>
- *
- * 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.
- */
+// 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.
 
-/* Thread local storage is implemented by using either pthread API or Windows
- * native API. There is subtle semantic discrepancy for the cleanup function
- * implementation as noted below:
- *   @ In pthread implementation, the destructor function will be called
- *     repeatedly if there is still non-NULL value associated with the function.
- *   @ In Windows native implementation, the destructor function will be called
- *     only once.
- * This semantic discrepancy does not impose any problem because nowhere in
- * WebKit the repeated call bahavior is utilized.
- */
+#include "platform/wtf/ThreadSpecific.h"
 
-#ifndef WTF_ThreadSpecific_h
-#define WTF_ThreadSpecific_h
-
-#include "wtf/Allocator.h"
-#include "wtf/Noncopyable.h"
-#include "wtf/StackUtil.h"
-#include "wtf/StdLibExtras.h"
-#include "wtf/WTF.h"
-#include "wtf/WTFExport.h"
-#include "wtf/allocator/PartitionAllocator.h"
-#include "wtf/allocator/Partitions.h"
-
-#if OS(POSIX)
-#include <pthread.h>
-#elif OS(WIN)
-#include <windows.h>
-#endif
-
-namespace WTF {
-
-#if OS(WIN)
-// ThreadSpecificThreadExit should be called each time when a thread is
-// detached.
-// This is done automatically for threads created with WTF::createThread.
-WTF_EXPORT void ThreadSpecificThreadExit();
-#endif
-
-template <typename T>
-class ThreadSpecific {
-  USING_FAST_MALLOC(ThreadSpecific);
-  WTF_MAKE_NONCOPYABLE(ThreadSpecific);
-
- public:
-  ThreadSpecific();
-  bool
-  isSet();  // Useful as a fast check to see if this thread has set this value.
-  T* operator->();
-  operator T*();
-  T& operator*();
-
- private:
-#if OS(WIN)
-  WTF_EXPORT friend void ThreadSpecificThreadExit();
-#endif
-
-  // Not implemented. It's technically possible to destroy a thread specific
-  // key, but one would need to make sure that all values have been destroyed
-  // already (usually, that all threads that used it have exited). It's
-  // unlikely that any user of this call will be in that situation - and having
-  // a destructor defined can be confusing, given that it has such strong
-  // pre-requisites to work correctly.
-  ~ThreadSpecific();
-
-  T* get();
-  void set(T*);
-  void static destroy(void* ptr);
-
-  struct Data {
-    WTF_MAKE_NONCOPYABLE(Data);
-
-   public:
-    Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {}
-
-    T* value;
-    ThreadSpecific<T>* owner;
-#if OS(WIN)
-    void (*destructor)(void*);
-#endif
-  };
-
-#if OS(POSIX)
-  pthread_key_t m_key;
-#elif OS(WIN)
-  int m_index;
-#endif
-  // This member must only be accessed or modified on the main thread.
-  T* m_mainThreadStorage = nullptr;
-};
-
-#if OS(POSIX)
-
-typedef pthread_key_t ThreadSpecificKey;
-
-inline void threadSpecificKeyCreate(ThreadSpecificKey* key,
-                                    void (*destructor)(void*)) {
-  int error = pthread_key_create(key, destructor);
-  if (error)
-    CRASH();
-}
-
-inline void threadSpecificKeyDelete(ThreadSpecificKey key) {
-  int error = pthread_key_delete(key);
-  if (error)
-    CRASH();
-}
-
-inline void threadSpecificSet(ThreadSpecificKey key, void* value) {
-  pthread_setspecific(key, value);
-}
-
-inline void* threadSpecificGet(ThreadSpecificKey key) {
-  return pthread_getspecific(key);
-}
-
-template <typename T>
-inline ThreadSpecific<T>::ThreadSpecific() {
-  int error = pthread_key_create(&m_key, destroy);
-  if (error)
-    CRASH();
-}
-
-template <typename T>
-inline T* ThreadSpecific<T>::get() {
-  Data* data = static_cast<Data*>(pthread_getspecific(m_key));
-  return data ? data->value : 0;
-}
-
-template <typename T>
-inline void ThreadSpecific<T>::set(T* ptr) {
-  DCHECK(!get());
-  pthread_setspecific(m_key, new Data(ptr, this));
-}
-
-#elif OS(WIN)
-
-// TLS_OUT_OF_INDEXES is not defined on WinCE.
-#ifndef TLS_OUT_OF_INDEXES
-#define TLS_OUT_OF_INDEXES 0xffffffff
-#endif
-
-// The maximum number of TLS keys that can be created. For simplification, we
-// assume that:
-// 1) Once the instance of ThreadSpecific<> is created, it will not be
-//    destructed until the program dies.
-// 2) We do not need to hold many instances of ThreadSpecific<> data. This fixed
-//    number should be far enough.
-const int kMaxTlsKeySize = 256;
-
-WTF_EXPORT long& tlsKeyCount();
-WTF_EXPORT DWORD* tlsKeys();
-
-class PlatformThreadSpecificKey;
-typedef PlatformThreadSpecificKey* ThreadSpecificKey;
-
-WTF_EXPORT void threadSpecificKeyCreate(ThreadSpecificKey*, void (*)(void*));
-WTF_EXPORT void threadSpecificKeyDelete(ThreadSpecificKey);
-WTF_EXPORT void threadSpecificSet(ThreadSpecificKey, void*);
-WTF_EXPORT void* threadSpecificGet(ThreadSpecificKey);
-
-template <typename T>
-inline ThreadSpecific<T>::ThreadSpecific() : m_index(-1) {
-  DWORD tlsKey = TlsAlloc();
-  if (tlsKey == TLS_OUT_OF_INDEXES)
-    CRASH();
-
-  m_index = InterlockedIncrement(&tlsKeyCount()) - 1;
-  if (m_index >= kMaxTlsKeySize)
-    CRASH();
-  tlsKeys()[m_index] = tlsKey;
-}
-
-template <typename T>
-inline ThreadSpecific<T>::~ThreadSpecific() {
-  // Does not invoke destructor functions. They will be called from
-  // ThreadSpecificThreadExit when the thread is detached.
-  TlsFree(tlsKeys()[m_index]);
-}
-
-template <typename T>
-inline T* ThreadSpecific<T>::get() {
-  Data* data = static_cast<Data*>(TlsGetValue(tlsKeys()[m_index]));
-  return data ? data->value : 0;
-}
-
-template <typename T>
-inline void ThreadSpecific<T>::set(T* ptr) {
-  DCHECK(!get());
-  Data* data = new Data(ptr, this);
-  data->destructor = &ThreadSpecific<T>::destroy;
-  TlsSetValue(tlsKeys()[m_index], data);
-}
-
-#else
-#error ThreadSpecific is not implemented for this platform.
-#endif
-
-template <typename T>
-inline void ThreadSpecific<T>::destroy(void* ptr) {
-  Data* data = static_cast<Data*>(ptr);
-
-#if OS(POSIX)
-  // We want get() to keep working while data destructor works, because it can
-  // be called indirectly by the destructor.  Some pthreads implementations
-  // zero out the pointer before calling destroy(), so we temporarily reset it.
-  pthread_setspecific(data->owner->m_key, ptr);
-#endif
-
-  // Never call destructors on the main thread. This is fine because Blink no
-  // longer has a graceful shutdown sequence. Be careful to call this function
-  // (which can be re-entrant) while the pointer is still set, to avoid lazily
-  // allocating WTFThreadData after it is destroyed.
-  if (isMainThread())
-    return;
-
-  data->value->~T();
-  Partitions::fastFree(data->value);
-
-#if OS(POSIX)
-  pthread_setspecific(data->owner->m_key, 0);
-#elif OS(WIN)
-  TlsSetValue(tlsKeys()[data->owner->m_index], 0);
-#else
-#error ThreadSpecific is not implemented for this platform.
-#endif
-
-  delete data;
-}
-
-template <typename T>
-inline bool ThreadSpecific<T>::isSet() {
-  return !!get();
-}
-
-template <typename T>
-inline ThreadSpecific<T>::operator T*() {
-  T* offThreadPtr;
-#if defined(__GLIBC__) || OS(ANDROID) || OS(FREEBSD)
-  // TLS is fast on these platforms.
-  // TODO(csharrison): Qualify this statement for Android.
-  const bool mainThreadAlwaysChecksTLS = true;
-  T** ptr = &offThreadPtr;
-  offThreadPtr = static_cast<T*>(get());
-#else
-  const bool mainThreadAlwaysChecksTLS = false;
-  T** ptr = &m_mainThreadStorage;
-  if (UNLIKELY(mayNotBeMainThread())) {
-    offThreadPtr = static_cast<T*>(get());
-    ptr = &offThreadPtr;
-  }
-#endif
-  // Set up thread-specific value's memory pointer before invoking constructor,
-  // in case any function it calls needs to access the value, to avoid
-  // recursion.
-  if (UNLIKELY(!*ptr)) {
-    *ptr = static_cast<T*>(Partitions::fastZeroedMalloc(
-        sizeof(T), WTF_HEAP_PROFILER_TYPE_NAME(T)));
-
-    // Even if we didn't realize we're on the main thread, we might still be.
-    // We need to double-check so that |m_mainThreadStorage| is populated.
-    if (!mainThreadAlwaysChecksTLS && UNLIKELY(ptr != &m_mainThreadStorage) &&
-        isMainThread()) {
-      m_mainThreadStorage = *ptr;
-    }
-
-    set(*ptr);
-    new (NotNull, *ptr) T;
-  }
-  return *ptr;
-}
-
-template <typename T>
-inline T* ThreadSpecific<T>::operator->() {
-  return operator T*();
-}
-
-template <typename T>
-inline T& ThreadSpecific<T>::operator*() {
-  return *operator T*();
-}
-
-}  // namespace WTF
-
-using WTF::ThreadSpecific;
-
-#endif  // WTF_ThreadSpecific_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/Threading.h b/third_party/WebKit/Source/wtf/Threading.h
index 4c78f22..0210ff1 100644
--- a/third_party/WebKit/Source/wtf/Threading.h
+++ b/third_party/WebKit/Source/wtf/Threading.h
@@ -1,66 +1,9 @@
-/*
- * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- *
- * 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.
- */
+// 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 Threading_h
-#define Threading_h
+#include "platform/wtf/Threading.h"
 
-#include "wtf/Atomics.h"
-#include "wtf/TypeTraits.h"
-#include "wtf/WTFExport.h"
-#include <stdint.h>
-
-namespace WTF {
-
-#if OS(WIN)
-typedef uint32_t ThreadIdentifier;
-#else
-typedef intptr_t ThreadIdentifier;
-#endif
-
-namespace internal {
-WTF_EXPORT ThreadIdentifier currentThreadSyscall();
-}  // namespace internal
-
-// Initializes global state required by |currentThread|.
-// Needs to be called once during program execution, before |currentThread|.
-WTF_EXPORT void initializeCurrentThread();
-
-WTF_EXPORT ThreadIdentifier currentThread();
-
-#if DCHECK_IS_ON()
-WTF_EXPORT bool isBeforeThreadCreated();
-WTF_EXPORT void willCreateThread();
-#endif
-
-}  // namespace WTF
-
-using WTF::ThreadIdentifier;
-using WTF::currentThread;
-
-#endif  // Threading_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
index 84b72a6..0f40588 100644
--- a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
+++ b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
@@ -1,175 +1,9 @@
-/*
- * Copyright (C) 2007, 2008, 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
- *
- * 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.
- *
- */
+// 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 ThreadingPrimitives_h
-#define ThreadingPrimitives_h
+#include "platform/wtf/ThreadingPrimitives.h"
 
-#include "wtf/Allocator.h"
-#include "wtf/Assertions.h"
-#include "wtf/Locker.h"
-#include "wtf/Noncopyable.h"
-#include "wtf/WTFExport.h"
-
-#if OS(WIN)
-#include <windows.h>
-#endif
-
-#if OS(POSIX)
-#include <pthread.h>
-#endif
-
-namespace WTF {
-
-#if OS(POSIX)
-struct PlatformMutex {
-  pthread_mutex_t m_internalMutex;
-#if DCHECK_IS_ON()
-  size_t m_recursionCount;
-#endif
-};
-typedef pthread_cond_t PlatformCondition;
-#elif OS(WIN)
-struct PlatformMutex {
-  CRITICAL_SECTION m_internalMutex;
-  size_t m_recursionCount;
-};
-struct PlatformCondition {
-  size_t m_waitersGone;
-  size_t m_waitersBlocked;
-  size_t m_waitersToUnblock;
-  HANDLE m_blockLock;
-  HANDLE m_blockQueue;
-  HANDLE m_unblockLock;
-
-  bool timedWait(PlatformMutex&, DWORD durationMilliseconds);
-  void signal(bool unblockAll);
-};
-#else
-typedef void* PlatformMutex;
-typedef void* PlatformCondition;
-#endif
-
-class WTF_EXPORT MutexBase {
-  WTF_MAKE_NONCOPYABLE(MutexBase);
-  USING_FAST_MALLOC(MutexBase);
-
- public:
-  ~MutexBase();
-
-  void lock();
-  void unlock();
-#if DCHECK_IS_ON()
-  bool locked() { return m_mutex.m_recursionCount > 0; }
-#endif
-
- public:
-  PlatformMutex& impl() { return m_mutex; }
-
- protected:
-  MutexBase(bool recursive);
-
-  PlatformMutex m_mutex;
-};
-
-class WTF_EXPORT Mutex : public MutexBase {
- public:
-  Mutex() : MutexBase(false) {}
-  bool tryLock();
-};
-
-class WTF_EXPORT RecursiveMutex : public MutexBase {
- public:
-  RecursiveMutex() : MutexBase(true) {}
-  bool tryLock();
-};
-
-typedef Locker<MutexBase> MutexLocker;
-
-class MutexTryLocker final {
-  STACK_ALLOCATED();
-  WTF_MAKE_NONCOPYABLE(MutexTryLocker);
-
- public:
-  MutexTryLocker(Mutex& mutex) : m_mutex(mutex), m_locked(mutex.tryLock()) {}
-  ~MutexTryLocker() {
-    if (m_locked)
-      m_mutex.unlock();
-  }
-
-  bool locked() const { return m_locked; }
-
- private:
-  Mutex& m_mutex;
-  bool m_locked;
-};
-
-class WTF_EXPORT ThreadCondition final {
-  USING_FAST_MALLOC(ThreadCondition);  // Only HeapTest.cpp requires.
-  WTF_MAKE_NONCOPYABLE(ThreadCondition);
-
- public:
-  ThreadCondition();
-  ~ThreadCondition();
-
-  void wait(MutexBase&);
-  // Returns true if the condition was signaled before absoluteTime, false if
-  // the absoluteTime was reached or is in the past.
-  // The absoluteTime is in seconds, starting on January 1, 1970. The time is
-  // assumed to use the same time zone as WTF::currentTime().
-  bool timedWait(MutexBase&, double absoluteTime);
-  void signal();
-  void broadcast();
-
- private:
-  PlatformCondition m_condition;
-};
-
-#if OS(WIN)
-// The absoluteTime is in seconds, starting on January 1, 1970. The time is
-// assumed to use the same time zone as WTF::currentTime().
-// Returns an interval in milliseconds suitable for passing to one of the Win32
-// wait functions (e.g., ::WaitForSingleObject).
-DWORD absoluteTimeToWaitTimeoutInterval(double absoluteTime);
-#endif
-
-}  // namespace WTF
-
-using WTF::MutexBase;
-using WTF::Mutex;
-using WTF::RecursiveMutex;
-using WTF::MutexLocker;
-using WTF::MutexTryLocker;
-using WTF::ThreadCondition;
-
-#if OS(WIN)
-using WTF::absoluteTimeToWaitTimeoutInterval;
-#endif
-
-#endif  // ThreadingPrimitives_h
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/TreeNode.h b/third_party/WebKit/Source/wtf/TreeNode.h
index ce0fecd3..071039fb 100644
--- a/third_party/WebKit/Source/wtf/TreeNode.h
+++ b/third_party/WebKit/Source/wtf/TreeNode.h
@@ -1,212 +1,9 @@
-/*
- * Copyright (C) 2013 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.
- */
+// 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 TreeNode_h
-#define TreeNode_h
+#include "platform/wtf/TreeNode.h"
 
-#include "wtf/Assertions.h"
-
-namespace WTF {
-
-//
-// TreeNode is generic, ContainerNode-like linked tree data structure.
-// There are a few notable difference between TreeNode and Node:
-//
-//  * Each TreeNode node is NOT ref counted. The user have to retain its
-//    lifetime somehow.
-//    FIXME: lifetime management could be parameterized so that ref counted
-//    implementations can be used.
-//  * It checks invalid input. The callers have to ensure that given
-//    parameter is sound.
-//  * There is no branch-leaf difference. Every node can be a parent of other
-//    node.
-//
-// FIXME: oilpan: Trace tree node edges to ensure we don't have dangling
-// pointers.
-// As it is used in HTMLImport it is safe since they all die together.
-template <class T>
-class TreeNode {
- public:
-  typedef T NodeType;
-
-  TreeNode()
-      : m_next(0),
-        m_previous(0),
-        m_parent(0),
-        m_firstChild(0),
-        m_lastChild(0) {}
-
-  NodeType* next() const { return m_next; }
-  NodeType* previous() const { return m_previous; }
-  NodeType* parent() const { return m_parent; }
-  NodeType* firstChild() const { return m_firstChild; }
-  NodeType* lastChild() const { return m_lastChild; }
-  NodeType* here() const {
-    return static_cast<NodeType*>(const_cast<TreeNode*>(this));
-  }
-
-  bool orphan() const {
-    return !m_parent && !m_next && !m_previous && !m_firstChild && !m_lastChild;
-  }
-  bool hasChildren() const { return m_firstChild; }
-
-  void insertBefore(NodeType* newChild, NodeType* refChild) {
-    DCHECK(!newChild->parent());
-    DCHECK(!newChild->next());
-    DCHECK(!newChild->previous());
-
-    DCHECK(!refChild || this == refChild->parent());
-
-    if (!refChild) {
-      appendChild(newChild);
-      return;
-    }
-
-    NodeType* newPrevious = refChild->previous();
-    newChild->m_parent = here();
-    newChild->m_next = refChild;
-    newChild->m_previous = newPrevious;
-    refChild->m_previous = newChild;
-    if (newPrevious)
-      newPrevious->m_next = newChild;
-    else
-      m_firstChild = newChild;
-  }
-
-  void appendChild(NodeType* child) {
-    DCHECK(!child->parent());
-    DCHECK(!child->next());
-    DCHECK(!child->previous());
-
-    child->m_parent = here();
-
-    if (!m_lastChild) {
-      DCHECK(!m_firstChild);
-      m_lastChild = m_firstChild = child;
-      return;
-    }
-
-    DCHECK(!m_lastChild->m_next);
-    NodeType* oldLast = m_lastChild;
-    m_lastChild = child;
-
-    child->m_previous = oldLast;
-    oldLast->m_next = child;
-  }
-
-  NodeType* removeChild(NodeType* child) {
-    DCHECK_EQ(child->parent(), this);
-
-    if (m_firstChild == child)
-      m_firstChild = child->next();
-    if (m_lastChild == child)
-      m_lastChild = child->previous();
-
-    NodeType* oldNext = child->next();
-    NodeType* oldPrevious = child->previous();
-    child->m_parent = child->m_next = child->m_previous = 0;
-
-    if (oldNext)
-      oldNext->m_previous = oldPrevious;
-    if (oldPrevious)
-      oldPrevious->m_next = oldNext;
-
-    return child;
-  }
-
-  void takeChildrenFrom(NodeType* oldParent) {
-    DCHECK_NE(oldParent, this);
-    while (oldParent->hasChildren()) {
-      NodeType* child = oldParent->firstChild();
-      oldParent->removeChild(child);
-      this->appendChild(child);
-    }
-  }
-
- private:
-  NodeType* m_next;
-  NodeType* m_previous;
-  NodeType* m_parent;
-  NodeType* m_firstChild;
-  NodeType* m_lastChild;
-};
-
-template <class T>
-inline typename TreeNode<T>::NodeType* traverseNext(
-    const TreeNode<T>* current,
-    const TreeNode<T>* stayWithin = 0) {
-  if (typename TreeNode<T>::NodeType* next = current->firstChild())
-    return next;
-  if (current == stayWithin)
-    return 0;
-  if (typename TreeNode<T>::NodeType* next = current->next())
-    return next;
-  for (typename TreeNode<T>::NodeType* parent = current->parent(); parent;
-       parent = parent->parent()) {
-    if (parent == stayWithin)
-      return 0;
-    if (typename TreeNode<T>::NodeType* next = parent->next())
-      return next;
-  }
-
-  return 0;
-}
-
-template <class T>
-inline typename TreeNode<T>::NodeType* traverseFirstPostOrder(
-    const TreeNode<T>* current) {
-  typename TreeNode<T>::NodeType* first = current->here();
-  while (first->firstChild())
-    first = first->firstChild();
-  return first;
-}
-
-template <class T>
-inline typename TreeNode<T>::NodeType* traverseNextPostOrder(
-    const TreeNode<T>* current,
-    const TreeNode<T>* stayWithin = 0) {
-  if (current == stayWithin)
-    return 0;
-
-  typename TreeNode<T>::NodeType* next = current->next();
-  if (!next)
-    return current->parent();
-  while (next->firstChild())
-    next = next->firstChild();
-  return next;
-}
-
-}  // namespace WTF
-
-using WTF::TreeNode;
-using WTF::traverseNext;
-using WTF::traverseNextPostOrder;
-
-#endif
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/WebKit/Source/wtf/WeakPtr.h b/third_party/WebKit/Source/wtf/WeakPtr.h
index cddba0cf..6f751b85 100644
--- a/third_party/WebKit/Source/wtf/WeakPtr.h
+++ b/third_party/WebKit/Source/wtf/WeakPtr.h
@@ -1,60 +1,9 @@
-/*
- * Copyright (C) 2013 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:
- * 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. 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.
- */
+// 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 WTF_WeakPtr_h
-#define WTF_WeakPtr_h
+#include "platform/wtf/WeakPtr.h"
 
-#include "base/memory/weak_ptr.h"
-#include "wtf/Noncopyable.h"
-
-namespace WTF {
-
-template <typename T>
-using WeakPtr = base::WeakPtr<T>;
-
-template <typename T>
-class WeakPtrFactory {
-  WTF_MAKE_NONCOPYABLE(WeakPtrFactory<T>);
-  USING_FAST_MALLOC(WeakPtrFactory);
-
- public:
-  explicit WeakPtrFactory(T* ptr) : m_factory(ptr) {}
-
-  WeakPtr<T> createWeakPtr() { return m_factory.GetWeakPtr(); }
-
-  void revokeAll() { m_factory.InvalidateWeakPtrs(); }
-
-  bool hasWeakPtrs() const { return m_factory.HasWeakPtrs(); }
-
- private:
-  base::WeakPtrFactory<T> m_factory;
-};
-
-}  // namespace WTF
-
-using WTF::WeakPtr;
-using WTF::WeakPtrFactory;
-
-#endif
+// The contents of this header was moved to platform/wtf as part of
+// WTF migration project. See the following post for details:
+// https://groups.google.com/a/chromium.org/d/msg/blink-dev/tLdAZCTlcAA/bYXVT8gYCAAJ
diff --git a/third_party/hamcrest/BUILD.gn b/third_party/hamcrest/BUILD.gn
index 3680c10..3c0c4d4 100644
--- a/third_party/hamcrest/BUILD.gn
+++ b/third_party/hamcrest/BUILD.gn
@@ -17,16 +17,19 @@
   supports_android = true
   testonly = true
   jar_path = "lib/hamcrest-core-1.3.jar"
+  proguard_configs = [ "//third_party/hamcrest/proguard.flags" ]
 }
 
 java_prebuilt("hamcrest_integration_java") {
   supports_android = true
   testonly = true
   jar_path = "lib/hamcrest-integration-1.3.jar"
+  proguard_configs = [ "//third_party/hamcrest/proguard.flags" ]
 }
 
 java_prebuilt("hamcrest_library_java") {
   supports_android = true
   testonly = true
   jar_path = "lib/hamcrest-library-1.3.jar"
+  proguard_configs = [ "//third_party/hamcrest/proguard.flags" ]
 }
diff --git a/third_party/hamcrest/proguard.flags b/third_party/hamcrest/proguard.flags
new file mode 100644
index 0000000..e9caf63
--- /dev/null
+++ b/third_party/hamcrest/proguard.flags
@@ -0,0 +1 @@
+-dontobfuscate
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index 6fb6d6a..829cfdfe 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -203,9 +203,11 @@
   }
 
   # Required for component builds. See http://crbug.com/172800.
-  if (is_component_build && (!is_linux || is_chromeos)) {
+  if (is_component_build) {
     public_configs += [ ":protobuf_use_dlls" ]
-    defines = [ "LIBPROTOBUF_EXPORTS" ]
+    if (!is_linux || is_chromeos) {
+      defines = [ "LIBPROTOBUF_EXPORTS" ]
+    }
   }
 }
 
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index edb4d6f..3d69cc4 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -29,10 +29,13 @@
 5. Extract all globals to src/google/protobuf/globals.cc and prefix these
    symbols with 'cr_'.  On Linux, the command
 
-   $ objdump -t -j.data -j.bss obj/third_party/protobuf/libprotobuf_lite.a
+   $ objdump -t -j.data -j.bss -j.tdata -j.tbss \
+     obj/third_party/protobuf/libprotobuf_lite.a
 
    should produce the output
 
+   objdump: section '.tbss' mentioned in a -j option, but not found in any input file
+   objdump: section '.tdata' mentioned in a -j option, but not found in any input file
    objdump: section '.bss' mentioned in a -j option, but not found in any input file
    objdump: section '.data' mentioned in a -j option, but not found in any input file
 
diff --git a/third_party/protobuf/patches/0012-extract-globals.patch b/third_party/protobuf/patches/0012-extract-globals.patch
index f2c899a..6521c60 100644
--- a/third_party/protobuf/patches/0012-extract-globals.patch
+++ b/third_party/protobuf/patches/0012-extract-globals.patch
@@ -1,15 +1,26 @@
 diff -ru --new-file protobuf/src/google/protobuf/arena.cc protobuf2/src/google/protobuf/arena.cc
---- protobuf/src/google/protobuf/arena.cc	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/arena.cc	2017-03-17 22:40:52.667151339 -0700
-@@ -39,7 +39,6 @@
+--- protobuf/src/google/protobuf/arena.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/arena.cc	2017-03-21 21:50:11.671241466 -0700
+@@ -39,24 +39,18 @@
  namespace protobuf {
  
  
 -google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_;
  #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
- Arena::ThreadCache& Arena::thread_cache() {
+-Arena::ThreadCache& Arena::thread_cache() {
++Arena::ThreadCache& Arena::cr_thread_cache() {
    static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
-@@ -56,7 +55,7 @@
+       new internal::ThreadLocalStorage<ThreadCache>();
+   return *thread_cache_->Get();
+ }
+-#elif defined(PROTOBUF_USE_DLLS)
+-Arena::ThreadCache& Arena::thread_cache() {
+-  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
+-  return thread_cache_;
+-}
+-#else
++#elif !defined(PROTOBUF_USE_DLLS)
+ GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
  #endif
  
  void Arena::Init() {
@@ -18,7 +29,16 @@
    blocks_ = 0;
    hint_ = 0;
    owns_first_block_ = true;
-@@ -99,7 +98,7 @@
+@@ -74,7 +68,7 @@
+     // Thread which calls Init() owns the first block. This allows the
+     // single-threaded case to allocate on the first block without taking any
+     // locks.
+-    first_block->owner = &thread_cache();
++    first_block->owner = &cr_thread_cache();
+     SetThreadCacheBlock(first_block);
+     AddBlockInternal(first_block);
+     owns_first_block_ = false;
+@@ -99,7 +93,7 @@
  
  uint64 Arena::Reset() {
    // Invalidate any ThreadCaches pointing to any blocks we just destroyed.
@@ -27,9 +47,51 @@
    return ResetInternal();
  }
  
+@@ -184,18 +178,18 @@
+   // If this thread already owns a block in this arena then try to use that.
+   // This fast path optimizes the case where multiple threads allocate from the
+   // same arena.
+-  if (thread_cache().last_lifecycle_id_seen == lifecycle_id_ &&
+-      thread_cache().last_block_used_ != NULL) {
+-    if (thread_cache().last_block_used_->avail() < n) {
++  if (cr_thread_cache().last_lifecycle_id_seen == lifecycle_id_ &&
++      cr_thread_cache().last_block_used_ != NULL) {
++    if (cr_thread_cache().last_block_used_->avail() < n) {
+       return SlowAlloc(n);
+     }
+-    return AllocFromBlock(thread_cache().last_block_used_, n);
++    return AllocFromBlock(cr_thread_cache().last_block_used_, n);
+   }
+ 
+   // Check whether we own the last accessed block on this arena.
+   // This fast path optimizes the case where a single thread uses multiple
+   // arenas.
+-  void* me = &thread_cache();
++  void* me = &cr_thread_cache();
+   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
+   if (!b || b->owner != me || b->avail() < n) {
+     return SlowAlloc(n);
+@@ -213,7 +207,7 @@
+ }
+ 
+ void* Arena::SlowAlloc(size_t n) {
+-  void* me = &thread_cache();
++  void* me = &cr_thread_cache();
+   Block* b = FindBlock(me);  // Find block owned by me.
+   // See if allocation fits in my latest block.
+   if (b != NULL && b->avail() >= n) {
+@@ -290,7 +284,7 @@
+     // Thread which calls Reset() owns the first block. This allows the
+     // single-threaded case to allocate on the first block without taking any
+     // locks.
+-    first_block->owner = &thread_cache();
++    first_block->owner = &cr_thread_cache();
+     SetThreadCacheBlock(first_block);
+     AddBlockInternal(first_block);
+   }
 diff -ru --new-file protobuf/src/google/protobuf/arena.h protobuf2/src/google/protobuf/arena.h
---- protobuf/src/google/protobuf/arena.h	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/arena.h	2017-03-17 22:40:52.667151339 -0700
+--- protobuf/src/google/protobuf/arena.h	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/arena.h	2017-03-21 21:50:11.671241466 -0700
 @@ -70,6 +70,9 @@
  template<typename Type>
  class GenericTypeHandler; // repeated_field.h
@@ -40,7 +102,7 @@
  // Templated cleanup methods.
  template<typename T> void arena_destruct_object(void* object) {
    reinterpret_cast<T*>(object)->~T();
-@@ -552,7 +555,6 @@
+@@ -552,19 +555,20 @@
    };
  
    static const size_t kHeaderSize = sizeof(Block);
@@ -48,9 +110,37 @@
  #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
    // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
    // local storage class we implemented.
+   // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
+-  static ThreadCache& thread_cache();
++  static ThreadCache& cr_thread_cache();
+ #elif defined(PROTOBUF_USE_DLLS)
+   // Thread local variables cannot be exposed through DLL interface but we can
+   // wrap them in static functions.
+-  static ThreadCache& thread_cache();
++  static ThreadCache& cr_thread_cache();
+ #else
+   static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
+-  static ThreadCache& thread_cache() { return thread_cache_; }
++  static ThreadCache& cr_thread_cache() {
++    return thread_cache_;
++  }
+ #endif
+ 
+   // SFINAE for skipping addition to delete list for a message type when created
+@@ -872,8 +876,8 @@
+   uint64 ResetInternal();
+ 
+   inline void SetThreadCacheBlock(Block* block) {
+-    thread_cache().last_block_used_ = block;
+-    thread_cache().last_lifecycle_id_seen = lifecycle_id_;
++    cr_thread_cache().last_block_used_ = block;
++    cr_thread_cache().last_lifecycle_id_seen = lifecycle_id_;
+   }
+ 
+   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
 diff -ru --new-file protobuf/src/google/protobuf/extension_set.cc protobuf2/src/google/protobuf/extension_set.cc
---- protobuf/src/google/protobuf/extension_set.cc	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/extension_set.cc	2017-03-17 22:40:52.667151339 -0700
+--- protobuf/src/google/protobuf/extension_set.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/extension_set.cc	2017-03-21 21:50:11.671241466 -0700
 @@ -46,6 +46,12 @@
  namespace protobuf {
  namespace internal {
@@ -200,8 +290,8 @@
  }  // namespace protobuf
  }  // namespace google
 diff -ru --new-file protobuf/src/google/protobuf/extension_set.h protobuf2/src/google/protobuf/extension_set.h
---- protobuf/src/google/protobuf/extension_set.h	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/extension_set.h	2017-03-17 22:40:52.675151341 -0700
+--- protobuf/src/google/protobuf/extension_set.h	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/extension_set.h	2017-03-21 21:50:11.679241474 -0700
 @@ -731,13 +731,13 @@
    template<typename Type> friend class RepeatedPrimitiveTypeTraits;
    static void InitializeDefaultRepeatedFields();
@@ -282,8 +372,8 @@
  
  // -------------------------------------------------------------------
 diff -ru --new-file protobuf/src/google/protobuf/generated_message_util.cc protobuf2/src/google/protobuf/generated_message_util.cc
---- protobuf/src/google/protobuf/generated_message_util.cc	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/generated_message_util.cc	2017-03-17 22:40:52.691151345 -0700
+--- protobuf/src/google/protobuf/generated_message_util.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/generated_message_util.cc	2017-03-21 21:50:11.695241487 -0700
 @@ -48,20 +48,18 @@
    return std::numeric_limits<double>::quiet_NaN();
  }
@@ -310,8 +400,8 @@
  }
  
 diff -ru --new-file protobuf/src/google/protobuf/generated_message_util.h protobuf2/src/google/protobuf/generated_message_util.h
---- protobuf/src/google/protobuf/generated_message_util.h	2017-03-17 22:40:59.379153132 -0700
-+++ protobuf2/src/google/protobuf/generated_message_util.h	2017-03-17 22:40:52.655151335 -0700
+--- protobuf/src/google/protobuf/generated_message_util.h	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/generated_message_util.h	2017-03-21 21:50:11.659241456 -0700
 @@ -77,14 +77,14 @@
  
  // Default empty string object. Don't use the pointer directly. Instead, call
@@ -333,8 +423,8 @@
  LIBPROTOBUF_EXPORT const ::std::string& GetEmptyString();
 diff -ru --new-file protobuf/src/google/protobuf/globals.cc protobuf2/src/google/protobuf/globals.cc
 --- protobuf/src/google/protobuf/globals.cc	1969-12-31 16:00:00.000000000 -0800
-+++ protobuf2/src/google/protobuf/globals.cc	2017-03-17 22:40:52.655151335 -0700
-@@ -0,0 +1,113 @@
++++ protobuf2/src/google/protobuf/globals.cc	2017-03-21 21:50:11.659241456 -0700
+@@ -0,0 +1,122 @@
 +// Protocol Buffers - Google's data interchange format
 +// Copyright 2017 Google Inc.  All rights reserved.
 +// https://developers.google.com/protocol-buffers/
@@ -365,6 +455,7 @@
 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 +
++#include <google/protobuf/arena.h>
 +#include <google/protobuf/extension_set.h>
 +#include <google/protobuf/generated_message_util.h>
 +#include <google/protobuf/stubs/atomicops.h>
@@ -372,6 +463,14 @@
 +
 +namespace google {
 +namespace protobuf {
++
++#if !defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) && defined(PROTOBUF_USE_DLLS)
++Arena::ThreadCache& Arena::cr_thread_cache() {
++  static GOOGLE_THREAD_LOCAL ThreadCache cr_thread_cache_ = {-1, NULL};
++  return cr_thread_cache_;
++}
++#endif
++
 +namespace internal {
 +
 +SequenceNumber cr_lifecycle_id_generator_;
@@ -449,8 +548,8 @@
 +}  // namespace protobuf
 +}  // namespace google
 diff -ru --new-file protobuf/src/google/protobuf/io/coded_stream.cc protobuf2/src/google/protobuf/io/coded_stream.cc
---- protobuf/src/google/protobuf/io/coded_stream.cc	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/io/coded_stream.cc	2017-03-17 22:40:52.659151336 -0700
+--- protobuf/src/google/protobuf/io/coded_stream.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/io/coded_stream.cc	2017-03-21 21:50:11.663241460 -0700
 @@ -83,7 +83,7 @@
  }
  
@@ -461,8 +560,8 @@
  
  void CodedOutputStream::EnableAliasing(bool enabled) {
 diff -ru --new-file protobuf/src/google/protobuf/io/coded_stream.h protobuf2/src/google/protobuf/io/coded_stream.h
---- protobuf/src/google/protobuf/io/coded_stream.h	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/io/coded_stream.h	2017-03-17 22:40:52.659151336 -0700
+--- protobuf/src/google/protobuf/io/coded_stream.h	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/io/coded_stream.h	2017-03-21 21:50:11.663241460 -0700
 @@ -613,7 +613,7 @@
  
    static const int kDefaultTotalBytesWarningThreshold = 32 << 20;  // 32MB
@@ -473,8 +572,8 @@
  
  // Class which encodes and writes binary data which is composed of varint-
 diff -ru --new-file protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc
---- protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc	2017-03-17 22:40:52.671151340 -0700
+--- protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc	2017-03-21 21:50:11.675241470 -0700
 @@ -58,23 +58,13 @@
        : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
  #endif
@@ -540,8 +639,8 @@
 -
  #endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_X86_GCC_H_
 diff -ru --new-file protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h
---- protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h	2017-03-17 22:40:52.671151340 -0700
+--- protobuf/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/stubs/atomicops_internals_x86_gcc.h	2017-03-21 21:50:11.675241470 -0700
 @@ -46,7 +46,9 @@
                               // after acquire compare-and-swap.
    bool has_sse2;             // Processor has SSE2.
@@ -608,8 +707,8 @@
    }
    return x;
 diff -ru --new-file protobuf/src/google/protobuf/stubs/common.cc protobuf2/src/google/protobuf/stubs/common.cc
---- protobuf/src/google/protobuf/stubs/common.cc	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/stubs/common.cc	2017-03-17 22:40:52.671151340 -0700
+--- protobuf/src/google/protobuf/stubs/common.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/stubs/common.cc	2017-03-21 21:50:11.675241470 -0700
 @@ -116,7 +116,8 @@
    if (level < GOOGLE_PROTOBUF_MIN_LOG_LEVEL) {
      return;
@@ -777,8 +876,8 @@
  
  #if PROTOBUF_USE_EXCEPTIONS
 diff -ru --new-file protobuf/src/google/protobuf/stubs/structurally_valid.cc protobuf2/src/google/protobuf/stubs/structurally_valid.cc
---- protobuf/src/google/protobuf/stubs/structurally_valid.cc	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/stubs/structurally_valid.cc	2017-03-17 22:40:52.675151341 -0700
+--- protobuf/src/google/protobuf/stubs/structurally_valid.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/stubs/structurally_valid.cc	2017-03-21 21:50:11.679241474 -0700
 @@ -511,21 +511,10 @@
  //   UTF-8 strings.  Since UTF-8 validation is only used for debugging
  //   anyway, we simply always return success if initialization hasn't
@@ -813,8 +912,8 @@
    int bytes_consumed = 0;
    UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
 diff -ru --new-file protobuf/src/google/protobuf/stubs/strutil.cc protobuf2/src/google/protobuf/stubs/strutil.cc
---- protobuf/src/google/protobuf/stubs/strutil.cc	2017-03-17 22:40:59.383153133 -0700
-+++ protobuf2/src/google/protobuf/stubs/strutil.cc	2017-03-17 22:40:52.671151340 -0700
+--- protobuf/src/google/protobuf/stubs/strutil.cc	2017-03-21 21:50:28.399255503 -0700
++++ protobuf2/src/google/protobuf/stubs/strutil.cc	2017-03-21 21:50:11.675241470 -0700
 @@ -528,7 +528,7 @@
  // Assumes that non-printable characters are escaped using octal sequences, and
  // that UTF-8 bytes are not handled specially.
diff --git a/third_party/protobuf/src/google/protobuf/arena.cc b/third_party/protobuf/src/google/protobuf/arena.cc
index 40a15cc..3ce17e3 100755
--- a/third_party/protobuf/src/google/protobuf/arena.cc
+++ b/third_party/protobuf/src/google/protobuf/arena.cc
@@ -40,17 +40,12 @@
 
 
 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
-Arena::ThreadCache& Arena::thread_cache() {
+Arena::ThreadCache& Arena::cr_thread_cache() {
   static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ =
       new internal::ThreadLocalStorage<ThreadCache>();
   return *thread_cache_->Get();
 }
-#elif defined(PROTOBUF_USE_DLLS)
-Arena::ThreadCache& Arena::thread_cache() {
-  static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL };
-  return thread_cache_;
-}
-#else
+#elif !defined(PROTOBUF_USE_DLLS)
 GOOGLE_THREAD_LOCAL Arena::ThreadCache Arena::thread_cache_ = { -1, NULL };
 #endif
 
@@ -73,7 +68,7 @@
     // Thread which calls Init() owns the first block. This allows the
     // single-threaded case to allocate on the first block without taking any
     // locks.
-    first_block->owner = &thread_cache();
+    first_block->owner = &cr_thread_cache();
     SetThreadCacheBlock(first_block);
     AddBlockInternal(first_block);
     owns_first_block_ = false;
@@ -183,18 +178,18 @@
   // If this thread already owns a block in this arena then try to use that.
   // This fast path optimizes the case where multiple threads allocate from the
   // same arena.
-  if (thread_cache().last_lifecycle_id_seen == lifecycle_id_ &&
-      thread_cache().last_block_used_ != NULL) {
-    if (thread_cache().last_block_used_->avail() < n) {
+  if (cr_thread_cache().last_lifecycle_id_seen == lifecycle_id_ &&
+      cr_thread_cache().last_block_used_ != NULL) {
+    if (cr_thread_cache().last_block_used_->avail() < n) {
       return SlowAlloc(n);
     }
-    return AllocFromBlock(thread_cache().last_block_used_, n);
+    return AllocFromBlock(cr_thread_cache().last_block_used_, n);
   }
 
   // Check whether we own the last accessed block on this arena.
   // This fast path optimizes the case where a single thread uses multiple
   // arenas.
-  void* me = &thread_cache();
+  void* me = &cr_thread_cache();
   Block* b = reinterpret_cast<Block*>(google::protobuf::internal::Acquire_Load(&hint_));
   if (!b || b->owner != me || b->avail() < n) {
     return SlowAlloc(n);
@@ -212,7 +207,7 @@
 }
 
 void* Arena::SlowAlloc(size_t n) {
-  void* me = &thread_cache();
+  void* me = &cr_thread_cache();
   Block* b = FindBlock(me);  // Find block owned by me.
   // See if allocation fits in my latest block.
   if (b != NULL && b->avail() >= n) {
@@ -289,7 +284,7 @@
     // Thread which calls Reset() owns the first block. This allows the
     // single-threaded case to allocate on the first block without taking any
     // locks.
-    first_block->owner = &thread_cache();
+    first_block->owner = &cr_thread_cache();
     SetThreadCacheBlock(first_block);
     AddBlockInternal(first_block);
   }
diff --git a/third_party/protobuf/src/google/protobuf/arena.h b/third_party/protobuf/src/google/protobuf/arena.h
index 72d8a9d..2836a618 100644
--- a/third_party/protobuf/src/google/protobuf/arena.h
+++ b/third_party/protobuf/src/google/protobuf/arena.h
@@ -559,14 +559,16 @@
   // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
   // local storage class we implemented.
   // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
-  static ThreadCache& thread_cache();
+  static ThreadCache& cr_thread_cache();
 #elif defined(PROTOBUF_USE_DLLS)
   // Thread local variables cannot be exposed through DLL interface but we can
   // wrap them in static functions.
-  static ThreadCache& thread_cache();
+  static ThreadCache& cr_thread_cache();
 #else
   static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
-  static ThreadCache& thread_cache() { return thread_cache_; }
+  static ThreadCache& cr_thread_cache() {
+    return thread_cache_;
+  }
 #endif
 
   // SFINAE for skipping addition to delete list for a message type when created
@@ -874,8 +876,8 @@
   uint64 ResetInternal();
 
   inline void SetThreadCacheBlock(Block* block) {
-    thread_cache().last_block_used_ = block;
-    thread_cache().last_lifecycle_id_seen = lifecycle_id_;
+    cr_thread_cache().last_block_used_ = block;
+    cr_thread_cache().last_lifecycle_id_seen = lifecycle_id_;
   }
 
   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
diff --git a/third_party/protobuf/src/google/protobuf/globals.cc b/third_party/protobuf/src/google/protobuf/globals.cc
index f4122734..31fb6ba9 100644
--- a/third_party/protobuf/src/google/protobuf/globals.cc
+++ b/third_party/protobuf/src/google/protobuf/globals.cc
@@ -28,6 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <google/protobuf/arena.h>
 #include <google/protobuf/extension_set.h>
 #include <google/protobuf/generated_message_util.h>
 #include <google/protobuf/stubs/atomicops.h>
@@ -35,6 +36,14 @@
 
 namespace google {
 namespace protobuf {
+
+#if !defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) && defined(PROTOBUF_USE_DLLS)
+Arena::ThreadCache& Arena::cr_thread_cache() {
+  static GOOGLE_THREAD_LOCAL ThreadCache cr_thread_cache_ = {-1, NULL};
+  return cr_thread_cache_;
+}
+#endif
+
 namespace internal {
 
 SequenceNumber cr_lifecycle_id_generator_;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f5f8b16d4..69a00de 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -93871,6 +93871,7 @@
   <int value="1867" label="CSSOverflowPaged"/>
   <int value="1868" label="ChildSrcAllowedWorkerThatScriptSrcBlocked"/>
   <int value="1869" label="HTMLTableElementPresentationAttributeBackground"/>
+  <int value="1870" label="V8Navigator_GetInstalledRelatedApps_Method"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -99837,6 +99838,7 @@
   <int value="-1052415111" label="malware-interstitial-v2"/>
   <int value="-1052219252" label="disable-captive-portal-bypass-proxy"/>
   <int value="-1045900007" label="NoCreditCardAbort:disabled"/>
+  <int value="-1045882995" label="UseNewDoodleApi:enabled"/>
   <int value="-1041650038" label="enable-forced-migration-to-tabbed-mode"/>
   <int value="-1039889738" label="NativeNotifications:enabled"/>
   <int value="-1039555838" label="GamepadExtensions:enabled"/>
@@ -99907,6 +99909,7 @@
   <int value="-795600188" label="disable-async-dns"/>
   <int value="-790036192" label="overscroll-start-threshold"/>
   <int value="-780798969" label="disable-single-click-autofill"/>
+  <int value="-775321548" label="UseNewDoodleApi:disabled"/>
   <int value="-770319039" label="enable-touch-editing"/>
   <int value="-763759697" label="enable-audio-support-for-desktop-share"/>
   <int value="-759830869" label="enable-tab-discarding"/>
@@ -123017,6 +123020,15 @@
   <affected-histogram name="WebRTC.Stun.SuccessPercent.UnknownNAT"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="SubresourceFilterOnlyExperiment" separator=".">
+  <suffix name="SocialEngineeringAdsInterstitial"
+      label="social eng ad blacklist pattern"/>
+  <suffix name="PhishingInterstitial" label="phishing blacklist pattern"/>
+  <affected-histogram name="SubresourceFilter.PageLoad.RedirectChainLength"/>
+  <affected-histogram
+      name="SubresourceFilter.PageLoad.RedirectChainMatchPattern"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="SyncModelType" separator=".">
   <suffix name="APP" label="APP"/>
   <suffix name="APP_LIST" label="APP_LIST"/>
diff --git a/ui/arc/notification/arc_custom_notification_item.cc b/ui/arc/notification/arc_custom_notification_item.cc
index d3cac1be..f44884d 100644
--- a/ui/arc/notification/arc_custom_notification_item.cc
+++ b/ui/arc/notification/arc_custom_notification_item.cc
@@ -39,6 +39,8 @@
 
   void Close(bool by_user) override { item_->Close(by_user); }
 
+  void Click() override { item_->Click(); }
+
  private:
   // The destructor is private since this class is ref-counted.
   ~ArcNotificationDelegate() override {}
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index 85c3234..edb2346 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -161,6 +161,11 @@
   return false;
 }
 
+bool GLSurface::SetEnableDCLayers(bool enable) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 bool GLSurface::IsSurfaceless() const {
   return false;
 }
@@ -173,7 +178,7 @@
   return false;
 }
 
-bool GLSurface::SupportsSetDrawRectangle() const {
+bool GLSurface::SupportsDCLayers() const {
   return false;
 }
 
@@ -359,6 +364,10 @@
   return surface_->ScheduleDCLayer(params);
 }
 
+bool GLSurfaceAdapter::SetEnableDCLayers(bool enable) {
+  return surface_->SetEnableDCLayers(enable);
+}
+
 bool GLSurfaceAdapter::IsSurfaceless() const {
   return surface_->IsSurfaceless();
 }
@@ -371,8 +380,8 @@
   return surface_->BuffersFlipped();
 }
 
-bool GLSurfaceAdapter::SupportsSetDrawRectangle() const {
-  return surface_->SupportsSetDrawRectangle();
+bool GLSurfaceAdapter::SupportsDCLayers() const {
+  return surface_->SupportsDCLayers();
 }
 
 bool GLSurfaceAdapter::SetDrawRectangle(const gfx::Rect& rect) {
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 56d9a1c5..4287ad2 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -201,6 +201,8 @@
 
   virtual bool ScheduleDCLayer(const ui::DCRendererLayerParams& params);
 
+  virtual bool SetEnableDCLayers(bool enable);
+
   virtual bool IsSurfaceless() const;
 
   virtual bool FlipsVertically() const;
@@ -209,7 +211,7 @@
   // the next buffer may be 2 frames old.
   virtual bool BuffersFlipped() const;
 
-  virtual bool SupportsSetDrawRectangle() const;
+  virtual bool SupportsDCLayers() const;
 
   // Set the rectangle that will be drawn into on the surface.
   virtual bool SetDrawRectangle(const gfx::Rect& rect);
@@ -286,10 +288,11 @@
                             const gfx::Rect& bounds_rect,
                             const gfx::RectF& crop_rect) override;
   bool ScheduleDCLayer(const ui::DCRendererLayerParams& params) override;
+  bool SetEnableDCLayers(bool enable) override;
   bool IsSurfaceless() const override;
   bool FlipsVertically() const override;
   bool BuffersFlipped() const override;
-  bool SupportsSetDrawRectangle() const override;
+  bool SupportsDCLayers() const override;
   bool SetDrawRectangle(const gfx::Rect& rect) override;
   gfx::Vector2d GetDrawOffset() const override;
   void OnSetSwapInterval(int interval) override;
diff --git a/ui/gl/gl_surface_stub.cc b/ui/gl/gl_surface_stub.cc
index 857a4ef..6f93fa8 100644
--- a/ui/gl/gl_surface_stub.cc
+++ b/ui/gl/gl_surface_stub.cc
@@ -39,7 +39,7 @@
   return GLSurfaceFormat();
 }
 
-bool GLSurfaceStub::SupportsSetDrawRectangle() const {
+bool GLSurfaceStub::SupportsDCLayers() const {
   return supports_draw_rectangle_;
 }
 
diff --git a/ui/gl/gl_surface_stub.h b/ui/gl/gl_surface_stub.h
index 87f55655..7e11a9df 100644
--- a/ui/gl/gl_surface_stub.h
+++ b/ui/gl/gl_surface_stub.h
@@ -31,7 +31,7 @@
   void* GetHandle() override;
   bool BuffersFlipped() const override;
   GLSurfaceFormat GetFormat() override;
-  bool SupportsSetDrawRectangle() const override;
+  bool SupportsDCLayers() const override;
   gfx::Vector2d GetDrawOffset() const override;
 
  protected: