diff --git a/DEPS b/DEPS
index b6950687..02ae826 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '5ac0930fac8e3478d7208f942bbe4fd2b43a203d',
+  'v8_revision': 'a5ee59a9d7ab97a46345f11332ceb3783c90978d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'db124cff7ebb0b751fe86ca447dbee31363a64be',
+  'pdfium_revision': '7dee685df0309401ad37c30c49a56d8523d1f8bb',
   # 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': '264d6b2ebb8b5926f7ef4610088ef42d64542321',
+  'catapult_revision': 'dc460e541ad9d8ce33e8adc3aa46bd283ee26e39',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -199,7 +199,7 @@
     Var('chromium_git') + '/external/bidichecker/lib.git' + '@' + '97f2aa645b74c28c57eca56992235c79850fa9e0',
 
   'src/third_party/webgl/src':
-    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '9422979e2a13b6d80de866a271a34653998d4c85',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '331fe3a462b2e1f5c9baa1a710312a1b5888e404',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/android_webview/browser/surfaces_instance.cc b/android_webview/browser/surfaces_instance.cc
index a04bf5f5..7520a12 100644
--- a/android_webview/browser/surfaces_instance.cc
+++ b/android_webview/browser/surfaces_instance.cc
@@ -73,13 +73,17 @@
           DeferredGpuCommandService::GetInstance())));
   output_surface_ = output_surface_holder.get();
   std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
-      nullptr, output_surface_holder->capabilities().max_frames_pending));
+      begin_frame_source_.get(), nullptr,
+      output_surface_holder->capabilities().max_frames_pending));
   display_.reset(new cc::Display(
       nullptr /* shared_bitmap_manager */,
       nullptr /* gpu_memory_buffer_manager */, settings, frame_sink_id_,
-      begin_frame_source_.get(), std::move(output_surface_holder),
-      std::move(scheduler), std::move(texture_mailbox_deleter)));
+      std::move(output_surface_holder), std::move(scheduler),
+      std::move(texture_mailbox_deleter)));
   display_->Initialize(this, surface_manager_.get());
+  surface_manager_->RegisterBeginFrameSource(begin_frame_source_.get(),
+                                             frame_sink_id_);
+
   display_->SetVisible(true);
 
   DCHECK(!g_surfaces_instance);
@@ -88,6 +92,7 @@
 
 SurfacesInstance::~SurfacesInstance() {
   DCHECK_EQ(g_surfaces_instance, this);
+  surface_manager_->UnregisterBeginFrameSource(begin_frame_source_.get());
   g_surfaces_instance = nullptr;
   DCHECK(child_ids_.empty());
 }
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 7304bd8..c11b9eb 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -1133,10 +1133,21 @@
     UpdateDragIconProxy(screen_location);
     return true;
   }
-  // Check if we are too far away from the shelf to enter the ripped off state.
-  // Determine the distance to the shelf.
+
+  // Mark the item as dragged off the shelf if the drag distance exceeds
+  // |kRipOffDistance|, or if it's dragged between the main and overflow shelf.
   int delta = CalculateShelfDistance(screen_location);
-  if (delta > kRipOffDistance) {
+  bool dragged_off_shelf = delta > kRipOffDistance;
+  dragged_off_shelf |=
+      (is_overflow_mode() &&
+       main_shelf_->GetBoundsForDragInsertInScreen().Contains(screen_location));
+  dragged_off_shelf |= (!is_overflow_mode() && overflow_bubble_ &&
+                        overflow_bubble_->IsShowing() &&
+                        overflow_bubble_->shelf_view()
+                            ->GetBoundsForDragInsertInScreen()
+                            .Contains(screen_location));
+
+  if (dragged_off_shelf) {
     // Create a proxy view item which can be moved anywhere.
     CreateDragIconProxy(event.root_location(), drag_view_->GetImage(),
                         drag_view_, gfx::Vector2d(0, 0),
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index 6b40462..361a947 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -1256,6 +1256,73 @@
   ASSERT_EQ(ShelfButton::STATE_ATTENTION, button->state());
 }
 
+// Test what drag movements will rip an item off the shelf.
+TEST_F(ShelfViewTest, ShelfRipOff) {
+  ui::test::EventGenerator& generator = GetEventGenerator();
+
+  // The test makes some assumptions that the shelf is bottom aligned.
+  ASSERT_EQ(test_api_->shelf_view()->shelf()->alignment(),
+            SHELF_ALIGNMENT_BOTTOM);
+
+  // The rip off threshold. Taken from |kRipOffDistance| in shelf_view.cc.
+  const int kRipOffDistance = 48;
+
+  // Add two apps (which is on the main shelf) and then add buttons until
+  // overflow. Add one more app (which is on the overflow shelf).
+  ShelfID first_app_id = AddAppShortcut();
+  ShelfID second_app_id = AddAppShortcut();
+  AddButtonsUntilOverflow();
+  ShelfID overflow_app_id = AddAppShortcut();
+
+  // Verify that dragging an app off the shelf will trigger the app getting
+  // ripped off, unless the distance is less than |kRipOffDistance|.
+  gfx::Point first_app_location = GetButtonCenter(GetButtonByID(first_app_id));
+  generator.set_current_location(first_app_location);
+  generator.PressLeftButton();
+  // Drag the mouse to just off the shelf.
+  generator.MoveMouseBy(0, -kShelfSize / 2 - 1);
+  EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
+  // Drag the mouse past the rip off threshold.
+  generator.MoveMouseBy(0, -kRipOffDistance);
+  EXPECT_TRUE(test_api_->IsRippedOffFromShelf());
+  // Drag the mouse back to the original position, so that the app does not get
+  // deleted.
+  generator.MoveMouseTo(first_app_location);
+  generator.ReleaseLeftButton();
+  EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
+
+  // Open overflow shelf and test api for it.
+  test_api_->ShowOverflowBubble();
+  ASSERT_TRUE(test_api_->IsShowingOverflowBubble());
+  ShelfViewTestAPI test_api_for_overflow(
+      test_api_->overflow_bubble()->shelf_view());
+
+  // Verify that when an app from the main shelf is dragged to a location on the
+  // overflow shelf, it is ripped off.
+  gfx::Point second_app_location =
+      GetButtonCenter(GetButtonByID(second_app_id));
+  gfx::Point overflow_app_location = GetButtonCenter(
+      test_api_for_overflow.GetButton(model_->ItemIndexByID(overflow_app_id)));
+  generator.set_current_location(second_app_location);
+  generator.PressLeftButton();
+  generator.MoveMouseTo(overflow_app_location);
+  EXPECT_TRUE(test_api_->IsRippedOffFromShelf());
+  generator.MoveMouseTo(second_app_location);
+  generator.ReleaseLeftButton();
+  EXPECT_FALSE(test_api_->IsRippedOffFromShelf());
+
+  // Verify that when an app from the overflow shelf is dragged to a location on
+  // the main shelf, it is ripped off.
+  ASSERT_TRUE(test_api_->IsShowingOverflowBubble());
+  generator.set_current_location(overflow_app_location);
+  generator.PressLeftButton();
+  generator.MoveMouseTo(second_app_location);
+  EXPECT_TRUE(test_api_for_overflow.IsRippedOffFromShelf());
+  generator.MoveMouseTo(overflow_app_location);
+  generator.ReleaseLeftButton();
+  EXPECT_FALSE(test_api_for_overflow.IsRippedOffFromShelf());
+}
+
 // Confirm that item status changes are reflected in the buttons
 // for platform apps.
 TEST_F(ShelfViewTest, ShelfItemStatusPlatformApp) {
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 34eda97f..6fc30a0 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -152,7 +152,16 @@
 void SoftwareRenderer::ClearCanvas(SkColor color) {
   if (!current_canvas_)
     return;
-  current_canvas_->clear(color);
+
+  if (is_scissor_enabled_) {
+    // The same paint used by SkCanvas::clear, but applied to the scissor rect.
+    SkPaint clear_paint;
+    clear_paint.setColor(color);
+    clear_paint.setBlendMode(SkBlendMode::kSrc);
+    current_canvas_->drawRect(gfx::RectToSkRect(scissor_rect_), clear_paint);
+  } else {
+    current_canvas_->clear(color);
+  }
 }
 
 void SoftwareRenderer::ClearFramebuffer() {
diff --git a/cc/surfaces/direct_compositor_frame_sink_unittest.cc b/cc/surfaces/direct_compositor_frame_sink_unittest.cc
index f295ab0..a56be81 100644
--- a/cc/surfaces/direct_compositor_frame_sink_unittest.cc
+++ b/cc/surfaces/direct_compositor_frame_sink_unittest.cc
@@ -56,13 +56,13 @@
         base::MakeUnique<DelayBasedTimeSource>(task_runner_.get())));
 
     int max_frames_pending = 2;
-    std::unique_ptr<DisplayScheduler> scheduler(
-        new DisplayScheduler(task_runner_.get(), max_frames_pending));
+    std::unique_ptr<DisplayScheduler> scheduler(new DisplayScheduler(
+        begin_frame_source_.get(), task_runner_.get(), max_frames_pending));
 
     display_.reset(new Display(
         &bitmap_manager_, &gpu_memory_buffer_manager_, RendererSettings(),
-        kArbitraryFrameSinkId, begin_frame_source_.get(),
-        std::move(display_output_surface), std::move(scheduler),
+        kArbitraryFrameSinkId, std::move(display_output_surface),
+        std::move(scheduler),
         base::MakeUnique<TextureMailboxDeleter>(task_runner_.get())));
     compositor_frame_sink_.reset(new TestDirectCompositorFrameSink(
         kArbitraryFrameSinkId, &surface_manager_, display_.get(),
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index afcc23d..a9c5358e 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -37,7 +37,6 @@
                  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
                  const RendererSettings& settings,
                  const FrameSinkId& frame_sink_id,
-                 BeginFrameSource* begin_frame_source,
                  std::unique_ptr<OutputSurface> output_surface,
                  std::unique_ptr<DisplayScheduler> scheduler,
                  std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter)
@@ -45,17 +44,13 @@
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       settings_(settings),
       frame_sink_id_(frame_sink_id),
-      begin_frame_source_(begin_frame_source),
       output_surface_(std::move(output_surface)),
       scheduler_(std::move(scheduler)),
       texture_mailbox_deleter_(std::move(texture_mailbox_deleter)) {
   DCHECK(output_surface_);
-  DCHECK_EQ(!scheduler_, !begin_frame_source_);
   DCHECK(frame_sink_id_.is_valid());
-  if (scheduler_) {
+  if (scheduler_)
     scheduler_->SetClient(this);
-    scheduler_->SetBeginFrameSource(begin_frame_source);
-  }
 }
 
 Display::~Display() {
@@ -63,9 +58,8 @@
   if (client_) {
     if (auto* context = output_surface_->context_provider())
       context->SetLostContextCallback(base::Closure());
-    if (begin_frame_source_)
-      surface_manager_->UnregisterBeginFrameSource(begin_frame_source_);
-    surface_manager_->RemoveObserver(this);
+    if (scheduler_)
+      surface_manager_->RemoveObserver(scheduler_.get());
   }
   if (aggregator_) {
     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
@@ -82,15 +76,8 @@
   DCHECK(surface_manager);
   client_ = client;
   surface_manager_ = surface_manager;
-
-  surface_manager_->AddObserver(this);
-
-  // This must be done in Initialize() so that the caller can delay this until
-  // they are ready to receive a BeginFrameSource.
-  if (begin_frame_source_) {
-    surface_manager_->RegisterBeginFrameSource(begin_frame_source_,
-                                               frame_sink_id_);
-  }
+  if (scheduler_)
+    surface_manager_->AddObserver(scheduler_.get());
 
   output_surface_->BindToClient(this);
   InitializeRenderer();
@@ -384,12 +371,12 @@
   if (scheduler_) {
     BeginFrameAck ack;
     ack.has_damage = true;
-    scheduler_->SurfaceDamaged(current_surface_id_, ack, true);
+    scheduler_->ProcessSurfaceDamage(current_surface_id_, ack, true);
   }
 }
 
-bool Display::OnSurfaceDamaged(const SurfaceId& surface_id,
-                               const BeginFrameAck& ack) {
+bool Display::SurfaceDamaged(const SurfaceId& surface_id,
+                             const BeginFrameAck& ack) {
   bool display_damaged = false;
   if (ack.has_damage) {
     if (aggregator_ &&
@@ -409,11 +396,14 @@
     }
   }
 
-  if (scheduler_)
-    scheduler_->SurfaceDamaged(surface_id, ack, display_damaged);
   return display_damaged;
 }
 
+void Display::SurfaceDiscarded(const SurfaceId& surface_id) {
+  if (aggregator_)
+    aggregator_->ReleaseResources(surface_id);
+}
+
 bool Display::SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const {
   if (!surface_manager_)
     return false;
@@ -425,27 +415,6 @@
   return surface->HasUndrawnActiveFrame();
 }
 
-void Display::OnSurfaceCreated(const SurfaceInfo& surface_info) {
-  if (scheduler_)
-    scheduler_->SurfaceCreated(surface_info);
-}
-
-void Display::OnSurfaceDestroyed(const SurfaceId& surface_id) {
-  if (scheduler_)
-    scheduler_->SurfaceDestroyed(surface_id);
-}
-
-void Display::OnSurfaceDamageExpected(const SurfaceId& surface_id,
-                                      const BeginFrameArgs& args) {
-  if (scheduler_)
-    scheduler_->SurfaceDamageExpected(surface_id, args);
-}
-
-void Display::OnSurfaceDiscarded(const SurfaceId& surface_id) {
-  if (aggregator_)
-    aggregator_->ReleaseResources(surface_id);
-}
-
 const SurfaceId& Display::CurrentSurfaceId() {
   return current_surface_id_;
 }
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 610588f..b96abb6 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -32,7 +32,6 @@
 
 namespace cc {
 
-class BeginFrameSource;
 class DirectRenderer;
 class DisplayClient;
 class OutputSurface;
@@ -46,8 +45,7 @@
 // (OutputSurface). The client is responsible for creating and sizing the
 // surface IDs used to draw into the display and deciding when to draw.
 class CC_SURFACES_EXPORT Display : public DisplaySchedulerClient,
-                                   public OutputSurfaceClient,
-                                   public SurfaceObserver {
+                                   public OutputSurfaceClient {
  public:
   // The |begin_frame_source| and |scheduler| may be null (together). In that
   // case, DrawAndSwap must be called externally when needed.
@@ -55,7 +53,6 @@
           gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
           const RendererSettings& settings,
           const FrameSinkId& frame_sink_id,
-          BeginFrameSource* begin_frame_source,
           std::unique_ptr<OutputSurface> output_surface,
           std::unique_ptr<DisplayScheduler> scheduler,
           std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter);
@@ -78,6 +75,9 @@
   // DisplaySchedulerClient implementation.
   bool DrawAndSwap() override;
   bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const override;
+  bool SurfaceDamaged(const SurfaceId& surface_id,
+                      const BeginFrameAck& ack) override;
+  void SurfaceDiscarded(const SurfaceId& surface_id) override;
 
   // OutputSurfaceClient implementation.
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
@@ -85,15 +85,6 @@
   void DidReceiveTextureInUseResponses(
       const gpu::TextureInUseResponses& responses) override;
 
-  // SurfaceObserver implementation.
-  bool OnSurfaceDamaged(const SurfaceId& surface,
-                        const BeginFrameAck& ack) override;
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
-  void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
-  void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
-  void OnSurfaceDamageExpected(const SurfaceId& surface_id,
-                               const BeginFrameArgs& args) override;
-
   bool has_scheduler() const { return !!scheduler_; }
   DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
 
@@ -120,9 +111,6 @@
   bool swapped_since_resize_ = false;
   bool output_is_secure_ = false;
 
-  // The begin_frame_source_ is not owned here, and also often known by the
-  // output_surface_ and the scheduler_.
-  BeginFrameSource* begin_frame_source_;
   std::unique_ptr<OutputSurface> output_surface_;
   std::unique_ptr<DisplayScheduler> scheduler_;
   std::unique_ptr<ResourceProvider> resource_provider_;
diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc
index 8265b87..75ace10c2 100644
--- a/cc/surfaces/display_scheduler.cc
+++ b/cc/surfaces/display_scheduler.cc
@@ -14,10 +14,11 @@
 
 namespace cc {
 
-DisplayScheduler::DisplayScheduler(base::SingleThreadTaskRunner* task_runner,
+DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source,
+                                   base::SingleThreadTaskRunner* task_runner,
                                    int max_pending_swaps)
     : client_(nullptr),
-      begin_frame_source_(nullptr),
+      begin_frame_source_(begin_frame_source),
       task_runner_(task_runner),
       inside_surface_damaged_(false),
       visible_(false),
@@ -44,11 +45,6 @@
   client_ = client;
 }
 
-void DisplayScheduler::SetBeginFrameSource(
-    BeginFrameSource* begin_frame_source) {
-  begin_frame_source_ = begin_frame_source;
-}
-
 void DisplayScheduler::SetVisible(bool visible) {
   if (visible_ == visible)
     return;
@@ -91,15 +87,15 @@
   root_surface_id_ = root_surface_id;
   BeginFrameAck ack;
   ack.has_damage = true;
-  SurfaceDamaged(root_surface_id, ack, true);
+  ProcessSurfaceDamage(root_surface_id, ack, true);
 }
 
 // Indicates that there was damage to one of the surfaces.
 // Has some logic to wait for multiple active surfaces before
 // triggering the deadline.
-void DisplayScheduler::SurfaceDamaged(const SurfaceId& surface_id,
-                                      const BeginFrameAck& ack,
-                                      bool display_damaged) {
+void DisplayScheduler::ProcessSurfaceDamage(const SurfaceId& surface_id,
+                                            const BeginFrameAck& ack,
+                                            bool display_damaged) {
   TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamaged", "surface_id",
                surface_id.ToString());
 
@@ -135,33 +131,6 @@
     ScheduleBeginFrameDeadline();
 }
 
-void DisplayScheduler::SurfaceCreated(const SurfaceInfo& surface_info) {
-  SurfaceId surface_id = surface_info.id();
-  DCHECK(!base::ContainsKey(surface_states_, surface_id));
-  surface_states_[surface_id] = SurfaceBeginFrameState();
-}
-
-void DisplayScheduler::SurfaceDestroyed(const SurfaceId& surface_id) {
-  auto it = surface_states_.find(surface_id);
-  if (it == surface_states_.end())
-    return;
-  surface_states_.erase(it);
-  if (UpdateHasPendingSurfaces())
-    ScheduleBeginFrameDeadline();
-}
-
-void DisplayScheduler::SurfaceDamageExpected(const SurfaceId& surface_id,
-                                             const BeginFrameArgs& args) {
-  TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamageExpected", "surface_id",
-               surface_id.ToString());
-  auto it = surface_states_.find(surface_id);
-  if (it == surface_states_.end())
-    return;
-  it->second.last_args = args;
-  if (UpdateHasPendingSurfaces())
-    ScheduleBeginFrameDeadline();
-}
-
 bool DisplayScheduler::UpdateHasPendingSurfaces() {
   // If we're not currently inside a deadline interval, we will call
   // UpdateHasPendingSurfaces() again during OnBeginFrameImpl().
@@ -306,6 +275,45 @@
     NOTIMPLEMENTED();
 }
 
+void DisplayScheduler::OnSurfaceCreated(const SurfaceInfo& surface_info) {
+  SurfaceId surface_id = surface_info.id();
+  DCHECK(!base::ContainsKey(surface_states_, surface_id));
+  surface_states_[surface_id] = SurfaceBeginFrameState();
+}
+
+void DisplayScheduler::OnSurfaceDestroyed(const SurfaceId& surface_id) {
+  auto it = surface_states_.find(surface_id);
+  if (it == surface_states_.end())
+    return;
+  surface_states_.erase(it);
+  if (UpdateHasPendingSurfaces())
+    ScheduleBeginFrameDeadline();
+}
+
+bool DisplayScheduler::OnSurfaceDamaged(const SurfaceId& surface_id,
+                                        const BeginFrameAck& ack) {
+  bool damaged = client_->SurfaceDamaged(surface_id, ack);
+  ProcessSurfaceDamage(surface_id, ack, damaged);
+
+  return damaged;
+}
+
+void DisplayScheduler::OnSurfaceDiscarded(const SurfaceId& surface_id) {
+  client_->SurfaceDiscarded(surface_id);
+}
+
+void DisplayScheduler::OnSurfaceDamageExpected(const SurfaceId& surface_id,
+                                               const BeginFrameArgs& args) {
+  TRACE_EVENT1("cc", "DisplayScheduler::SurfaceDamageExpected", "surface_id",
+               surface_id.ToString());
+  auto it = surface_states_.find(surface_id);
+  if (it == surface_states_.end())
+    return;
+  it->second.last_args = args;
+  if (UpdateHasPendingSurfaces())
+    ScheduleBeginFrameDeadline();
+}
+
 base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() {
   if (output_surface_lost_) {
     TRACE_EVENT_INSTANT0("cc", "Lost output surface", TRACE_EVENT_SCOPE_THREAD);
diff --git a/cc/surfaces/display_scheduler.h b/cc/surfaces/display_scheduler.h
index 536c55b..764757b 100644
--- a/cc/surfaces/display_scheduler.h
+++ b/cc/surfaces/display_scheduler.h
@@ -15,6 +15,7 @@
 #include "cc/output/renderer_settings.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_observer.h"
 #include "cc/surfaces/surfaces_export.h"
 
 namespace cc {
@@ -28,39 +29,48 @@
 
   virtual bool DrawAndSwap() = 0;
   virtual bool SurfaceHasUndrawnFrame(const SurfaceId& surface_id) const = 0;
+  virtual bool SurfaceDamaged(const SurfaceId& surface_id,
+                              const BeginFrameAck& ack) = 0;
+  virtual void SurfaceDiscarded(const SurfaceId& surface_id) = 0;
 };
 
-class CC_SURFACES_EXPORT DisplayScheduler : public BeginFrameObserverBase {
+class CC_SURFACES_EXPORT DisplayScheduler : public BeginFrameObserverBase,
+                                            public SurfaceObserver {
  public:
-  DisplayScheduler(base::SingleThreadTaskRunner* task_runner,
+  DisplayScheduler(BeginFrameSource* begin_frame_source,
+                   base::SingleThreadTaskRunner* task_runner,
                    int max_pending_swaps);
   ~DisplayScheduler() override;
 
   void SetClient(DisplaySchedulerClient* client);
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source);
 
   void SetVisible(bool visible);
   void SetRootSurfaceResourcesLocked(bool locked);
   void ForceImmediateSwapIfPossible();
   virtual void DisplayResized();
   virtual void SetNewRootSurface(const SurfaceId& root_surface_id);
-  virtual void SurfaceDamaged(const SurfaceId& surface_id,
-                              const BeginFrameAck& ack,
-                              bool display_damaged);
-  void SurfaceCreated(const SurfaceInfo& surface_info);
-  void SurfaceDestroyed(const SurfaceId& surface_id);
-  void SurfaceDamageExpected(const SurfaceId& surface_id,
-                             const BeginFrameArgs& args);
+  virtual void ProcessSurfaceDamage(const SurfaceId& surface_id,
+                                    const BeginFrameAck& ack,
+                                    bool display_damaged);
 
   virtual void DidSwapBuffers();
   void DidReceiveSwapBuffersAck();
 
   void OutputSurfaceLost();
 
-  // BeginFrameObserverBase implementation
+  // BeginFrameObserverBase implementation.
   bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override;
   void OnBeginFrameSourcePausedChanged(bool paused) override;
 
+  // SurfaceObserver implementation.
+  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+  void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
+  bool OnSurfaceDamaged(const SurfaceId& surface_id,
+                        const BeginFrameAck& ack) override;
+  void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
+  void OnSurfaceDamageExpected(const SurfaceId& surface_id,
+                               const BeginFrameArgs& args) override;
+
  protected:
   base::TimeTicks DesiredBeginFrameDeadlineTime();
   virtual void ScheduleBeginFrameDeadline();
diff --git a/cc/surfaces/display_scheduler_unittest.cc b/cc/surfaces/display_scheduler_unittest.cc
index 68e80a00..99fd6b6 100644
--- a/cc/surfaces/display_scheduler_unittest.cc
+++ b/cc/surfaces/display_scheduler_unittest.cc
@@ -45,6 +45,13 @@
     return base::ContainsKey(undrawn_surfaces_, surface_id);
   }
 
+  bool SurfaceDamaged(const SurfaceId& surface_id,
+                      const BeginFrameAck& ack) override {
+    return false;
+  }
+
+  void SurfaceDiscarded(const SurfaceId& surface_id) override {}
+
   int draw_and_swap_count() const { return draw_and_swap_count_; }
 
   void SetNextDrawAndSwapFails() { next_draw_and_swap_fails_ = true; }
@@ -62,12 +69,11 @@
 class TestDisplayScheduler : public DisplayScheduler {
  public:
   TestDisplayScheduler(BeginFrameSource* begin_frame_source,
+                       SurfaceManager* surface_manager,
                        base::SingleThreadTaskRunner* task_runner,
                        int max_pending_swaps)
-      : DisplayScheduler(task_runner, max_pending_swaps),
-        scheduler_begin_frame_deadline_count_(0) {
-    SetBeginFrameSource(begin_frame_source);
-  }
+      : DisplayScheduler(begin_frame_source, task_runner, max_pending_swaps),
+        scheduler_begin_frame_deadline_count_(0) {}
 
   base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() {
     return DesiredBeginFrameDeadlineTime();
@@ -106,13 +112,17 @@
       : fake_begin_frame_source_(0.f, false),
         task_runner_(new base::NullTaskRunner),
         scheduler_(&fake_begin_frame_source_,
+                   &surface_manager_,
                    task_runner_.get(),
                    kMaxPendingSwaps) {
     now_src_.Advance(base::TimeDelta::FromMicroseconds(10000));
+    surface_manager_.AddObserver(&scheduler_);
     scheduler_.SetClient(&client_);
   }
 
-  ~DisplaySchedulerTest() override {}
+  ~DisplaySchedulerTest() override {
+    surface_manager_.RemoveObserver(&scheduler_);
+  }
 
   void SetUp() override { scheduler_.SetRootSurfaceResourcesLocked(false); }
 
@@ -124,12 +134,13 @@
         BEGINFRAME_FROM_HERE, &now_src_);
     fake_begin_frame_source_.TestOnBeginFrame(last_begin_frame_args_);
     for (const SurfaceId& surface : observing_surfaces)
-      scheduler_.SurfaceDamageExpected(surface, last_begin_frame_args_);
+      scheduler_.OnSurfaceDamageExpected(surface, last_begin_frame_args_);
   }
 
   void SurfaceDamaged(const SurfaceId& surface_id) {
     client_.SurfaceDamaged(surface_id);
-    scheduler_.SurfaceDamaged(surface_id, AckForCurrentBeginFrame(), true);
+    scheduler_.ProcessSurfaceDamage(surface_id, AckForCurrentBeginFrame(),
+                                    true);
   }
 
  protected:
@@ -148,6 +159,7 @@
 
   base::SimpleTestTickClock now_src_;
   scoped_refptr<base::NullTaskRunner> task_runner_;
+  SurfaceManager surface_manager_;
   FakeDisplaySchedulerClient client_;
   TestDisplayScheduler scheduler_;
 };
@@ -167,7 +179,7 @@
 
   // Go trough an initial BeginFrame cycle with the root surface.
   AdvanceTimeAndBeginFrameForTest(std::vector<SurfaceId>());
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id1, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id1);
   scheduler_.BeginFrameDeadlineForTest();
 
@@ -175,13 +187,13 @@
   // for a new root surface.
   AdvanceTimeAndBeginFrameForTest({root_surface_id1});
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
   SurfaceDamaged(sid1);
   EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   scheduler_.DisplayResized();
   EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_.SurfaceDestroyed(root_surface_id1);
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id2, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceDestroyed(root_surface_id1);
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id2, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id2);
   EXPECT_GE(now_src().NowTicks(),
             scheduler_.DesiredBeginFrameDeadlineTimeForTest());
@@ -210,7 +222,7 @@
 
   // Go trough an initial BeginFrame cycle with the root surface.
   AdvanceTimeAndBeginFrameForTest(std::vector<SurfaceId>());
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
   scheduler_.BeginFrameDeadlineForTest();
 
@@ -218,7 +230,7 @@
   // for a new root surface.
   AdvanceTimeAndBeginFrameForTest({root_surface_id});
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
   SurfaceDamaged(sid1);
   EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   scheduler_.DisplayResized();
@@ -251,9 +263,9 @@
   scheduler_.SetVisible(true);
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(sid2, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid2, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
 
   // Set surface1 as active via SurfaceDamageExpected().
@@ -292,7 +304,7 @@
             scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   BeginFrameAck ack = AckForCurrentBeginFrame();
   ack.has_damage = false;
-  scheduler_.SurfaceDamaged(sid1, ack, false);
+  scheduler_.ProcessSurfaceDamage(sid1, ack, false);
   EXPECT_GE(now_src().NowTicks(),
             scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   scheduler_.BeginFrameDeadlineForTest();
@@ -303,12 +315,12 @@
 
   // SurfaceDamage with |!display_damaged| does not affect needs_draw and
   // scheduler stays idle.
-  scheduler_.SurfaceDamaged(sid1, AckForCurrentBeginFrame(), false);
+  scheduler_.ProcessSurfaceDamage(sid1, AckForCurrentBeginFrame(), false);
   EXPECT_FALSE(scheduler_.inside_begin_frame_deadline_interval());
 
   // Deadline should trigger early if child surfaces are idle and
   // we get damage on the root surface.
-  scheduler_.SurfaceDamageExpected(root_surface_id, last_begin_frame_args_);
+  scheduler_.OnSurfaceDamageExpected(root_surface_id, last_begin_frame_args_);
   EXPECT_FALSE(scheduler_.inside_begin_frame_deadline_interval());
   SurfaceDamaged(root_surface_id);
   EXPECT_GE(now_src().NowTicks(),
@@ -326,8 +338,8 @@
   scheduler_.SetVisible(true);
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
@@ -395,8 +407,8 @@
                  LocalSurfaceId(2, base::UnguessableToken::Create()));
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
   scheduler_.SetVisible(true);
   EXPECT_EQ(1u, fake_begin_frame_source_.num_observers());
@@ -452,8 +464,8 @@
   scheduler_.SetVisible(true);
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
@@ -483,8 +495,8 @@
   scheduler_.SetVisible(true);
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
@@ -537,9 +549,9 @@
   scheduler_.SetVisible(true);
 
   // Create surfaces and set the root surface.
-  scheduler_.SurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(sid2, 1.0f, gfx::Size()));
-  scheduler_.SurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid1, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(sid2, 1.0f, gfx::Size()));
+  scheduler_.OnSurfaceCreated(SurfaceInfo(root_surface_id, 1.0f, gfx::Size()));
   scheduler_.SetNewRootSurface(root_surface_id);
 
   // Set surface 1 and 2 as active.
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 25868c50..4bd0f4e 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -47,8 +47,9 @@
 
 class TestDisplayScheduler : public DisplayScheduler {
  public:
-  explicit TestDisplayScheduler(base::SingleThreadTaskRunner* task_runner)
-      : DisplayScheduler(task_runner, 1),
+  explicit TestDisplayScheduler(BeginFrameSource* begin_frame_source,
+                                base::SingleThreadTaskRunner* task_runner)
+      : DisplayScheduler(begin_frame_source, task_runner, 1),
         damaged(false),
         display_resized_(false),
         has_new_root_surface(false),
@@ -62,9 +63,9 @@
     has_new_root_surface = true;
   }
 
-  void SurfaceDamaged(const SurfaceId& surface_id,
-                      const BeginFrameAck& ack,
-                      bool display_damaged) override {
+  void ProcessSurfaceDamage(const SurfaceId& surface_id,
+                            const BeginFrameAck& ack,
+                            bool display_damaged) override {
     if (display_damaged) {
       damaged = true;
       needs_draw_ = true;
@@ -114,28 +115,35 @@
       output_surface = FakeOutputSurface::CreateSoftware(std::move(device));
     }
     output_surface_ = output_surface.get();
-    auto scheduler = base::MakeUnique<TestDisplayScheduler>(task_runner_.get());
+    auto scheduler = base::MakeUnique<TestDisplayScheduler>(
+        begin_frame_source_.get(), task_runner_.get());
     scheduler_ = scheduler.get();
     display_ = CreateDisplay(settings, kArbitraryFrameSinkId,
-                             begin_frame_source_.get(), std::move(scheduler),
-                             std::move(output_surface));
+                             std::move(scheduler), std::move(output_surface));
+    manager_.RegisterBeginFrameSource(begin_frame_source_.get(),
+                                      kArbitraryFrameSinkId);
   }
 
   std::unique_ptr<Display> CreateDisplay(
       const RendererSettings& settings,
       const FrameSinkId& frame_sink_id,
-      BeginFrameSource* begin_frame_source,
       std::unique_ptr<DisplayScheduler> scheduler,
       std::unique_ptr<OutputSurface> output_surface) {
     auto display = base::MakeUnique<Display>(
         &shared_bitmap_manager_, nullptr /* gpu_memory_buffer_manager */,
-        settings, frame_sink_id, begin_frame_source, std::move(output_surface),
+        settings, frame_sink_id, std::move(output_surface),
         std::move(scheduler),
         base::MakeUnique<TextureMailboxDeleter>(task_runner_.get()));
     display->SetVisible(true);
     return display;
   }
 
+  void TearDownDisplay() {
+    // Only call UnregisterBeginFrameSource if SetupDisplay has been called.
+    if (begin_frame_source_)
+      manager_.UnregisterBeginFrameSource(begin_frame_source_.get());
+  }
+
  protected:
   void SubmitCompositorFrame(RenderPassList* pass_list,
                              const LocalSurfaceId& local_surface_id) {
@@ -424,6 +432,7 @@
               software_output_device_->damage_rect());
     EXPECT_EQ(0u, output_surface_->last_sent_frame()->latency_info.size());
   }
+  TearDownDisplay();
 }
 
 class MockedContext : public TestWebGraphicsContext3D {
@@ -497,6 +506,7 @@
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM());
   display_->Resize(gfx::Size(250, 250));
   testing::Mock::VerifyAndClearExpectations(context_ptr);
+  TearDownDisplay();
 }
 
 class CountLossDisplayClient : public StubDisplayClient {
@@ -523,6 +533,7 @@
       GL_GUILTY_CONTEXT_RESET_ARB, GL_INNOCENT_CONTEXT_RESET_ARB);
   output_surface_->context_provider()->ContextGL()->Flush();
   EXPECT_EQ(1, client.loss_count());
+  TearDownDisplay();
 }
 
 // Regression test for https://crbug.com/727162: Submitting a CompositorFrame to
@@ -544,14 +555,15 @@
       true /* handles_frame_sink_id_invalidation */,
       true /* needs_sync_points */);
   auto begin_frame_source2 = base::MakeUnique<StubBeginFrameSource>();
-  auto scheduler_for_display2 =
-      base::MakeUnique<TestDisplayScheduler>(task_runner_.get());
+  auto scheduler_for_display2 = base::MakeUnique<TestDisplayScheduler>(
+      begin_frame_source2.get(), task_runner_.get());
   TestDisplayScheduler* scheduler2 = scheduler_for_display2.get();
-  auto display2 =
-      CreateDisplay(settings, kAnotherFrameSinkId, begin_frame_source2.get(),
-                    std::move(scheduler_for_display2),
-                    FakeOutputSurface::CreateSoftware(
-                        base::MakeUnique<TestSoftwareOutputDevice>()));
+  auto display2 = CreateDisplay(
+      settings, kAnotherFrameSinkId, std::move(scheduler_for_display2),
+      FakeOutputSurface::CreateSoftware(
+          base::MakeUnique<TestSoftwareOutputDevice>()));
+  manager_.RegisterBeginFrameSource(begin_frame_source2.get(),
+                                    kAnotherFrameSinkId);
   StubDisplayClient client2;
   display2->Initialize(&client2, &manager_);
   display2->SetLocalSurfaceId(local_surface_id, 1.f);
@@ -577,6 +589,8 @@
   // Should have damaged only display_ but not display2.
   EXPECT_TRUE(scheduler_->damaged);
   EXPECT_FALSE(scheduler2->damaged);
+  manager_.UnregisterBeginFrameSource(begin_frame_source2.get());
+  TearDownDisplay();
 }
 
 }  // namespace
diff --git a/cc/test/test_compositor_frame_sink.cc b/cc/test/test_compositor_frame_sink.cc
index 440b5d5..6b4a5a5 100644
--- a/cc/test/test_compositor_frame_sink.cc
+++ b/cc/test/test_compositor_frame_sink.cc
@@ -79,15 +79,14 @@
                                             renderer_settings_.refresh_rate));
     }
     scheduler.reset(new DisplayScheduler(
-        task_runner_.get(),
+        begin_frame_source_.get(), task_runner_.get(),
         display_output_surface->capabilities().max_frames_pending));
   }
 
-  display_.reset(
-      new Display(shared_bitmap_manager(), gpu_memory_buffer_manager(),
-                  renderer_settings_, frame_sink_id_, begin_frame_source_.get(),
-                  std::move(display_output_surface), std::move(scheduler),
-                  base::MakeUnique<TextureMailboxDeleter>(task_runner_.get())));
+  display_ = base::MakeUnique<Display>(
+      shared_bitmap_manager(), gpu_memory_buffer_manager(), renderer_settings_,
+      frame_sink_id_, std::move(display_output_surface), std::move(scheduler),
+      base::MakeUnique<TextureMailboxDeleter>(task_runner_.get()));
 
   // We want the Display's OutputSurface to hear about lost context, and when
   // this shares a context with it we should not be listening for lost context
@@ -102,7 +101,10 @@
       this, surface_manager_.get(), frame_sink_id_, is_root,
       handles_frame_sink_id_invalidation, needs_sync_points);
   client_->SetBeginFrameSource(&external_begin_frame_source_);
-
+  if (begin_frame_source_) {
+    surface_manager_->RegisterBeginFrameSource(begin_frame_source_.get(),
+                                               frame_sink_id_);
+  }
   display_->Initialize(this, surface_manager_.get());
   display_->renderer_for_testing()->SetEnlargePassTextureAmountForTesting(
       enlarge_pass_texture_amount_);
@@ -111,6 +113,8 @@
 }
 
 void TestCompositorFrameSink::DetachFromClient() {
+  if (begin_frame_source_)
+    surface_manager_->UnregisterBeginFrameSource(begin_frame_source_.get());
   client_->SetBeginFrameSource(nullptr);
   support_ = nullptr;
   display_ = nullptr;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
index 6b25878..8361e241 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadManagerUi.java
@@ -401,7 +401,7 @@
         MenuItem infoMenuItem = mToolbar.getMenu().findItem(R.id.info_menu_id);
         Drawable iconDrawable = TintedDrawable.constructTintedDrawable(mActivity.getResources(),
                 R.drawable.btn_info,
-                show ? R.color.light_active_color : R.color.default_text_color);
+                show ? R.color.light_active_color : R.color.light_normal_color);
         infoMenuItem.setIcon(iconDrawable);
         infoMenuItem.setTitle(show ? R.string.hide_info : R.string.show_info);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java
index 0cb4dd0b..c55a1149 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java
@@ -4,22 +4,17 @@
 
 package org.chromium.chrome.browser.infobar;
 
-import android.support.v7.widget.SwitchCompat;
-
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ResourceId;
 import org.chromium.chrome.browser.tab.Tab;
 
-import java.util.ArrayList;
-
 /**
  * An infobar for showing several permission requests which can be allowed or blocked.
  */
 public class GroupedPermissionInfoBar extends PermissionInfoBar {
     private final String[] mPermissionText;
     private final int[] mPermissionIcons;
-    private long mNativeGroupedPermissionInfoBar;
 
     GroupedPermissionInfoBar(Tab tab, int[] contentSettingsTypes, String message, String buttonOk,
             String buttonCancel, boolean showPersistenceToggle, String[] permissionText,
@@ -34,54 +29,18 @@
     public void createContent(InfoBarLayout layout) {
         InfoBarControlLayout control = layout.addControlLayout();
 
-        if (mPermissionIcons.length == 1) {
+        for (int i = 0; i < mPermissionIcons.length; i++) {
             control.addIcon(ResourceId.mapToDrawableId(mPermissionIcons[0]),
-                    R.color.light_normal_color, mPermissionText[0], null);
-        } else {
-            for (int i = 0; i < mPermissionIcons.length; i++) {
-                control.addSwitch(ResourceId.mapToDrawableId(mPermissionIcons[i]),
-                        R.color.light_normal_color, mPermissionText[i], i, true);
-            }
+                    R.color.light_normal_color, mPermissionText[i], null);
         }
 
+        // TODO(raymes): Ensure the ALLOW/BLOCK buttons are shown.
+
         // Call this last to ensure that if a persistence toggle is added, it's added last.
         super.createContent(layout);
     }
 
     @Override
-    public void onButtonClicked(final boolean isPrimaryButton) {
-        if (isPrimaryButton) {
-            boolean[] toggleStatus = new boolean[mPermissionIcons.length];
-
-            if (mPermissionIcons.length == 1) {
-                toggleStatus[0] = true;
-            } else {
-                for (int i = 0; i < mPermissionIcons.length; i++) {
-                    toggleStatus[i] = ((SwitchCompat) getView().findViewById(i)).isChecked();
-                }
-            }
-
-            // Only request the permissions which were actually allowed by the user.
-            ArrayList<Integer> selectedContentSettingsTypes = new ArrayList<Integer>();
-            for (int i = 0; i < toggleStatus.length; i++) {
-                if (toggleStatus[i]) {
-                    selectedContentSettingsTypes.add(Integer.valueOf(mContentSettingsTypes[i]));
-                }
-            }
-            int[] selectedArray = new int[selectedContentSettingsTypes.size()];
-            for (int i = 0; i < selectedContentSettingsTypes.size(); i++) {
-                selectedArray[i] = selectedContentSettingsTypes.get(i).intValue();
-            }
-
-            if (mNativeGroupedPermissionInfoBar != 0) {
-                nativeSetPermissionState(mNativeGroupedPermissionInfoBar, toggleStatus);
-                mContentSettingsTypes = selectedArray;
-            }
-        }
-        super.onButtonClicked(isPrimaryButton);
-    }
-
-    @Override
     @CalledByNative
     protected boolean isPersistSwitchOn() {
         return super.isPersistSwitchOn();
@@ -110,18 +69,4 @@
                         buttonCancel, showPersistenceToggle, permissionText, permissionIcons);
         return infobar;
     }
-
-    @CalledByNative
-    private void setNativePtr(long nativePtr) {
-        mNativeGroupedPermissionInfoBar = nativePtr;
-    }
-
-    @Override
-    protected void onNativeDestroyed() {
-        mNativeGroupedPermissionInfoBar = 0;
-        super.onNativeDestroyed();
-    }
-
-    private native void nativeSetPermissionState(
-            long nativeGroupedPermissionInfoBar, boolean[] permissions);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index c2c743e38..425ecda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -687,8 +687,10 @@
                 mToolbarHeight = bottom - top;
                 updateSheetDimensions();
 
-                cancelAnimation();
-                setSheetState(mCurrentState, false);
+                if (!mIsScrolling) {
+                    cancelAnimation();
+                    setSheetState(mCurrentState, false);
+                }
             }
         });
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java
index 69cabcc..637e9be 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java
@@ -289,8 +289,11 @@
         // Validate our size is what we expect.
         expectedWidth = VrShellImpl.DEFAULT_CONTENT_WIDTH;
         expectedHeight = VrShellImpl.DEFAULT_CONTENT_HEIGHT;
-        Assert.assertTrue(mVrTestRule.pollJavaScriptBoolean(
-                "screen.width == " + expectedWidth + " && screen.height == " + expectedHeight,
-                POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents()));
+
+        // We aren't comparing for equality because there is some rounding that occurs.
+        Assert.assertTrue(
+                mVrTestRule.pollJavaScriptBoolean("Math.abs(screen.width - " + expectedWidth
+                                + ") < 2 && Math.abs(screen.height - " + expectedHeight + ") < 2",
+                        POLL_TIMEOUT_LONG_MS, mVrTestRule.getFirstTabWebContents()));
     }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4e0140a7..382cf510 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4717,10 +4717,7 @@
       "media/pepper_cdm_test_helper.cc",
       "media/pepper_cdm_test_helper.h",
     ]
-    deps += [
-      ":pepper_cdm_test_constants",
-      "//media:cdm_paths",
-    ]
+    deps += [ "//media:cdm_paths" ]
   }
 }
 
@@ -4780,19 +4777,6 @@
   }
 }
 
-if (enable_pepper_cdms) {
-  # These constants are separated so that test binaries can use them without
-  # linking all of the test support.
-  static_library("pepper_cdm_test_constants") {
-    testonly = true
-    visibility = [ "//chrome/*" ]
-    sources = [
-      "media/pepper_cdm_test_constants.cc",
-      "media/pepper_cdm_test_constants.h",
-    ]
-  }
-}
-
 service_manifest("preferences_forwarder_manifest") {
   name = "preferences_forwarder"
   source = "prefs/forwarder_manifest.json"
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 62903eec..8b2178a 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -158,7 +158,6 @@
 #include "chrome/browser/ui/android/context_menu_helper.h"
 #include "chrome/browser/ui/android/infobars/app_banner_infobar_android.h"
 #include "chrome/browser/ui/android/infobars/autofill_save_card_infobar.h"
-#include "chrome/browser/ui/android/infobars/grouped_permission_infobar.h"
 #include "chrome/browser/ui/android/infobars/infobar_android.h"
 #include "chrome/browser/ui/android/infobars/infobar_container_android.h"
 #include "chrome/browser/ui/android/infobars/reader_mode_infobar.h"
@@ -328,7 +327,6 @@
     {"FontSizePrefsAndroid", FontSizePrefsAndroid::Register},
     {"ForeignSessionHelper",
      ForeignSessionHelper::RegisterForeignSessionHelper},
-    {"GroupedPermissionInfoBar", GroupedPermissionInfoBar::Register},
     {"HistoryReportJniBridge", history_report::RegisterHistoryReportJniBridge},
     {"InfoBarContainer", RegisterInfoBarContainer},
     {"InstantAppsInfobarDelegate", RegisterInstantAppsInfoBarDelegate},
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index d6f9064..5110d8b9 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1147,16 +1147,9 @@
 
     // Store the initial VariationsService seed in local state, if it exists
     // in master prefs.
-    if (!master_prefs_->variations_seed.empty() ||
-        !master_prefs_->compressed_variations_seed.empty()) {
-      if (!master_prefs_->variations_seed.empty()) {
-        local_state_->SetString(variations::prefs::kVariationsSeed,
-                                master_prefs_->variations_seed);
-      }
-      if (!master_prefs_->compressed_variations_seed.empty()) {
-        local_state_->SetString(variations::prefs::kVariationsCompressedSeed,
-                                master_prefs_->compressed_variations_seed);
-      }
+    if (!master_prefs_->compressed_variations_seed.empty()) {
+      local_state_->SetString(variations::prefs::kVariationsCompressedSeed,
+                              master_prefs_->compressed_variations_seed);
       if (!master_prefs_->variations_seed_signature.empty()) {
         local_state_->SetString(variations::prefs::kVariationsSeedSignature,
                                 master_prefs_->variations_seed_signature);
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index fb17f47..8156041e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1328,8 +1328,6 @@
     "system/automatic_reboot_manager.cc",
     "system/automatic_reboot_manager.h",
     "system/automatic_reboot_manager_observer.h",
-    "system/device_change_handler.cc",
-    "system/device_change_handler.h",
     "system/device_disabling_manager.cc",
     "system/device_disabling_manager.h",
     "system/device_disabling_manager_default_delegate.cc",
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
index 0f11ece..7e84e236 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.cc
@@ -317,6 +317,32 @@
   framework_instance->SetMetalayerVisibility(visible);
 }
 
+void ArcVoiceInteractionFrameworkService::SetVoiceInteractionEnabled(
+    bool enable) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  mojom::VoiceInteractionFrameworkInstance* framework_instance =
+      ARC_GET_INSTANCE_FOR_METHOD(
+          arc_bridge_service()->voice_interaction_framework(),
+          SetVoiceInteractionEnabled);
+  if (!framework_instance)
+    return;
+  framework_instance->SetVoiceInteractionEnabled(enable);
+}
+
+void ArcVoiceInteractionFrameworkService::SetVoiceInteractionContextEnabled(
+    bool enable) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  mojom::VoiceInteractionFrameworkInstance* framework_instance =
+      ARC_GET_INSTANCE_FOR_METHOD(
+          arc_bridge_service()->voice_interaction_framework(),
+          SetVoiceInteractionContextEnabled);
+  if (!framework_instance)
+    return;
+  framework_instance->SetVoiceInteractionContextEnabled(enable);
+}
+
 void ArcVoiceInteractionFrameworkService::StartSessionFromUserInteraction(
     const gfx::Rect& rect) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
diff --git a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
index 10f67f4..1d44a4c6 100644
--- a/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
+++ b/chrome/browser/chromeos/arc/voice_interaction/arc_voice_interaction_framework_service.h
@@ -64,6 +64,15 @@
   // VoiceInteractionFrameworkInstance::StartVoiceInteraction() is called.
   void StartSessionFromUserInteraction(const gfx::Rect& region);
 
+  // Turn on / off voice interaction in ARC.
+  // TODO(muyuanli): We should also check on Chrome side once CrOS side settings
+  // are ready (tracked separately at crbug.com/727873).
+  void SetVoiceInteractionEnabled(bool enable);
+
+  // Turn on / off voice interaction context (screenshot and structural data)
+  // in ARC.
+  void SetVoiceInteractionContextEnabled(bool enable);
+
   // Checks whether the caller is called within the time limit since last user
   // initiated interaction. Logs UMA metric when it's not.
   bool ValidateTimeSinceUserInteraction();
diff --git a/chrome/browser/chromeos/system/device_change_handler.cc b/chrome/browser/chromeos/system/device_change_handler.cc
deleted file mode 100644
index e66314b..0000000
--- a/chrome/browser/chromeos/system/device_change_handler.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/system/device_change_handler.h"
-
-#include "chrome/browser/chromeos/system/input_device_settings.h"
-
-namespace chromeos {
-namespace system {
-
-DeviceChangeHandler::DeviceChangeHandler()
-    : pointer_device_observer_(new PointerDeviceObserver) {
-  pointer_device_observer_->AddObserver(this);
-  pointer_device_observer_->Init();
-
-  // Apply settings on startup.
-  TouchpadExists(true);
-  MouseExists(true);
-}
-
-DeviceChangeHandler::~DeviceChangeHandler() {
-  pointer_device_observer_->RemoveObserver(this);
-}
-
-// When we detect a touchpad is attached, apply touchpad settings that was
-// cached inside InputDeviceSettings.
-void DeviceChangeHandler::TouchpadExists(bool exists) {
-  if (!exists)
-    return;
-  system::InputDeviceSettings::Get()->ReapplyTouchpadSettings();
-}
-
-// When we detect a mouse is attached, apply mouse settings that was cached
-// inside InputDeviceSettings.
-void DeviceChangeHandler::MouseExists(bool exists) {
-  if (!exists)
-    return;
-  system::InputDeviceSettings::Get()->ReapplyMouseSettings();
-}
-
-}  // namespace system
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/system/device_change_handler.h b/chrome/browser/chromeos/system/device_change_handler.h
deleted file mode 100644
index b9f69b3..0000000
--- a/chrome/browser/chromeos/system/device_change_handler.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_CHANGE_HANDLER_H_
-#define CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_CHANGE_HANDLER_H_
-
-#include <memory>
-
-#include "chrome/browser/chromeos/system/pointer_device_observer.h"
-
-namespace chromeos {
-namespace system {
-
-// Observes changes in device hierarchy. When a new touchpad/mouse is attached,
-// applies the last used touchpad/mouse settings to the system.
-class DeviceChangeHandler : public PointerDeviceObserver::Observer {
- public:
-  DeviceChangeHandler();
-  ~DeviceChangeHandler() override;
-
- private:
-  // PointerDeviceObserver::Observer implementation.
-  void TouchpadExists(bool exists) override;
-  void MouseExists(bool exists) override;
-
-  std::unique_ptr<PointerDeviceObserver> pointer_device_observer_;
-};
-
-}  // namespace system
-}  // namespace chromeos
-
-
-#endif  // CHROME_BROWSER_CHROMEOS_SYSTEM_DEVICE_CHANGE_HANDLER_H_
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index 41c6f179..443fdac 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -472,7 +472,6 @@
 
   out_prefs->compressed_variations_seed =
       install_prefs.GetCompressedVariationsSeed();
-  out_prefs->variations_seed = install_prefs.GetVariationsSeed();
   out_prefs->variations_seed_signature =
       install_prefs.GetVariationsSeedSignature();
 
diff --git a/chrome/browser/first_run/first_run.h b/chrome/browser/first_run/first_run.h
index 93f4484..c3a1680 100644
--- a/chrome/browser/first_run/first_run.h
+++ b/chrome/browser/first_run/first_run.h
@@ -82,7 +82,6 @@
   std::vector<GURL> bookmarks;
   std::string import_bookmarks_path;
   std::string compressed_variations_seed;
-  std::string variations_seed;
   std::string variations_seed_signature;
   std::string suppress_default_browser_prompt_for_version;
 };
diff --git a/chrome/browser/first_run/first_run_unittest.cc b/chrome/browser/first_run/first_run_unittest.cc
index 93873d70..bac8e1dd 100644
--- a/chrome/browser/first_run/first_run_unittest.cc
+++ b/chrome/browser/first_run/first_run_unittest.cc
@@ -27,12 +27,13 @@
 };
 
 TEST_F(FirstRunTest, SetupMasterPrefsFromInstallPrefs_VariationsSeed) {
-  installer::MasterPreferences install_prefs("{ \"variations_seed\":\"xyz\" }");
+  installer::MasterPreferences install_prefs(
+      "{\"variations_compressed_seed\":\"xyz\"}");
   EXPECT_EQ(1U, install_prefs.master_dictionary().size());
 
   MasterPrefs out_prefs;
   internal::SetupMasterPrefsFromInstallPrefs(install_prefs, &out_prefs);
-  EXPECT_EQ("xyz", out_prefs.variations_seed);
+  EXPECT_EQ("xyz", out_prefs.compressed_variations_seed);
   // Variations prefs should have been extracted (removed) from the dictionary.
   EXPECT_TRUE(install_prefs.master_dictionary().empty());
 }
@@ -43,18 +44,19 @@
 
   MasterPrefs out_prefs;
   internal::SetupMasterPrefsFromInstallPrefs(install_prefs, &out_prefs);
-  EXPECT_TRUE(out_prefs.variations_seed.empty());
+  EXPECT_TRUE(out_prefs.compressed_variations_seed.empty());
   EXPECT_TRUE(out_prefs.variations_seed_signature.empty());
 }
 
 TEST_F(FirstRunTest, SetupMasterPrefsFromInstallPrefs_VariationsSeedSignature) {
   installer::MasterPreferences install_prefs(
-      "{ \"variations_seed\":\"xyz\", \"variations_seed_signature\":\"abc\" }");
+      "{\"variations_compressed_seed\":\"xyz\","
+      " \"variations_seed_signature\":\"abc\"}");
   EXPECT_EQ(2U, install_prefs.master_dictionary().size());
 
   MasterPrefs out_prefs;
   internal::SetupMasterPrefsFromInstallPrefs(install_prefs, &out_prefs);
-  EXPECT_EQ("xyz", out_prefs.variations_seed);
+  EXPECT_EQ("xyz", out_prefs.compressed_variations_seed);
   EXPECT_EQ("abc", out_prefs.variations_seed_signature);
   // Variations prefs should have been extracted (removed) from the dictionary.
   EXPECT_TRUE(install_prefs.master_dictionary().empty());
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 4f2db70..0797746a 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -83,6 +83,7 @@
 class LoggingNetworkChangeObserver;
 class NetworkQualityEstimator;
 class ProxyConfigService;
+class RTTAndThroughputEstimatesObserver;
 class SSLConfigService;
 class URLRequestContext;
 class URLRequestContextGetter;
@@ -154,8 +155,7 @@
 #endif
     std::unique_ptr<net::HostMappingRules> host_mapping_rules;
     std::unique_ptr<net::NetworkQualityEstimator> network_quality_estimator;
-    std::unique_ptr<
-        net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver>
+    std::unique_ptr<net::RTTAndThroughputEstimatesObserver>
         network_quality_observer;
 
     // NetErrorTabHelper uses |dns_probe_service| to send DNS probes when a
diff --git a/chrome/browser/load_library_perf_test.cc b/chrome/browser/load_library_perf_test.cc
index bf128f68..b19be06 100644
--- a/chrome/browser/load_library_perf_test.cc
+++ b/chrome/browser/load_library_perf_test.cc
@@ -20,7 +20,6 @@
 #include "widevine_cdm_version.h"  //  In SHARED_INTERMEDIATE_DIR.
 
 #if BUILDFLAG(ENABLE_PEPPER_CDMS)
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
 #include "media/cdm/cdm_paths.h"
 #endif
 
@@ -90,12 +89,12 @@
 
 TEST(LoadCDMPerfTest, ExternalClearKey) {
   MeasureSizeAndTimeToLoadCdm(
-      kClearKeyCdmBaseDirectory,
+      media::kClearKeyCdmBaseDirectory,
       base::GetNativeLibraryName(media::kClearKeyCdmLibraryName));
 }
 
 TEST(LoadCDMPerfTest, ExternalClearKeyAdapter) {
-  MeasureSizeAndTimeToLoadCdm(kClearKeyCdmBaseDirectory,
-                              kClearKeyCdmAdapterFileName);
+  MeasureSizeAndTimeToLoadCdm(media::kClearKeyCdmBaseDirectory,
+                              media::kClearKeyCdmAdapterFileName);
 }
 #endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 151e914..3938185 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -38,9 +38,9 @@
 #endif
 
 #if BUILDFLAG(ENABLE_PEPPER_CDMS)
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
 #include "chrome/browser/media/pepper_cdm_test_helper.h"
 #include "media/base/media_switches.h"
+#include "media/cdm/cdm_paths.h"
 #endif
 
 #include "widevine_cdm_version.h"  //  In SHARED_INTERMEDIATE_DIR.
@@ -75,13 +75,11 @@
 
 // Supported media types.
 const char kWebMVorbisAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
-const char kWebMOpusAudioOnly[] = "audio/webm; codecs=\"opus\"";
 const char kWebMVP8VideoOnly[] = "video/webm; codecs=\"vp8\"";
 const char kWebMVorbisAudioVP8Video[] = "video/webm; codecs=\"vorbis, vp8\"";
 const char kWebMOpusAudioVP9Video[] = "video/webm; codecs=\"opus, vp9\"";
 const char kWebMVP9VideoOnly[] = "video/webm; codecs=\"vp9\"";
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-const char kMP4AudioOnly[] = "audio/mp4; codecs=\"mp4a.40.2\"";
 const char kMP4VideoOnly[] = "video/mp4; codecs=\"avc1.4D000C\"";
 const char kMP4VideoVp9Only[] =
     "video/mp4; codecs=\"vp09.00.10.08.01.02.02.02.00\"";
@@ -289,9 +287,10 @@
 
 #if BUILDFLAG(ENABLE_PEPPER_CDMS)
     if (IsExternalClearKey(key_system)) {
-      RegisterPepperCdm(command_line, kClearKeyCdmBaseDirectory,
-                        kClearKeyCdmAdapterFileName, kClearKeyCdmDisplayName,
-                        kClearKeyCdmPepperMimeType);
+      RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
+                        media::kClearKeyCdmAdapterFileName,
+                        media::kClearKeyCdmDisplayName,
+                        media::kClearKeyCdmPepperMimeType);
       command_line->AppendSwitchASCII(switches::kEnableFeatures,
                                       media::kExternalClearKeyForTesting.name);
     }
@@ -457,13 +456,6 @@
 using ::testing::Combine;
 using ::testing::Values;
 
-#if !defined(OS_ANDROID)
-INSTANTIATE_TEST_CASE_P(SRC_ClearKey,
-                        EncryptedMediaTest,
-                        Combine(Values(kClearKeyKeySystem),
-                                Values(SrcType::SRC)));
-#endif  // !defined(OS_ANDROID)
-
 INSTANTIATE_TEST_CASE_P(MSE_ClearKey,
                         EncryptedMediaTest,
                         Combine(Values(kClearKeyKeySystem),
@@ -480,15 +472,13 @@
                         EncryptedMediaTest,
                         Combine(Values(kExternalClearKeyKeySystem),
                                 Values(SrcType::MSE)));
-
-const char kExternalClearKeyDecryptOnlyKeySystem[] =
-    "org.chromium.externalclearkey.decryptonly";
-
-// To reduce test time, only run ExternalClearKeyDecryptOnly with MSE.
-INSTANTIATE_TEST_CASE_P(MSE_ExternalClearKeyDecryptOnly,
+#else
+// To reduce test time, only run ClearKey SRC tests when we are not running
+// ExternalClearKey SRC tests.
+INSTANTIATE_TEST_CASE_P(SRC_ClearKey,
                         EncryptedMediaTest,
-                        Combine(Values(kExternalClearKeyDecryptOnlyKeySystem),
-                                Values(SrcType::MSE)));
+                        Combine(Values(kClearKeyKeySystem),
+                                Values(SrcType::SRC)));
 #endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
@@ -500,10 +490,6 @@
 #endif  // !defined(OS_CHROMEOS)
 #endif  // defined(WIDEVINE_CDM_AVAILABLE)
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM) {
-  TestSimplePlayback("bear-a_enc-a.webm", kWebMVorbisAudioOnly);
-}
-
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioClearVideo_WebM) {
   TestSimplePlayback("bear-320x240-av_enc-a.webm", kWebMVorbisAudioVP8Video);
 }
@@ -512,10 +498,6 @@
   TestSimplePlayback("bear-320x240-av_enc-av.webm", kWebMVorbisAudioVP8Video);
 }
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_WebM) {
-  TestSimplePlayback("bear-320x240-v_enc-v.webm", kWebMVP8VideoOnly);
-}
-
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoClearAudio_WebM) {
   TestSimplePlayback("bear-320x240-av_enc-v.webm", kWebMVorbisAudioVP8Video);
 }
@@ -530,10 +512,6 @@
                      kWebMVP9VideoOnly);
 }
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_WebM_Opus) {
-  TestSimplePlayback("bear-320x240-opus-a_enc-a.webm", kWebMOpusAudioOnly);
-}
-
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoAudio_WebM_Opus) {
   TestSimplePlayback("bear-320x240-opus-av_enc-av.webm",
                      kWebMOpusAudioVP9Video);
@@ -596,13 +574,7 @@
 }
 
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
-// Crashes on Mac only.  http://crbug.com/621857
-#if defined(OS_MACOSX)
-#define MAYBE_Playback_VideoOnly_MP4 DISABLED_Playback_VideoOnly_MP4
-#else
-#define MAYBE_Playback_VideoOnly_MP4 Playback_VideoOnly_MP4
-#endif
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, MAYBE_Playback_VideoOnly_MP4) {
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4) {
   // MP4 without MSE is not support yet, http://crbug.com/170793.
   if (CurrentSourceType() != SrcType::MSE) {
     DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
@@ -611,15 +583,6 @@
   TestSimplePlayback("bear-640x360-v_frag-cenc.mp4", kMP4VideoOnly);
 }
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_AudioOnly_MP4) {
-  // MP4 without MSE is not support yet, http://crbug.com/170793.
-  if (CurrentSourceType() != SrcType::MSE) {
-    DVLOG(0) << "Skipping test; Can only play MP4 encrypted streams by MSE.";
-    return;
-  }
-  TestSimplePlayback("bear-640x360-a_frag-cenc.mp4", kMP4AudioOnly);
-}
-
 IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, Playback_VideoOnly_MP4_VP9) {
   // MP4 without MSE is not support yet, http://crbug.com/170793.
   if (CurrentSourceType() != SrcType::MSE) {
@@ -735,6 +698,23 @@
   TestPlaybackCase(kExternalClearKeyKeySystem, kUnknownSession,
                    kEmeSessionNotFound);
 }
+
+const char kExternalClearKeyDecryptOnlyKeySystem[] =
+    "org.chromium.externalclearkey.decryptonly";
+
+IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, DecryptOnly_VideoAudio_WebM) {
+  RunSimpleEncryptedMediaTest(
+      "bear-320x240-av_enc-av.webm", kWebMVorbisAudioVP8Video,
+      kExternalClearKeyDecryptOnlyKeySystem, SrcType::MSE);
+}
+
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, DecryptOnly_VideoOnly_MP4_VP9) {
+  RunSimpleEncryptedMediaTest(
+      "bear-320x240-v_frag-vp9-cenc.mp4", kMP4VideoVp9Only,
+      kExternalClearKeyDecryptOnlyKeySystem, SrcType::MSE);
+}
+#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
 #endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
 
 #if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
diff --git a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
index 05e066d..5672f11 100644
--- a/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_supported_types_browsertest.cc
@@ -32,8 +32,8 @@
 #include "url/gurl.h"
 
 #if BUILDFLAG(ENABLE_PEPPER_CDMS)
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
 #include "chrome/browser/media/pepper_cdm_test_helper.h"
+#include "media/cdm/cdm_paths.h"
 #endif
 
 #if defined(OS_ANDROID)
@@ -296,9 +296,10 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EncryptedMediaSupportedTypesTest::SetUpCommandLine(command_line);
-    RegisterPepperCdm(command_line, kClearKeyCdmBaseDirectory,
-                      kClearKeyCdmAdapterFileName, kClearKeyCdmDisplayName,
-                      kClearKeyCdmPepperMimeType);
+    RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
+                      media::kClearKeyCdmAdapterFileName,
+                      media::kClearKeyCdmDisplayName,
+                      media::kClearKeyCdmPepperMimeType);
     command_line->AppendSwitchASCII(switches::kEnableFeatures,
                                     media::kExternalClearKeyForTesting.name);
   }
@@ -315,9 +316,10 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EncryptedMediaSupportedTypesTest::SetUpCommandLine(command_line);
 #if BUILDFLAG(ENABLE_PEPPER_CDMS)
-    RegisterPepperCdm(command_line, kClearKeyCdmBaseDirectory,
-                      kClearKeyCdmAdapterFileName, kClearKeyCdmDisplayName,
-                      kClearKeyCdmPepperMimeType);
+    RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
+                      media::kClearKeyCdmAdapterFileName,
+                      media::kClearKeyCdmDisplayName,
+                      media::kClearKeyCdmPepperMimeType);
 #endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
   }
 };
@@ -333,10 +335,10 @@
  protected:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     EncryptedMediaSupportedTypesTest::SetUpCommandLine(command_line);
-    RegisterPepperCdm(command_line, kClearKeyCdmBaseDirectory,
+    RegisterPepperCdm(command_line, media::kClearKeyCdmBaseDirectory,
                       "clearkeycdmadapterwrongname.dll",
-                      kClearKeyCdmDisplayName, kClearKeyCdmPepperMimeType,
-                      false);
+                      media::kClearKeyCdmDisplayName,
+                      media::kClearKeyCdmPepperMimeType, false);
     command_line->AppendSwitchASCII(switches::kEnableFeatures,
                                     media::kExternalClearKeyForTesting.name);
   }
diff --git a/chrome/browser/media/pepper_cdm_test_constants.cc b/chrome/browser/media/pepper_cdm_test_constants.cc
deleted file mode 100644
index abdaca2..0000000
--- a/chrome/browser/media/pepper_cdm_test_constants.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
-
-#include "build/build_config.h"
-
-const char kClearKeyCdmBaseDirectory[] = "ClearKeyCdm";
-
-const char kClearKeyCdmAdapterFileName[] =
-#if defined(OS_MACOSX)
-    "clearkeycdmadapter.plugin";
-#elif defined(OS_WIN)
-    "clearkeycdmadapter.dll";
-#elif defined(OS_POSIX)
-    "libclearkeycdmadapter.so";
-#endif
-
-const char kClearKeyCdmDisplayName[] = "Clear Key CDM";
-
-const char kClearKeyCdmPepperMimeType[] = "application/x-ppapi-clearkey-cdm";
diff --git a/chrome/browser/media/pepper_cdm_test_constants.h b/chrome/browser/media/pepper_cdm_test_constants.h
deleted file mode 100644
index 255a288..0000000
--- a/chrome/browser/media/pepper_cdm_test_constants.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 CHROME_BROWSER_MEDIA_PEPPER_CDM_TEST_CONSTANTS_H_
-#define CHROME_BROWSER_MEDIA_PEPPER_CDM_TEST_CONSTANTS_H_
-
-// Base path for Clear Key CDM (relative to the chrome executable).
-extern const char kClearKeyCdmBaseDirectory[];
-
-// Platform-specific filename relative to kClearKeyCdmBaseDirectory.
-extern const char kClearKeyCdmAdapterFileName[];
-
-// Display name for Clear Key CDM.
-extern const char kClearKeyCdmDisplayName[];
-
-// Pepper type for Clear Key CDM.
-extern const char kClearKeyCdmPepperMimeType[];
-
-#endif  // CHROME_BROWSER_MEDIA_PEPPER_CDM_TEST_CONSTANTS_H_
diff --git a/chrome/browser/media/pepper_cdm_test_helper.cc b/chrome/browser/media/pepper_cdm_test_helper.cc
index 734e8137..06e6a332 100644
--- a/chrome/browser/media/pepper_cdm_test_helper.cc
+++ b/chrome/browser/media/pepper_cdm_test_helper.cc
@@ -8,7 +8,6 @@
 #include "base/files/file_util.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/media/pepper_cdm_test_constants.h"
 #include "content/public/browser/plugin_service.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/webplugininfo.h"
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc b/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc
index a13b2c3..a118d4e 100644
--- a/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc
+++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service.cc
@@ -20,8 +20,10 @@
 #include "components/prefs/pref_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/network_qualities_prefs_manager.h"
 #include "net/nqe/network_quality.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
 
 namespace {
 
@@ -81,8 +83,8 @@
 // to the UI service.
 // It is created on the UI thread, but used and deleted on the IO thread.
 class UINetworkQualityEstimatorService::IONetworkQualityObserver
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver,
-      public net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver {
+    : public net::EffectiveConnectionTypeObserver,
+      public net::RTTAndThroughputEstimatesObserver {
  public:
   explicit IONetworkQualityObserver(
       base::WeakPtr<UINetworkQualityEstimatorService> service)
@@ -221,7 +223,7 @@
 }
 
 void UINetworkQualityEstimatorService::AddEffectiveConnectionTypeObserver(
-    net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) {
+    net::EffectiveConnectionTypeObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   effective_connection_type_observer_list_.AddObserver(observer);
 
@@ -235,7 +237,7 @@
 }
 
 void UINetworkQualityEstimatorService::RemoveEffectiveConnectionTypeObserver(
-    net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) {
+    net::EffectiveConnectionTypeObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   effective_connection_type_observer_list_.RemoveObserver(observer);
 }
@@ -268,7 +270,7 @@
 }
 
 void UINetworkQualityEstimatorService::AddRTTAndThroughputEstimatesObserver(
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
+    net::RTTAndThroughputEstimatesObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   rtt_throughput_observer_list_.AddObserver(observer);
 
@@ -284,7 +286,7 @@
 // Removes |observer| from the list of RTT and throughput estimate observers.
 // Must be called on the IO thread.
 void UINetworkQualityEstimatorService::RemoveRTTAndThroughputEstimatesObserver(
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
+    net::RTTAndThroughputEstimatesObserver* observer) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   rtt_throughput_observer_list_.RemoveObserver(observer);
 }
@@ -310,8 +312,7 @@
 
 void UINetworkQualityEstimatorService::
     NotifyEffectiveConnectionTypeObserverIfPresent(
-        net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-        const {
+        net::EffectiveConnectionTypeObserver* observer) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!effective_connection_type_observer_list_.HasObserver(observer))
@@ -322,8 +323,7 @@
 }
 
 void UINetworkQualityEstimatorService::NotifyRTTAndThroughputObserverIfPresent(
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-    const {
+    net::RTTAndThroughputEstimatesObserver* observer) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   if (!rtt_throughput_observer_list_.HasObserver(observer))
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service.h b/chrome/browser/net/nqe/ui_network_quality_estimator_service.h
index 128456a..20eacc0d 100644
--- a/chrome/browser/net/nqe/ui_network_quality_estimator_service.h
+++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service.h
@@ -24,7 +24,9 @@
 class Profile;
 
 namespace net {
+class EffectiveConnectionTypeObserver;
 class NetworkQualitiesPrefsManager;
+class RTTAndThroughputEstimatesObserver;
 }
 
 // UI service to determine the current EffectiveConnectionType.
@@ -38,33 +40,17 @@
   // NetworkQualityProvider implementation:
   // Must be called on the UI thread.
   net::EffectiveConnectionType GetEffectiveConnectionType() const override;
-  // Must be called on the UI thread. |observer| will be notified on the UI
-  // thread.  |observer| would be notified of the current effective connection
-  // type in the next message pump.
   void AddEffectiveConnectionTypeObserver(
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-      override;
-  // Must be called on the UI thread.
+      net::EffectiveConnectionTypeObserver* observer) override;
   void RemoveEffectiveConnectionTypeObserver(
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-      override;
+      net::EffectiveConnectionTypeObserver* observer) override;
   base::Optional<base::TimeDelta> GetHttpRTT() const override;
   base::Optional<base::TimeDelta> GetTransportRTT() const override;
   base::Optional<int32_t> GetDownstreamThroughputKbps() const override;
-
-  // Must be called on the UI thread. |observer| will be notified on the UI
-  // thread. |observer| would be notified of the changes in the HTTP RTT,
-  // transport RTT or throughput. |observer| would be notified of the current
-  // values in the next message pump.
   void AddRTTAndThroughputEstimatesObserver(
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-      override;
-
-  // Removes |observer| from the list of RTT and throughput estimate observers.
-  // Must be called on the UI thread.
+      net::RTTAndThroughputEstimatesObserver* observer) override;
   void RemoveRTTAndThroughputEstimatesObserver(
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-      override;
+      net::RTTAndThroughputEstimatesObserver* observer) override;
 
   // Registers the profile-specific network quality estimator prefs.
   static void RegisterProfilePrefs(PrefRegistrySimple* registry);
@@ -88,14 +74,12 @@
   // Notifies |observer| of the current effective connection type if |observer|
   // is still registered as an observer.
   void NotifyEffectiveConnectionTypeObserverIfPresent(
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-      const;
+      net::EffectiveConnectionTypeObserver* observer) const;
 
   // Notifies |observer| of the current effective connection type if |observer|
   // is still registered as an observer.
   void NotifyRTTAndThroughputObserverIfPresent(
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-      const;
+      net::RTTAndThroughputEstimatesObserver* observer) const;
 
   // KeyedService implementation:
   void Shutdown() override;
@@ -125,13 +109,11 @@
   std::unique_ptr<IONetworkQualityObserver> io_observer_;
 
   // Observer list for changes in effective connection type.
-  base::ObserverList<
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver>
+  base::ObserverList<net::EffectiveConnectionTypeObserver>
       effective_connection_type_observer_list_;
 
   // Observer list for changes in RTT or throughput values.
-  base::ObserverList<
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver>
+  base::ObserverList<net::RTTAndThroughputEstimatesObserver>
       rtt_throughput_observer_list_;
 
   // Prefs manager that is owned by this service. Created on the UI thread, but
diff --git a/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc b/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc
index 72d41e60..5bd55116 100644
--- a/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc
+++ b/chrome/browser/net/nqe/ui_network_quality_estimator_service_browsertest.cc
@@ -23,8 +23,10 @@
 #include "net/base/network_change_notifier.h"
 #include "net/nqe/cached_network_quality.h"
 #include "net/nqe/effective_connection_type.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/network_id.h"
 #include "net/nqe/network_quality_estimator.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class Profile;
@@ -32,14 +34,13 @@
 namespace {
 
 class TestEffectiveConnectionTypeObserver
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver {
+    : public net::EffectiveConnectionTypeObserver {
  public:
   TestEffectiveConnectionTypeObserver()
       : effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
   ~TestEffectiveConnectionTypeObserver() override {}
 
-  // net::NetworkQualityEstimator::EffectiveConnectionTypeObserver
-  // implementation:
+  // net::EffectiveConnectionTypeObserver implementation:
   void OnEffectiveConnectionTypeChanged(
       net::EffectiveConnectionType type) override {
     effective_connection_type_ = type;
@@ -57,7 +58,7 @@
 };
 
 class TestRTTAndThroughputEstimatesObserver
-    : public net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver {
+    : public net::RTTAndThroughputEstimatesObserver {
  public:
   TestRTTAndThroughputEstimatesObserver()
       : http_rtt_(base::TimeDelta::FromMilliseconds(-1)),
@@ -65,8 +66,7 @@
         downstream_throughput_kbps_(-1) {}
   ~TestRTTAndThroughputEstimatesObserver() override {}
 
-  // net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver
-  // implementation:
+  // net::RTTAndThroughputEstimatesObserver implementation:
   void OnRTTOrThroughputEstimatesComputed(
       base::TimeDelta http_rtt,
       base::TimeDelta transport_rtt,
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index f862f1c6..d71a3de 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -12,6 +12,8 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "components/ukm/test_ukm_recorder.h"
 #include "components/ukm/ukm_source.h"
+#include "net/nqe/effective_connection_type.h"
+#include "net/nqe/network_quality_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::AnyNumber;
@@ -23,25 +25,12 @@
 const char kTestUrl1[] = "https://www.google.com/";
 const char kTestUrl2[] = "https://www.example.com/";
 
-class MockNetworkQualityProvider
-    : public net::NetworkQualityEstimator::NetworkQualityProvider {
+class MockNetworkQualityProvider : public net::NetworkQualityProvider {
  public:
   MOCK_CONST_METHOD0(GetEffectiveConnectionType,
                      net::EffectiveConnectionType());
   MOCK_CONST_METHOD0(GetHttpRTT, base::Optional<base::TimeDelta>());
   MOCK_CONST_METHOD0(GetTransportRTT, base::Optional<base::TimeDelta>());
-  MOCK_METHOD1(
-      AddEffectiveConnectionTypeObserver,
-      void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
-  MOCK_METHOD1(
-      RemoveEffectiveConnectionTypeObserver,
-      void(net::NetworkQualityEstimator::EffectiveConnectionTypeObserver*));
-  MOCK_METHOD1(
-      AddRTTAndThroughputEstimatesObserver,
-      void(net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver*));
-  MOCK_METHOD1(
-      RemoveRTTAndThroughputEstimatesObserver,
-      void(net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver*));
 };
 
 }  // namespace
diff --git a/chrome/browser/permissions/permission_request_manager.cc b/chrome/browser/permissions/permission_request_manager.cc
index 982e4ff..3d4e4d2 100644
--- a/chrome/browser/permissions/permission_request_manager.cc
+++ b/chrome/browser/permissions/permission_request_manager.cc
@@ -191,10 +191,8 @@
   }
 
   std::vector<PermissionRequest*>::iterator requests_iter;
-  std::vector<bool>::iterator accepts_iter = accept_states_.begin();
-  for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
-       requests_iter != requests_.end();
-       requests_iter++, accepts_iter++) {
+  for (requests_iter = requests_.begin(); requests_iter != requests_.end();
+       requests_iter++) {
     if (*requests_iter != request)
       continue;
 
@@ -204,7 +202,6 @@
     if (can_erase) {
       RequestFinishedIncludingDuplicates(*requests_iter);
       requests_.erase(requests_iter);
-      accept_states_.erase(accepts_iter);
 
       if (view_) {
         view_->Hide();
@@ -338,12 +335,13 @@
 }
 
 const std::vector<bool>& PermissionRequestManager::AcceptStates() {
-  return accept_states_;
+  // TODO(crbug.com/728483): Remove this function.
+  CR_DEFINE_STATIC_LOCAL(std::vector<bool>, accept_states, ());
+  return accept_states;
 }
 
 void PermissionRequestManager::ToggleAccept(int request_index, bool new_value) {
-  DCHECK(request_index < static_cast<int>(accept_states_.size()));
-  accept_states_[request_index] = new_value;
+  // TODO(crbug.com/728483): Remove this function.
 }
 
 void PermissionRequestManager::TogglePersist(bool new_value) {
@@ -351,24 +349,17 @@
 }
 
 void PermissionRequestManager::Accept() {
-  PermissionUmaUtil::PermissionPromptAccepted(requests_, accept_states_);
+  PermissionUmaUtil::PermissionPromptAccepted(requests_);
 
   std::vector<PermissionRequest*>::iterator requests_iter;
-  std::vector<bool>::iterator accepts_iter = accept_states_.begin();
-  for (requests_iter = requests_.begin(), accepts_iter = accept_states_.begin();
-       requests_iter != requests_.end();
-       requests_iter++, accepts_iter++) {
-    if (*accepts_iter) {
-      PermissionGrantedIncludingDuplicates(*requests_iter);
-    } else {
-      PermissionDeniedIncludingDuplicates(*requests_iter);
-    }
+  for (requests_iter = requests_.begin(); requests_iter != requests_.end();
+       requests_iter++) {
+    PermissionGrantedIncludingDuplicates(*requests_iter);
   }
   FinalizeBubble();
 }
 
 void PermissionRequestManager::Deny() {
-  DCHECK_EQ(1u, requests_.size());
   PermissionUmaUtil::PermissionPromptDenied(requests_);
 
   std::vector<PermissionRequest*>::iterator requests_iter;
@@ -421,9 +412,6 @@
     queued_requests_.pop_front();
   }
 
-  // Sets the default value for each request to be 'accept'.
-  accept_states_.resize(requests_.size(), true);
-
   ShowBubble();
 }
 
@@ -452,7 +440,6 @@
     RequestFinishedIncludingDuplicates(*requests_iter);
   }
   requests_.clear();
-  accept_states_.clear();
   if (queued_requests_.size())
     DequeueRequestsAndShowBubble();
 }
@@ -547,14 +534,7 @@
       Accept();
       break;
     case DENY_ALL:
-      // Deny() assumes there is only 1 request.
-      if (accept_states_.size() == 1) {
-        Deny();
-      } else {
-        for (size_t i = 0; i < accept_states_.size(); ++i)
-          accept_states_[i] = false;
-        Accept();
-      }
+      Deny();
       break;
     case DISMISS:
       Closing();
diff --git a/chrome/browser/permissions/permission_request_manager.h b/chrome/browser/permissions/permission_request_manager.h
index 275f968..db8aac9 100644
--- a/chrome/browser/permissions/permission_request_manager.h
+++ b/chrome/browser/permissions/permission_request_manager.h
@@ -199,9 +199,6 @@
   // Whether the response to each request should be persisted.
   bool persist_;
 
-  // Whether each of the requests in |requests_| is accepted by the user.
-  std::vector<bool> accept_states_;
-
   base::ObserverList<Observer> observer_list_;
   AutoResponseType auto_response_for_test_;
 
diff --git a/chrome/browser/permissions/permission_request_manager_unittest.cc b/chrome/browser/permissions/permission_request_manager_unittest.cc
index 54fd984..37564927 100644
--- a/chrome/browser/permissions/permission_request_manager_unittest.cc
+++ b/chrome/browser/permissions/permission_request_manager_unittest.cc
@@ -117,7 +117,6 @@
   EXPECT_TRUE(prompt_factory_->is_visible());
   ASSERT_EQ(prompt_factory_->request_count(), 1);
 
-  ToggleAccept(0, true);
   Accept();
   EXPECT_TRUE(request1_.granted());
 }
@@ -130,7 +129,6 @@
   EXPECT_TRUE(prompt_factory_->is_visible());
   ASSERT_EQ(prompt_factory_->request_count(), 1);
 
-  ToggleAccept(0, true);
   Accept();
   EXPECT_TRUE(request1_.granted());
 }
@@ -164,8 +162,6 @@
   EXPECT_TRUE(prompt_factory_->is_visible());
   ASSERT_EQ(prompt_factory_->request_count(), 2);
 
-  ToggleAccept(0, true);
-  ToggleAccept(1, true);
   Accept();
   EXPECT_TRUE(request_mic_.granted());
   EXPECT_TRUE(request_camera_.granted());
@@ -188,9 +184,6 @@
   EXPECT_TRUE(prompt_factory_->is_visible());
   ASSERT_EQ(prompt_factory_->request_count(), 2);
 
-  ToggleAccept(0, true);
-  ToggleAccept(1, false);
-
   MockTabSwitchAway();
   EXPECT_FALSE(prompt_factory_->is_visible());
 
@@ -201,7 +194,7 @@
 
   Accept();
   EXPECT_TRUE(request_mic_.granted());
-  EXPECT_FALSE(request_camera_.granted());
+  EXPECT_TRUE(request_camera_.granted());
 }
 
 TEST_F(PermissionRequestManagerTest, NoRequests) {
@@ -513,7 +506,6 @@
   histograms.ExpectUniqueSample(
       PermissionUmaUtil::kPermissionsPromptRequestsPerPrompt, 1, 1);
 
-  ToggleAccept(0, true);
   Accept();
   histograms.ExpectUniqueSample(
       PermissionUmaUtil::kPermissionsPromptAccepted,
@@ -574,8 +566,7 @@
   // No need to test UMA for showing prompts again, they were tested in
   // UMAForSimpleAcceptedBubble.
 
-  ToggleAccept(0, false);
-  Accept();
+  Deny();
   histograms.ExpectUniqueSample(
       PermissionUmaUtil::kPermissionsPromptDenied,
       static_cast<base::HistogramBase::Sample>(PermissionRequestType::QUOTA),
@@ -611,8 +602,6 @@
   histograms.ExpectTotalCount(
       PermissionUmaUtil::kPermissionsPromptShownNoGesture, 0);
 
-  ToggleAccept(0, true);
-  ToggleAccept(1, true);
   Accept();
 
   histograms.ExpectUniqueSample(
@@ -631,36 +620,6 @@
       1);
 }
 
-TEST_F(PermissionRequestManagerTest, UMAForMergedMixedBubble) {
-  base::HistogramTester histograms;
-
-  manager_->AddRequest(&request_mic_);
-  manager_->AddRequest(&request_camera_);
-  manager_->DisplayPendingRequests();
-  WaitForBubbleToBeShown();
-  // No need to test UMA for showing prompts again, they were tested in
-  // UMAForMergedAcceptedBubble.
-
-  ToggleAccept(0, true);
-  ToggleAccept(1, false);
-  Accept();
-
-  histograms.ExpectUniqueSample(
-      PermissionUmaUtil::kPermissionsPromptDenied,
-      static_cast<base::HistogramBase::Sample>(PermissionRequestType::MULTIPLE),
-      1);
-  histograms.ExpectBucketCount(
-      PermissionUmaUtil::kPermissionsPromptMergedBubbleAccepted,
-      static_cast<base::HistogramBase::Sample>(
-          PermissionRequestType::PERMISSION_MEDIASTREAM_MIC),
-      1);
-  histograms.ExpectBucketCount(
-      PermissionUmaUtil::kPermissionsPromptMergedBubbleDenied,
-      static_cast<base::HistogramBase::Sample>(
-          PermissionRequestType::PERMISSION_MEDIASTREAM_CAMERA),
-      1);
-}
-
 TEST_F(PermissionRequestManagerTest, UMAForMergedDeniedBubble) {
   base::HistogramTester histograms;
 
@@ -671,9 +630,7 @@
   // No need to test UMA for showing prompts again, they were tested in
   // UMAForMergedAcceptedBubble.
 
-  ToggleAccept(0, false);
-  ToggleAccept(1, false);
-  Accept();
+  Deny();
 
   histograms.ExpectUniqueSample(
       PermissionUmaUtil::kPermissionsPromptDenied,
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc
index 9ddfcf5..45305b1 100644
--- a/chrome/browser/permissions/permission_uma_util.cc
+++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -390,48 +390,13 @@
 }
 
 void PermissionUmaUtil::PermissionPromptAccepted(
-    const std::vector<PermissionRequest*>& requests,
-    const std::vector<bool>& accept_states) {
-  DCHECK(!requests.empty());
-  DCHECK(requests.size() == accept_states.size());
-
-  bool all_accepted = accept_states[0];
-  PermissionRequestType permission_prompt_type =
-      requests[0]->GetPermissionRequestType();
-  PermissionRequestGestureType permission_gesture_type =
-      requests[0]->GetGestureType();
-  if (requests.size() > 1) {
-    permission_prompt_type = PermissionRequestType::MULTIPLE;
-    permission_gesture_type = PermissionRequestGestureType::UNKNOWN;
-    for (size_t i = 0; i < requests.size(); ++i) {
-      const auto* request = requests[i];
-      if (accept_states[i]) {
-        PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptMergedBubbleAccepted,
-                                   request->GetPermissionRequestType());
-      } else {
-        all_accepted = false;
-        PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptMergedBubbleDenied,
-                                   request->GetPermissionRequestType());
-      }
-    }
-  }
-
-  if (all_accepted) {
-    RecordPermissionPromptAccepted(permission_prompt_type,
-                                   permission_gesture_type);
-  } else {
-    RecordPermissionPromptDenied(permission_prompt_type,
-                                 permission_gesture_type);
-  }
+    const std::vector<PermissionRequest*>& requests) {
+  RecordPromptDecided(requests, /*accepted=*/true);
 }
 
 void PermissionUmaUtil::PermissionPromptDenied(
     const std::vector<PermissionRequest*>& requests) {
-  DCHECK(!requests.empty());
-  DCHECK(requests.size() == 1);
-
-  RecordPermissionPromptDenied(requests[0]->GetPermissionRequestType(),
-                               requests[0]->GetGestureType());
+  RecordPromptDecided(requests, /*accepted=*/false);
 }
 
 void PermissionUmaUtil::RecordPermissionPromptShown(
@@ -714,3 +679,37 @@
         rappor::GetDomainAndRegistrySampleFromGURL(requesting_origin));
   }
 }
+
+// static
+void PermissionUmaUtil::RecordPromptDecided(
+    const std::vector<PermissionRequest*>& requests,
+    bool accepted) {
+  DCHECK(!requests.empty());
+
+  PermissionRequestType permission_prompt_type =
+      requests[0]->GetPermissionRequestType();
+  PermissionRequestGestureType permission_gesture_type =
+      requests[0]->GetGestureType();
+  if (requests.size() > 1) {
+    permission_prompt_type = PermissionRequestType::MULTIPLE;
+    permission_gesture_type = PermissionRequestGestureType::UNKNOWN;
+    for (size_t i = 0; i < requests.size(); ++i) {
+      const auto* request = requests[i];
+      if (accepted) {
+        PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptMergedBubbleAccepted,
+                                   request->GetPermissionRequestType());
+      } else {
+        PERMISSION_BUBBLE_TYPE_UMA(kPermissionsPromptMergedBubbleDenied,
+                                   request->GetPermissionRequestType());
+      }
+    }
+  }
+
+  if (accepted) {
+    RecordPermissionPromptAccepted(permission_prompt_type,
+                                   permission_gesture_type);
+  } else {
+    RecordPermissionPromptDenied(permission_prompt_type,
+                                 permission_gesture_type);
+  }
+}
diff --git a/chrome/browser/permissions/permission_uma_util.h b/chrome/browser/permissions/permission_uma_util.h
index 2fa063c..c32c7b2 100644
--- a/chrome/browser/permissions/permission_uma_util.h
+++ b/chrome/browser/permissions/permission_uma_util.h
@@ -160,12 +160,8 @@
 
   // The following two functions can be combined with the PermissionPromptShown
   // metrics to calculate accept, deny and ignore rates.
-  // Note that for coalesced permission bubbles, PermissionPromptAccepted will
-  // always be called, with |accept_states| containing whether each request was
-  // accepted or denied.
   static void PermissionPromptAccepted(
-      const std::vector<PermissionRequest*>& requests,
-      const std::vector<bool>& accept_states);
+      const std::vector<PermissionRequest*>& requests);
 
   static void PermissionPromptDenied(
       const std::vector<PermissionRequest*>& requests);
@@ -219,6 +215,10 @@
       const std::string& prefix,
       int count);
 
+  static void RecordPromptDecided(
+      const std::vector<PermissionRequest*>& requests,
+      bool accepted);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionUmaUtil);
 };
 
diff --git a/chrome/browser/resources/chromeos/genius_app/manifest.json b/chrome/browser/resources/chromeos/genius_app/manifest.json
index 4677174..6a625f7 100644
--- a/chrome/browser/resources/chromeos/genius_app/manifest.json
+++ b/chrome/browser/resources/chromeos/genius_app/manifest.json
@@ -35,10 +35,9 @@
     "unlimitedStorage",
     "https://*.ytimg.com/*",
     "https://www.google.com/*",
+    "https://support.google.com/*",
     "https://commondatastorage.googleapis.com/*",
     "https://storage.googleapis.com/*",
-    "https://www-googleapis-test.sandbox.google.com/*",
-    "https://www.googleapis.com/*",
     "https://www.google-analytics.com/"
   ],
   "oauth2": {
diff --git a/chrome/browser/resources/help_app/manifest.json b/chrome/browser/resources/help_app/manifest.json
index 6707e030..0a5a98f1 100644
--- a/chrome/browser/resources/help_app/manifest.json
+++ b/chrome/browser/resources/help_app/manifest.json
@@ -6,5 +6,8 @@
   "default_locale": "en",
   "manifest_version": 2,
   "content_security_policy": "default-src 'self' blob: filesystem:; img-src 'self' blob: filesystem: data:;",
-  "incognito": "split"
+  "incognito": "split",
+  "permissions": [
+    "storage"
+  ]
 }
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js
index e2f84cd..be258a32 100644
--- a/chrome/browser/resources/md_bookmarks/command_manager.js
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js
@@ -217,6 +217,29 @@
       }
     },
 
+    /**
+     * @param {Event} e
+     * @param {!Set<string>} itemIds
+     * @return {boolean} True if the event was handled, triggering a keyboard
+     *     shortcut.
+     */
+    handleKeyEvent: function(e, itemIds) {
+      for (var commandName in this.shortcuts_) {
+        var shortcut = this.shortcuts_[commandName];
+        if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(
+                e, shortcut) &&
+            this.canExecute(commandName, itemIds)) {
+          this.handle(commandName, itemIds);
+
+          e.stopPropagation();
+          e.preventDefault();
+          return true;
+        }
+      }
+
+      return false;
+    },
+
     ////////////////////////////////////////////////////////////////////////////
     // Private functions:
 
@@ -340,20 +363,8 @@
      */
     onKeydown_: function(e) {
       var selection = this.getState().selection.items;
-      // TODO(tsergeant): Prevent keyboard shortcuts when a dialog is open or
-      // text field is focused.
-      for (var commandName in this.shortcuts_) {
-        var shortcut = this.shortcuts_[commandName];
-        if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(
-                e, shortcut) &&
-            this.canExecute(commandName, selection)) {
-          this.handle(commandName, selection);
-
-          e.stopPropagation();
-          e.preventDefault();
-          return;
-        }
-      }
+      if (e.target == document.body)
+        this.handleKeyEvent(e, selection);
     },
 
     /**
diff --git a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
index c4b7645..f88af25 100644
--- a/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_bookmarks/compiled_resources2.gyp
@@ -83,6 +83,7 @@
       'dependencies': [
         '<(EXTERNS_GYP):chrome_extensions',
         'actions',
+        'command_manager',
         'store_client',
       ],
     },
@@ -103,6 +104,7 @@
         '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-list/compiled_resources2.gyp:iron-list-extracted',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         'actions',
+        'command_manager',
         'store_client',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.html b/chrome/browser/resources/md_bookmarks/folder_node.html
index 3bb5c9b..1c2bde8 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.html
+++ b/chrome/browser/resources/md_bookmarks/folder_node.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="chrome://bookmarks/actions.html">
+<link rel="import" href="chrome://bookmarks/command_manager.html">
 <link rel="import" href="chrome://bookmarks/icons.html">
 <link rel="import" href="chrome://bookmarks/shared_style.html">
 <link rel="import" href="chrome://bookmarks/store_client.html">
diff --git a/chrome/browser/resources/md_bookmarks/folder_node.js b/chrome/browser/resources/md_bookmarks/folder_node.js
index 09dd809..f5b101e 100644
--- a/chrome/browser/resources/md_bookmarks/folder_node.js
+++ b/chrome/browser/resources/md_bookmarks/folder_node.js
@@ -110,6 +110,11 @@
     this.changeKeyboardSelection_(
         xDirection, yDirection, this.root.activeElement);
 
+    if (!handled) {
+      handled = bookmarks.CommandManager.getInstance().handleKeyEvent(
+          e, new Set([this.itemId]));
+    }
+
     if (!handled)
       return;
 
diff --git a/chrome/browser/resources/md_bookmarks/list.html b/chrome/browser/resources/md_bookmarks/list.html
index 6705d25..00c8ceaf 100644
--- a/chrome/browser/resources/md_bookmarks/list.html
+++ b/chrome/browser/resources/md_bookmarks/list.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.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-styles/shadow.html">
+<link rel="import" href="chrome://bookmarks/command_manager.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">
diff --git a/chrome/browser/resources/md_bookmarks/list.js b/chrome/browser/resources/md_bookmarks/list.js
index f960e2e..cb0bdb9 100644
--- a/chrome/browser/resources/md_bookmarks/list.js
+++ b/chrome/browser/resources/md_bookmarks/list.js
@@ -179,6 +179,15 @@
       }
     }
 
+    // Prevent the iron-list from changing focus on enter.
+    if (e.path[0] instanceof HTMLButtonElement && e.key == 'Enter')
+      handled = true;
+
+    if (!handled) {
+      handled = bookmarks.CommandManager.getInstance().handleKeyEvent(
+          e, this.getState().selection.items);
+    }
+
     if (handled)
       e.stopPropagation();
   },
diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
index 661ed01..e03a979 100644
--- a/chrome/browser/ssl/ssl_browser_tests.cc
+++ b/chrome/browser/ssl/ssl_browser_tests.cc
@@ -20,6 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/histogram_tester.h"
+#include "base/test/scoped_command_line.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/simple_test_clock.h"
 #include "base/threading/thread_restrictions.h"
@@ -1306,12 +1307,13 @@
   EXPECT_TRUE(base::LowerCaseEqualsASCII(result, "pass"));
 }
 
-// Ensure that non-standard origins are marked correctly when the
-// MarkNonSecureAs field trial is enabled.
+// Ensure that non-standard origins are marked as neutral when the
+// MarkNonSecureAs Dangerous flag is enabled.
 IN_PROC_BROWSER_TEST_F(SSLUITest, MarkFileAsNonSecure) {
-  scoped_refptr<base::FieldTrial> trial =
-      base::FieldTrialList::CreateFieldTrial(
-          "MarkNonSecureAs", security_state::switches::kMarkHttpAsDangerous);
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+      security_state::switches::kMarkHttpAs,
+      security_state::switches::kMarkHttpAsDangerous);
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -1327,10 +1329,13 @@
   EXPECT_EQ(security_state::NONE, security_info.security_level);
 }
 
+// Ensure that about-protocol origins are marked as neutral when the
+// MarkNonSecureAs Dangerous flag is enabled.
 IN_PROC_BROWSER_TEST_F(SSLUITest, MarkAboutAsNonSecure) {
-  scoped_refptr<base::FieldTrial> trial =
-      base::FieldTrialList::CreateFieldTrial(
-          "MarkNonSecureAs", security_state::switches::kMarkHttpAsDangerous);
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+      security_state::switches::kMarkHttpAs,
+      security_state::switches::kMarkHttpAsDangerous);
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
@@ -1362,10 +1367,34 @@
   EXPECT_EQ(security_state::HTTP_SHOW_WARNING, security_info.security_level);
 }
 
+// Ensure that HTTP-protocol origins are marked as Dangerous when the
+// MarkNonSecureAs Dangerous flag is enabled.
+IN_PROC_BROWSER_TEST_F(SSLUITest, MarkHTTPAsDangerous) {
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+      security_state::switches::kMarkHttpAs,
+      security_state::switches::kMarkHttpAsDangerous);
+
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  // Navigate to a non-local HTTP page.
+  ui_test_utils::NavigateToURL(browser(), GURL("http://example.com/"));
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  SecurityStateTabHelper* helper = SecurityStateTabHelper::FromWebContents(tab);
+  ASSERT_TRUE(helper);
+
+  security_state::SecurityInfo security_info;
+  helper->GetSecurityInfo(&security_info);
+  EXPECT_EQ(security_state::DANGEROUS, security_info.security_level);
+}
+
+// Ensure that blob-protocol origins are marked as neutral when the
+// MarkNonSecureAs Dangerous flag is enabled.
 IN_PROC_BROWSER_TEST_F(SSLUITest, MarkBlobAsNonSecure) {
-  scoped_refptr<base::FieldTrial> trial =
-      base::FieldTrialList::CreateFieldTrial(
-          "MarkNonSecureAs", security_state::switches::kMarkHttpAsDangerous);
+  base::test::ScopedCommandLine scoped_command_line;
+  scoped_command_line.GetProcessCommandLine()->AppendSwitchASCII(
+      security_state::switches::kMarkHttpAs,
+      security_state::switches::kMarkHttpAsDangerous);
 
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
diff --git a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
index 43c36cf..3299a596 100644
--- a/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_browsertest.cc
@@ -14,6 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/path_service.h"
+#include "base/strings/pattern.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -543,6 +544,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest, SubFrameActivation) {
+  content::ConsoleObserverDelegate console_observer(
+      web_contents(), kDisallowSubframeConsoleMessage + "*");
+  web_contents()->SetDelegate(&console_observer);
+
   GURL url(GetTestUrl(kTestFrameSetPath));
   ConfigureAsPhishingURL(url);
   ASSERT_NO_FATAL_FAILURE(
@@ -557,6 +562,57 @@
 
   tester.ExpectBucketCount(kSubresourceFilterActionsHistogram, kActionUIShown,
                            1);
+
+  // Console message for subframe blocking should be displayed.
+  EXPECT_TRUE(base::MatchPattern(
+      console_observer.message(),
+      kDisallowSubframeConsoleMessage + "*included_script.js*"));
+}
+
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       ActivationDisabled_NoConsoleMessage) {
+  content::ConsoleObserverDelegate console_observer(
+      web_contents(), kDisallowSubframeConsoleMessage + "*");
+  web_contents()->SetDelegate(&console_observer);
+
+  Configuration config(
+      subresource_filter::ActivationLevel::DISABLED,
+      subresource_filter::ActivationScope::ACTIVATION_LIST,
+      subresource_filter::ActivationList::PHISHING_INTERSTITIAL);
+  ResetConfiguration(std::move(config));
+
+  GURL url(GetTestUrl(kTestFrameSetPath));
+  ConfigureAsPhishingURL(url);
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Console message for subframe blocking should not be displayed as filtering
+  // is disabled.
+  EXPECT_TRUE(console_observer.message().empty());
+}
+
+IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
+                       ActivationDryRun_NoConsoleMessage) {
+  content::ConsoleObserverDelegate console_observer(
+      web_contents(), kDisallowSubframeConsoleMessage + "*");
+  web_contents()->SetDelegate(&console_observer);
+
+  Configuration config(
+      subresource_filter::ActivationLevel::DRYRUN,
+      subresource_filter::ActivationScope::ACTIVATION_LIST,
+      subresource_filter::ActivationList::PHISHING_INTERSTITIAL);
+  ResetConfiguration(std::move(config));
+
+  GURL url(GetTestUrl(kTestFrameSetPath));
+  ConfigureAsPhishingURL(url);
+  ASSERT_NO_FATAL_FAILURE(
+      SetRulesetToDisallowURLsWithPathSuffix("included_script.js"));
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // Console message for subframe blocking should not be displayed as filtering
+  // is enabled in dryrun mode.
+  EXPECT_TRUE(console_observer.message().empty());
 }
 
 IN_PROC_BROWSER_TEST_F(SubresourceFilterBrowserTest,
diff --git a/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc b/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
index c8f147d..35d3436f 100644
--- a/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
+++ b/chrome/browser/ui/android/infobars/grouped_permission_infobar.cc
@@ -19,21 +19,6 @@
 GroupedPermissionInfoBar::~GroupedPermissionInfoBar() {
 }
 
-bool GroupedPermissionInfoBar::Register(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-void GroupedPermissionInfoBar::SetPermissionState(
-    JNIEnv* env,
-    const base::android::JavaParamRef<jobject>& obj,
-    const base::android::JavaParamRef<jbooleanArray>& permissions) {
-  for (size_t i = 0; i < GetDelegate()->PermissionCount(); i++) {
-    jboolean value;
-    env->GetBooleanArrayRegion(permissions.obj(), i, 1, &value);
-    GetDelegate()->ToggleAccept(i, value);
-  }
-}
-
 void GroupedPermissionInfoBar::ProcessButton(int action) {
   // Check if the delegate asked us to display a persistence toggle. If so,
   // inform it of the toggle state.
@@ -80,14 +65,6 @@
       base::android::ToJavaIntArray(env, permission_icons));
 }
 
-void GroupedPermissionInfoBar::SetJavaInfoBar(
-    const base::android::JavaRef<jobject>& java_info_bar) {
-  InfoBarAndroid::SetJavaInfoBar(java_info_bar);
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_GroupedPermissionInfoBar_setNativePtr(env, java_info_bar,
-                                             reinterpret_cast<intptr_t>(this));
-}
-
 GroupedPermissionInfoBarDelegate* GroupedPermissionInfoBar::GetDelegate() {
   return static_cast<GroupedPermissionInfoBarDelegate*>(delegate());
 }
diff --git a/chrome/browser/ui/android/infobars/grouped_permission_infobar.h b/chrome/browser/ui/android/infobars/grouped_permission_infobar.h
index be8ce90..0a2de0ea 100644
--- a/chrome/browser/ui/android/infobars/grouped_permission_infobar.h
+++ b/chrome/browser/ui/android/infobars/grouped_permission_infobar.h
@@ -18,21 +18,12 @@
       std::unique_ptr<GroupedPermissionInfoBarDelegate> delegate);
   ~GroupedPermissionInfoBar() override;
 
-  void SetPermissionState(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jbooleanArray>& permissions);
-
-  static bool Register(JNIEnv* env);
-
  private:
   void ProcessButton(int action) override;
 
   // InfoBarAndroid:
   base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
       JNIEnv* env) override;
-  void SetJavaInfoBar(
-      const base::android::JavaRef<jobject>& java_info_bar) override;
 
   GroupedPermissionInfoBarDelegate* GetDelegate();
 
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
index 80539cf..6314ab2 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller.mm
@@ -31,7 +31,6 @@
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
-#include "chrome/browser/ui/page_info/permission_menu_model.h"
 #include "chrome/browser/ui/permission_bubble/permission_prompt.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
@@ -43,10 +42,8 @@
 #include "ui/base/cocoa/a11y_util.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #import "ui/base/cocoa/controls/hyperlink_text_view.h"
-#import "ui/base/cocoa/menu_controller.h"
 #include "ui/base/cocoa/window_size_constants.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/models/simple_menu_model.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image_skia_util_mac.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -72,75 +69,6 @@
 
 }  // namespace
 
-// NSPopUpButton with a menu containing two items: allow and block.
-// One AllowBlockMenuButton is used for each requested permission when there are
-// multiple permissions in the bubble.
-@interface AllowBlockMenuButton : NSPopUpButton {
- @private
-  std::unique_ptr<PermissionMenuModel> menuModel_;
-  base::scoped_nsobject<MenuController> menuController_;
-}
-
-- (id)initForURL:(const GURL&)url
-         allowed:(BOOL)allow
-           index:(int)index
-        delegate:(PermissionPrompt::Delegate*)delegate
-         profile:(Profile*)profile;
-
-// Returns the maximum width of its possible titles.
-- (CGFloat)maximumTitleWidth;
-@end
-
-@implementation AllowBlockMenuButton
-
-- (id)initForURL:(const GURL&)url
-         allowed:(BOOL)allow
-           index:(int)index
-        delegate:(PermissionPrompt::Delegate*)delegate
-         profile:(Profile*)profile {
-  if (self = [super initWithFrame:NSZeroRect pullsDown:NO]) {
-    ContentSetting setting =
-        allow ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
-    [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
-    [self setBordered:NO];
-
-    __block PermissionPrompt::Delegate* blockDelegate = delegate;
-    __block AllowBlockMenuButton* blockSelf = self;
-    PermissionMenuModel::ChangeCallback changeCallback =
-        base::BindBlock(^(const PageInfoUI::PermissionInfo& permission) {
-          blockDelegate->ToggleAccept(
-              index, permission.setting == CONTENT_SETTING_ALLOW);
-          [blockSelf setFrameSize:SizeForPageInfoButtonTitle(
-                                      blockSelf, [blockSelf title])];
-        });
-
-    menuModel_.reset(
-        new PermissionMenuModel(profile, url, setting, changeCallback));
-    menuController_.reset([[MenuController alloc] initWithModel:menuModel_.get()
-                                         useWithPopUpButtonCell:NO]);
-    [self setMenu:[menuController_ menu]];
-    [self selectItemAtIndex:menuModel_->GetIndexOfCommandId(setting)];
-    // Although the frame is reset, below, this sizes the cell properly.
-    [self sizeToFit];
-    // Adjust the size to fit the current title.  Using only -sizeToFit leaves
-    // an ugly amount of whitespace between the title and the arrows because it
-    // will fit to the largest element in the menu, not just the selected item.
-    [self setFrameSize:SizeForPageInfoButtonTitle(self, [self title])];
-  }
-  return self;
-}
-
-- (CGFloat)maximumTitleWidth {
-  CGFloat maxTitleWidth = 0;
-  for (NSMenuItem* item in [self itemArray]) {
-    NSSize size = SizeForPageInfoButtonTitle(self, [item title]);
-    maxTitleWidth = std::max(maxTitleWidth, size.width);
-  }
-  return maxTitleWidth;
-}
-
-@end
-
 @interface PermissionBubbleController ()
 
 // Determines if the bubble has an anchor in a corner or no anchor at all.
@@ -156,12 +84,6 @@
 // requesting settings for |host|.
 - (NSView*)titleWithOrigin:(const GURL&)origin;
 
-// Returns an autoreleased NSView displaying a menu for |request|.  The
-// menu will be initialized as 'allow' if |allow| is YES.
-- (NSView*)menuForRequest:(PermissionRequest*)request
-                  atIndex:(int)index
-                    allow:(BOOL)allow;
-
 // Returns an autoreleased NSView of a button with |title| and |action|.
 - (NSView*)buttonWithTitle:(NSString*)title
                     action:(SEL)action;
@@ -291,24 +213,11 @@
   NSView* contentView = [[self window] contentView];
   [contentView setSubviews:@[]];
 
-  BOOL singlePermission = requests.size() == 1;
-
   // Create one button to use as a guide for the permissions' y-offsets.
-  base::scoped_nsobject<NSView> allowOrOkButton;
-  if (singlePermission) {
-    NSString* allowTitle = l10n_util::GetNSString(IDS_PERMISSION_ALLOW);
-    allowOrOkButton.reset([[self buttonWithTitle:allowTitle
-                                          action:@selector(onAllow:)] retain]);
-  } else {
-    NSString* okTitle = l10n_util::GetNSString(IDS_OK);
-    allowOrOkButton.reset([[self buttonWithTitle:okTitle
-                                          action:@selector(ok:)] retain]);
-  }
-  CGFloat yOffset = 2 * kVerticalPadding + NSMaxY([allowOrOkButton frame]);
-
-  base::scoped_nsobject<NSMutableArray> permissionMenus;
-  if (!singlePermission)
-    permissionMenus.reset([[NSMutableArray alloc] init]);
+  NSString* allowTitle = l10n_util::GetNSString(IDS_PERMISSION_ALLOW);
+  base::scoped_nsobject<NSView> allowButton(
+      [[self buttonWithTitle:allowTitle action:@selector(onAllow:)] retain]);
+  CGFloat yOffset = 2 * kVerticalPadding + NSMaxY([allowButton frame]);
 
   CGFloat maxPermissionLineWidth = 0;
   CGFloat verticalPadding = 0.0f;
@@ -321,18 +230,6 @@
     [permissionView setFrameOrigin:origin];
     [contentView addSubview:permissionView];
 
-    if (!singlePermission) {
-      int index = it - requests.begin();
-      base::scoped_nsobject<NSView> menu([[self
-          menuForRequest:(*it)atIndex:index
-                   allow:delegate->AcceptStates()[index] ? YES : NO] retain]);
-      // Align vertically.  Horizontal alignment will be adjusted once the
-      // widest permission is know.
-      [PermissionBubbleController alignCenterOf:menu
-                           verticallyToCenterOf:permissionView];
-      [permissionMenus addObject:menu];
-      [contentView addSubview:menu];
-    }
     maxPermissionLineWidth = std::max(
         maxPermissionLineWidth, NSMaxX([permissionView frame]));
     yOffset += NSHeight([permissionView frame]);
@@ -351,23 +248,13 @@
   base::scoped_nsobject<NSView> closeButton([[self closeButton] retain]);
 
   // Determine the dimensions of the bubble.
-  // Once the height and width are set, the buttons and permission menus can
-  // be laid out correctly.
+  // Once the height and width are set, the buttons can be laid out correctly.
   NSRect bubbleFrame = NSMakeRect(0, 0, kBubbleMinWidth, 0);
 
   // Fix the height of the bubble relative to the title.
   bubbleFrame.size.height = NSMaxY([titleView frame]) + kVerticalPadding +
                             info_bubble::kBubbleArrowHeight;
 
-  if (!singlePermission) {
-    // Add the maximum menu width to the bubble width.
-    CGFloat maxMenuWidth = 0;
-    for (AllowBlockMenuButton* button in permissionMenus.get()) {
-      maxMenuWidth = std::max(maxMenuWidth, [button maximumTitleWidth]);
-    }
-    maxPermissionLineWidth += maxMenuWidth;
-  }
-
   // The title and 'x' button row must fit within the bubble.
   CGFloat titleRowWidth = NSMaxX([titleView frame]) +
                           NSWidth([closeButton frame]) +
@@ -378,8 +265,7 @@
                std::max(titleRowWidth, maxPermissionLineWidth)) +
       kHorizontalPadding;
 
-  // Now that the bubble's dimensions have been set, lay out the buttons and
-  // menus.
+  // Now that the bubble's dimensions have been set, lay out the buttons.
 
   // Place the close button at the upper-right-hand corner of the bubble.
   NSPoint closeButtonOrigin =
@@ -394,32 +280,22 @@
   [contentView addSubview:closeButton];
 
   // Position the allow/ok button.
-  CGFloat xOrigin = NSWidth(bubbleFrame) - NSWidth([allowOrOkButton frame]) -
+  CGFloat xOrigin = NSWidth(bubbleFrame) - NSWidth([allowButton frame]) -
                     kButtonRightEdgePadding;
-  [allowOrOkButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
-  [contentView addSubview:allowOrOkButton];
+  [allowButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
+  [contentView addSubview:allowButton];
 
-  if (singlePermission) {
-    base::scoped_nsobject<NSView> blockButton;
-    blockButton.reset([[self blockButton] retain]);
-    CGFloat width = [PermissionBubbleController matchWidthsOf:blockButton
-                                                        andOf:allowOrOkButton];
-    // Ensure the allow/ok button is still in the correct position.
-    xOrigin = NSWidth(bubbleFrame) - width - kHorizontalPadding;
-    [allowOrOkButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
-    // Line up the block button.
-    xOrigin = NSMinX([allowOrOkButton frame]) - width - kBetweenButtonsPadding;
-    [blockButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
-    [contentView addSubview:blockButton];
-  } else {
-    // Adjust the horizontal origin for each menu so that its right edge
-    // lines up with the right edge of the ok button.
-    CGFloat rightEdge = NSMaxX([allowOrOkButton frame]);
-    for (NSView* view in permissionMenus.get()) {
-      [view setFrameOrigin:NSMakePoint(rightEdge - NSWidth([view frame]),
-                                       NSMinY([view frame]))];
-    }
-  }
+  base::scoped_nsobject<NSView> blockButton;
+  blockButton.reset([[self blockButton] retain]);
+  CGFloat width =
+      [PermissionBubbleController matchWidthsOf:blockButton andOf:allowButton];
+  // Ensure the allow/ok button is still in the correct position.
+  xOrigin = NSWidth(bubbleFrame) - width - kHorizontalPadding;
+  [allowButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
+  // Line up the block button.
+  xOrigin = NSMinX([allowButton frame]) - width - kBetweenButtonsPadding;
+  [blockButton setFrameOrigin:NSMakePoint(xOrigin, kVerticalPadding)];
+  [contentView addSubview:blockButton];
 
   bubbleFrame = [[self window] frameRectForContentRect:bubbleFrame];
   if ([[self window] isVisible]) {
@@ -437,7 +313,7 @@
     [self setAnchorPoint:[self getExpectedAnchorPoint]];
     [self showWindow:nil];
     [[self window] makeFirstResponder:nil];
-    [[self window] setInitialFirstResponder:allowOrOkButton.get()];
+    [[self window] setInitialFirstResponder:allowButton.get()];
   }
 }
 
@@ -532,20 +408,6 @@
   return titleView.autorelease();
 }
 
-- (NSView*)menuForRequest:(PermissionRequest*)request
-                  atIndex:(int)index
-                    allow:(BOOL)allow {
-  DCHECK(request);
-  DCHECK(delegate_);
-  base::scoped_nsobject<AllowBlockMenuButton> button(
-      [[AllowBlockMenuButton alloc] initForURL:request->GetOrigin()
-                                       allowed:allow
-                                         index:index
-                                      delegate:delegate_
-                                       profile:browser_->profile()]);
-  return button.autorelease();
-}
-
 - (NSView*)buttonWithTitle:(NSString*)title
                     action:(SEL)action {
   base::scoped_nsobject<NSButton> button(
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
index 8583736c..982c8842 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_controller_unittest.mm
@@ -97,7 +97,11 @@
     return requests_;
   }
 
-  const std::vector<bool>& AcceptStates() override { return accept_states_; }
+  const std::vector<bool>& AcceptStates() override {
+    // TODO(crbug.com/728483): Remove this function.
+    CR_DEFINE_STATIC_LOCAL(std::vector<bool>, accept_states, ());
+    return accept_states;
+  }
 
   void AddRequest(const std::string& title) {
     std::unique_ptr<MockPermissionRequest> request =
@@ -118,11 +122,6 @@
                                [ConstrainedWindowButton class]);
   }
 
-  NSButton* FindMenuButtonWithTitle(int title_id) {
-    return FindButtonWithTitle(l10n_util::GetNSString(title_id),
-                               [NSPopUpButton class]);
-  }
-
   // IDS_PERMISSION_ALLOW and IDS_PERMISSION_DENY are used for two distinct
   // UI elements, both of which derive from NSButton.  So check the expected
   // class, not just NSButton, as well as the title.
@@ -154,15 +153,6 @@
     return textField;
   }
 
-  void ChangePermissionMenuSelection(NSButton* menu_button, int next_title_id) {
-    NSMenu* menu = [base::mac::ObjCCastStrict<NSPopUpButton>(menu_button) menu];
-    NSString* next_title = l10n_util::GetNSString(next_title_id);
-    EXPECT_EQ([[menu itemWithTitle:[menu_button title]] state], NSOnState);
-    NSMenuItem* next_item = [menu itemWithTitle:next_title];
-    EXPECT_EQ([next_item state], NSOffState);
-    [menu performActionForItemAtIndex:[menu indexOfItem:next_item]];
-  }
-
  protected:
   PermissionBubbleController* controller_;  // Weak;  it deletes itself.
   std::unique_ptr<PermissionBubbleCocoa> bridge_;
@@ -203,91 +193,20 @@
   EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
   EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
   EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_DENY));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_OK));
 }
 
 TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissions) {
   AddRequest(kPermissionB);
   AddRequest(kPermissionC);
 
-  accept_states_.push_back(true);  // A
-  accept_states_.push_back(true);  // B
-  accept_states_.push_back(true);  // C
-
   [controller_ showWithDelegate:this];
 
   EXPECT_TRUE(FindTextFieldWithString(kPermissionA));
   EXPECT_TRUE(FindTextFieldWithString(kPermissionB));
   EXPECT_TRUE(FindTextFieldWithString(kPermissionC));
 
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
-  EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
-}
-
-TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsAllow) {
-  AddRequest(kPermissionB);
-
-  accept_states_.push_back(true);  // A
-  accept_states_.push_back(true);  // B
-
-  [controller_ showWithDelegate:this];
-
-  // Test that all menus have 'Allow' visible.
-  EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
-  EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
-
-  EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
-}
-
-TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsBlock) {
-  AddRequest(kPermissionB);
-
-  accept_states_.push_back(false);  // A
-  accept_states_.push_back(false);  // B
-
-  [controller_ showWithDelegate:this];
-
-  // Test that all menus have 'Block' visible.
-  EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
-  EXPECT_FALSE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
-
-  EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
-}
-
-TEST_F(PermissionBubbleControllerTest, ShowMultiplePermissionsMixed) {
-  AddRequest(kPermissionB);
-  AddRequest(kPermissionC);
-
-  accept_states_.push_back(false);  // A
-  accept_states_.push_back(false);  // B
-  accept_states_.push_back(true);   // C
-
-  [controller_ showWithDelegate:this];
-
-  // Test that both 'allow' and 'deny' are visible.
-  EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_DENY));
-  EXPECT_TRUE(FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW));
-
-  EXPECT_TRUE(FindButtonWithTitle(IDS_OK));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
-  EXPECT_FALSE(FindButtonWithTitle(IDS_PERMISSION_DENY));
-}
-
-TEST_F(PermissionBubbleControllerTest, OK) {
-  AddRequest(kPermissionB);
-
-  accept_states_.push_back(true);  // A
-  accept_states_.push_back(true);  // B
-
-  [controller_ showWithDelegate:this];
-
-  EXPECT_CALL(*this, Accept()).Times(1);
-  [FindButtonWithTitle(IDS_OK) performClick:nil];
+  EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_ALLOW));
+  EXPECT_TRUE(FindButtonWithTitle(IDS_PERMISSION_DENY));
 }
 
 TEST_F(PermissionBubbleControllerTest, Allow) {
@@ -297,6 +216,15 @@
   [FindButtonWithTitle(IDS_PERMISSION_ALLOW) performClick:nil];
 }
 
+TEST_F(PermissionBubbleControllerTest, AllowMultiple) {
+  AddRequest(kPermissionB);
+
+  [controller_ showWithDelegate:this];
+
+  EXPECT_CALL(*this, Accept()).Times(1);
+  [FindButtonWithTitle(IDS_PERMISSION_ALLOW) performClick:nil];
+}
+
 TEST_F(PermissionBubbleControllerTest, Deny) {
   [controller_ showWithDelegate:this];
 
@@ -304,20 +232,13 @@
   [FindButtonWithTitle(IDS_PERMISSION_DENY) performClick:nil];
 }
 
-TEST_F(PermissionBubbleControllerTest, ChangePermissionSelection) {
+TEST_F(PermissionBubbleControllerTest, DenyMultiple) {
   AddRequest(kPermissionB);
 
-  accept_states_.push_back(true);   // A
-  accept_states_.push_back(false);  // B
-
   [controller_ showWithDelegate:this];
 
-  EXPECT_CALL(*this, ToggleAccept(0, false)).Times(1);
-  EXPECT_CALL(*this, ToggleAccept(1, true)).Times(1);
-  NSButton* menu_a = FindMenuButtonWithTitle(IDS_PERMISSION_ALLOW);
-  NSButton* menu_b = FindMenuButtonWithTitle(IDS_PERMISSION_DENY);
-  ChangePermissionMenuSelection(menu_a, IDS_PERMISSION_DENY);
-  ChangePermissionMenuSelection(menu_b, IDS_PERMISSION_ALLOW);
+  EXPECT_CALL(*this, Deny()).Times(1);
+  [FindButtonWithTitle(IDS_PERMISSION_DENY) performClick:nil];
 }
 
 TEST_F(PermissionBubbleControllerTest, EscapeCloses) {
diff --git a/chrome/browser/ui/views/harmony/harmony_typography_provider.cc b/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
index 3f7f245..939f5a5 100644
--- a/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
+++ b/chrome/browser/ui/views/harmony/harmony_typography_provider.cc
@@ -22,12 +22,6 @@
   constexpr int kBodyTextLargeSize = 13;
   constexpr int kDefaultSize = 12;
 
-#if defined(OS_WIN)
-  constexpr gfx::Font::Weight kButtonFontWeight = gfx::Font::Weight::BOLD;
-#else
-  constexpr gfx::Font::Weight kButtonFontWeight = gfx::Font::Weight::MEDIUM;
-#endif
-
   int size_delta = kDefaultSize - gfx::PlatformFont::kDefaultBaseFontSize;
   gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
 
@@ -37,7 +31,7 @@
 
   switch (context) {
     case views::style::CONTEXT_BUTTON_MD:
-      font_weight = WeightNotLighterThanNormal(kButtonFontWeight);
+      font_weight = WeightNotLighterThanNormal(gfx::Font::Weight::MEDIUM);
       break;
     case views::style::CONTEXT_DIALOG_TITLE:
       size_delta = kTitleSize - gfx::PlatformFont::kDefaultBaseFontSize;
diff --git a/chrome/browser/ui/views/sad_tab_view.cc b/chrome/browser/ui/views/sad_tab_view.cc
index 2c7b8f3c..c62972d 100644
--- a/chrome/browser/ui/views/sad_tab_view.cc
+++ b/chrome/browser/ui/views/sad_tab_view.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/harmony/chrome_typography.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -24,7 +25,6 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/link.h"
 #include "ui/views/layout/grid_layout.h"
-#include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
 namespace {
@@ -42,8 +42,8 @@
 
   label->SetMultiLine(true);
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  label->SetLineHeight(views::kPanelSubVerticalSpacing);
-
+  label->SetLineHeight(ChromeLayoutProvider::Get()->GetDistanceMetric(
+      DISTANCE_UNRELATED_CONTROL_VERTICAL));
   return label;
 }
 
@@ -60,18 +60,27 @@
 
   const int column_set_id = 0;
   views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
-  columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
+
+  // TODO(ananta)
+  // This view should probably be styled as web UI.
+  ChromeLayoutProvider* provider = ChromeLayoutProvider::Get();
+  const int unrelated_horizontal_spacing = provider->GetDistanceMetric(
+          DISTANCE_UNRELATED_CONTROL_HORIZONTAL);
+  columns->AddPaddingColumn(1, unrelated_horizontal_spacing);
   columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
                      views::GridLayout::USE_PREF, 0, kMinColumnWidth);
   columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0,
                      views::GridLayout::USE_PREF, 0, kMinColumnWidth);
-  columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
+  columns->AddPaddingColumn(1, unrelated_horizontal_spacing);
 
   views::ImageView* image = new views::ImageView();
 
   image->SetImage(
       gfx::CreateVectorIcon(kCrashedTabIcon, 48, gfx::kChromeIconGrey));
-  layout->AddPaddingRow(1, views::kPanelVerticalSpacing);
+
+  const int unrelated_vertical_spacing_large = provider->GetDistanceMetric(
+      DISTANCE_UNRELATED_CONTROL_VERTICAL_LARGE);
+  layout->AddPaddingRow(1, unrelated_vertical_spacing_large);
   layout->StartRow(0, column_set_id);
   layout->AddView(image, 2, 1);
 
@@ -81,19 +90,20 @@
   title_->SetMultiLine(true);
   title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   layout->StartRowWithPadding(0, column_set_id, 0,
-                              views::kPanelVerticalSpacing);
+      unrelated_vertical_spacing_large);
   layout->AddView(title_, 2, 1);
 
   message_ = CreateFormattedLabel(l10n_util::GetStringUTF16(GetMessage()));
   layout->StartRowWithPadding(0, column_set_id, 0, kTitleBottomSpacing);
   layout->AddView(message_, 2, 1, views::GridLayout::LEADING,
                   views::GridLayout::LEADING);
+
   size_t bullet_id = 0;
   int bullet_string_id = GetSubMessage(bullet_id);
   if (bullet_string_id) {
     const int bullet_columnset_id = 1;
     views::ColumnSet* column_set = layout->AddColumnSet(bullet_columnset_id);
-    column_set->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
+    column_set->AddPaddingColumn(1, unrelated_horizontal_spacing);
     column_set->AddColumn(views::GridLayout::TRAILING,
                           views::GridLayout::LEADING, 0,
                           views::GridLayout::FIXED, kBulletWidth, 0);
@@ -103,7 +113,7 @@
                           views::GridLayout::USE_PREF,
                           0,  // No fixed width.
                           0);
-    column_set->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
+    column_set->AddPaddingColumn(1, unrelated_horizontal_spacing);
 
     while (bullet_string_id) {
       const base::string16 bullet_character(base::WideToUTF16(L"\u2022"));
@@ -126,13 +136,14 @@
   help_link_ = new views::Link(l10n_util::GetStringUTF16(GetHelpLinkTitle()));
   help_link_->set_listener(this);
   layout->StartRowWithPadding(0, column_set_id, 0,
-                              views::kPanelVerticalSpacing);
+      unrelated_vertical_spacing_large);
   layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
                   views::GridLayout::CENTER);
   layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
                   views::GridLayout::LEADING);
 
-  layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing);
+  layout->AddPaddingRow(2, provider->GetDistanceMetric(
+      DISTANCE_UNRELATED_CONTROL_VERTICAL));
 
   views::Widget::InitParams sad_tab_params(
       views::Widget::InitParams::TYPE_CONTROL);
@@ -172,12 +183,13 @@
 void SadTabView::Layout() {
   // Specify the maximum message width explicitly.
   const int max_width =
-      std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth);
+      std::min(width() - ChromeLayoutProvider::Get()->GetDistanceMetric(
+          DISTANCE_UNRELATED_CONTROL_HORIZONTAL) * 2, kMaxContentWidth);
 
   message_->SizeToFit(max_width);
   title_->SizeToFit(max_width);
 
-  // Bullet labels need to take into acocunt the size of the bullet.
+  // Bullet labels need to take into account the size of the bullet.
   for (views::Label* label : bullet_labels_)
     label->SizeToFit(max_width - kBulletWidth - kBulletPadding);
 
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index 67f3955d..a1113ad 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -241,6 +241,12 @@
 }
 
 void GaiaScreenHandler::MaybePreloadAuthExtension() {
+  // We shall not have network portal detector initialized, which unnecessarily
+  // polls captive portal checking URL if we don't need to load gaia. See
+  // go/bad-portal for more context.
+  if (!signin_screen_handler_->ShouldLoadGaia())
+    return;
+
   VLOG(1) << "MaybePreloadAuthExtension";
 
   if (!network_portal_detector_) {
@@ -254,8 +260,7 @@
 
   // If cookies clearing was initiated or |dns_clear_task_running_| then auth
   // extension showing has already been initiated and preloading is pointless.
-  if (signin_screen_handler_->ShouldLoadGaia() && !gaia_silent_load_ &&
-      !cookies_cleared_ && !dns_clear_task_running_ &&
+  if (!gaia_silent_load_ && !cookies_cleared_ && !dns_clear_task_running_ &&
       network_state_informer_->state() == NetworkStateInformer::ONLINE) {
     gaia_silent_load_ = true;
     gaia_silent_load_network_ = network_state_informer_->network_path();
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc
index 223aa32..8820718e 100644
--- a/chrome/installer/util/master_preferences.cc
+++ b/chrome/installer/util/master_preferences.cc
@@ -295,10 +295,6 @@
   return ExtractPrefString(variations::prefs::kVariationsCompressedSeed);
 }
 
-std::string MasterPreferences::GetVariationsSeed() const {
-  return ExtractPrefString(variations::prefs::kVariationsSeed);
-}
-
 std::string MasterPreferences::GetVariationsSeedSignature() const {
   return ExtractPrefString(variations::prefs::kVariationsSeedSignature);
 }
diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h
index 1eadf29..160eca6 100644
--- a/chrome/installer/util/master_preferences.h
+++ b/chrome/installer/util/master_preferences.h
@@ -161,9 +161,6 @@
   // Returns the compressed variations seed entry from the master prefs.
   std::string GetCompressedVariationsSeed() const;
 
-  // Returns the variations seed entry from the master prefs.
-  std::string GetVariationsSeed() const;
-
   // Returns the variations seed signature entry from the master prefs.
   std::string GetVariationsSeedSignature() const;
 
diff --git a/chrome/renderer/net/net_error_helper.cc b/chrome/renderer/net/net_error_helper.cc
index 8bc5649..1448dd9 100644
--- a/chrome/renderer/net/net_error_helper.cc
+++ b/chrome/renderer/net/net_error_helper.cc
@@ -320,7 +320,7 @@
 }
 
 void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
-  blink::WebFrame* web_frame = render_frame()->GetWebFrame();
+  blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
   DCHECK_NE("POST", web_frame->DataSource()->GetRequest().HttpMethod().Ascii());
 
   blink::WebURLRequest request(page_url);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7fac6655..02b76e5 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2867,10 +2867,7 @@
     ]
 
     if (enable_pepper_cdms) {
-      deps += [
-        "//chrome/browser:pepper_cdm_test_constants",
-        "//media:cdm_paths",
-      ]
+      deps += [ "//media:cdm_paths" ]
       data_deps = [
         "//media/cdm/ppapi:clearkeycdmadapter",
         "//third_party/widevine/cdm:widevinecdmadapter",
diff --git a/chrome/test/chromedriver/chrome/version.cc b/chrome/test/chromedriver/chrome/version.cc
index 79b5b15..a3ef8a1 100644
--- a/chrome/test/chromedriver/chrome/version.cc
+++ b/chrome/test/chromedriver/chrome/version.cc
@@ -9,7 +9,7 @@
 namespace {
 
 // This variable must be able to be found and parsed by the upload script.
-const int kMinimumSupportedChromeVersion[] = {57, 0, 2987, 0};
+const int kMinimumSupportedChromeVersion[] = {58, 0, 3029, 0};
 
 }  // namespace
 
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index e25b84f..183f8656 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -193,15 +193,15 @@
       # Linux32 builds need to be special-cased, because 1) they are keyed by
       # git hash rather than commit position, and 2) come from a different
       # download site (so we can't just convert the commit position to a hash).
+      versions['60'] = 'c1148176d6794fff0fd8dba2b9f7ed71ec52fed8'
       versions['59'] = 'c407e95a371a94bfd714e25eab788c9405de6975'
       versions['58'] = '7613176285d46fbc5b4712e42bd135aae99cbba5'
-      versions['57'] = '7da9cd89d4d18e171323ff7d0d2a93ede0c1d721'
       # TODO(samuong): speculative fix for crbug.com/611886
       os.environ['CHROME_DEVEL_SANDBOX'] = '/opt/chromium/chrome_sandbox'
     else:
+      versions['60'] = '474969'
       versions['59'] = '464674'
       versions['58'] = '454475'
-      versions['57'] = '444890'
     code = 0
     for version, revision in versions.iteritems():
       if options.chrome_version and version != options.chrome_version:
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 859e32f..4786e8d 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -76,19 +76,14 @@
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1819
     'ChromeExtensionsCapabilityTest.testIFrameWithExtensionsSource',
 ]
+_VERSION_SPECIFIC_FILTER['60'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1819
+    'ChromeExtensionsCapabilityTest.testIFrameWithExtensionsSource',
+]
 _VERSION_SPECIFIC_FILTER['58'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1673
     'ChromeDriverPageLoadTimeoutTest.testPageLoadTimeoutCrossDomain',
 ]
-_VERSION_SPECIFIC_FILTER['57'] = [
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
-    'ChromeDriverTest.testWindowMaximize',
-    'ChromeDriverTest.testWindowPosition',
-    'ChromeDriverTest.testWindowSize',
-    'ChromeExtensionsCapabilityTest.testCanInspectBackgroundPage',
-    'ChromeExtensionsCapabilityTest.testCanLaunchApp',
-    'MobileEmulationCapabilityTest.testDeviceMetricsWithStandardWidth',
-]
 
 _OS_SPECIFIC_FILTER = {}
 _OS_SPECIFIC_FILTER['win'] = [
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 2f0a982..b3f3954c 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -108,13 +108,6 @@
         'WindowSwitchingTest.testShouldBeAbleToIterateOverAllOpenWindows',
     ]
 )
-_REVISION_NEGATIVE_FILTER['57'] = (
-    _REVISION_NEGATIVE_FILTER['HEAD'] + [
-        # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1625
-        'TakesScreenshotTest.*',
-        'WindowTest.*',
-    ]
-)
 
 _OS_NEGATIVE_FILTER = {}
 _OS_NEGATIVE_FILTER['win'] = [
diff --git a/chrome/test/data/webui/md_bookmarks/command_manager_test.js b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
index ca849ce..2eab6fea 100644
--- a/chrome/test/data/webui/md_bookmarks/command_manager_test.js
+++ b/chrome/test/data/webui/md_bookmarks/command_manager_test.js
@@ -76,21 +76,21 @@
     store.data.selection.items = new Set(['13']);
     store.notifyObservers();
 
-    MockInteractions.pressAndReleaseKeyOn(document, 67, modifier, 'c');
+    MockInteractions.pressAndReleaseKeyOn(document.body, 67, modifier, 'c');
     commandManager.assertLastCommand('copy', ['13']);
 
     // Doesn't trigger when a folder is selected.
     store.data.selection.items = new Set(['11']);
     store.notifyObservers();
 
-    MockInteractions.pressAndReleaseKeyOn(document, 67, modifier, 'c');
+    MockInteractions.pressAndReleaseKeyOn(document.body, 67, modifier, 'c');
     commandManager.assertLastCommand(null);
 
     // Doesn't trigger when nothing is selected.
     store.data.selection.items = new Set();
     store.notifyObservers();
 
-    MockInteractions.pressAndReleaseKeyOn(document, 67, modifier, 'c');
+    MockInteractions.pressAndReleaseKeyOn(document.body, 67, modifier, 'c');
     commandManager.assertLastCommand(null);
   });
 
@@ -98,7 +98,7 @@
     store.data.selection.items = new Set(['12', '13']);
     store.notifyObservers();
 
-    MockInteractions.pressAndReleaseKeyOn(document, 46, '', 'Delete');
+    MockInteractions.pressAndReleaseKeyOn(document.body, 46, '', 'Delete');
     commandManager.assertLastCommand('delete', ['12', '13']);
   });
 
@@ -109,7 +109,7 @@
     store.data.selection.items = new Set(['11']);
     store.notifyObservers();
 
-    MockInteractions.pressAndReleaseKeyOn(document, keyCode, '', key);
+    MockInteractions.pressAndReleaseKeyOn(document.body, keyCode, '', key);
     commandManager.assertLastCommand('edit', ['11']);
   });
 
@@ -119,10 +119,12 @@
     var redoModifier = cr.isMac ? ['meta', 'shift'] : 'ctrl'
     var redoKey = cr.isMac ? 'z' : 'y';
 
-    MockInteractions.pressAndReleaseKeyOn(document, '', undoModifier, undoKey);
+    MockInteractions.pressAndReleaseKeyOn(
+        document.body, '', undoModifier, undoKey);
     commandManager.assertLastCommand('undo');
 
-    MockInteractions.pressAndReleaseKeyOn(document, '', redoModifier, redoKey);
+    MockInteractions.pressAndReleaseKeyOn(
+        document.body, '', redoModifier, redoKey);
     commandManager.assertLastCommand('redo');
   });
 
@@ -156,7 +158,7 @@
       lastCreate = createConfig;
     };
 
-    MockInteractions.pressAndReleaseKeyOn(document, 13, 'shift', 'Enter');
+    MockInteractions.pressAndReleaseKeyOn(document.body, 13, 'shift', 'Enter');
     commandManager.assertLastCommand(Command.OPEN_NEW_WINDOW, ['12', '13']);
     assertDeepEquals(['http://121/', 'http://13/'], lastCreate.url);
     assertFalse(lastCreate.incognito);
diff --git a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
index d7957ff7..f19ebf5 100644
--- a/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
+++ b/chrome/test/data/webui/md_bookmarks/md_bookmarks_focus_test.js
@@ -24,6 +24,7 @@
       [{switchName: 'enable-features', switchValue: 'MaterialDesignBookmarks'}],
 
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
+    'test_command_manager.js',
     'test_store.js',
     'test_util.js',
   ]),
@@ -178,6 +179,20 @@
 
       document.body.style.direction = 'ltr';
     });
+
+    test('keyboard commands are passed to command manager', function() {
+      var commandManager = new TestCommandManager();
+      document.body.appendChild(commandManager);
+      chrome.bookmarkManagerPrivate.removeTrees = function() {}
+
+      store.data.selection.items = new Set(['3', '4']);
+      store.notifyObservers();
+
+      getFolderNode('1').$.container.focus();
+      keydown('1', 'delete');
+
+      commandManager.assertLastCommand(Command.DELETE, ['1']);
+    });
   });
 
   suite('<bookmarks-list>', function() {
@@ -344,6 +359,37 @@
       assertDeepEquals(
           ['2', '4', '5', '6'], normalizeSet(store.data.selection.items));
     });
+
+    test('keyboard commands are passed to command manager', function() {
+      var commandManager = new TestCommandManager();
+      document.body.appendChild(commandManager);
+      chrome.bookmarkManagerPrivate.removeTrees = function() {}
+
+      store.data.selection.items = new Set(['2', '3']);
+      store.notifyObservers();
+
+      var focusedItem = items[4];
+      focusedItem.focus();
+
+      keydown(focusedItem, 'Delete');
+      // Commands should take affect on the selection, even if something else is
+      // focused.
+      commandManager.assertLastCommand(Command.DELETE, ['2', '3']);
+    });
+
+    test('iron-list does not steal focus on enter', function() {
+      // Iron-list attempts to focus the whole <bookmarks-item> when pressing
+      // enter on the menu button. This checks that we block this behavior
+      // during keydown on <bookmarks-list>.
+      var commandManager = new TestCommandManager();
+      document.body.appendChild(commandManager);
+
+      var button = items[0].$$('.more-vert-button');
+      button.focus();
+      keydown(button, 'Enter');
+
+      assertEquals(button, items[0].root.activeElement);
+    });
   });
 
   mocha.run();
diff --git a/chrome/test/data/webui/md_bookmarks/toolbar_test.js b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
index 9144e55..b5c697a 100644
--- a/chrome/test/data/webui/md_bookmarks/toolbar_test.js
+++ b/chrome/test/data/webui/md_bookmarks/toolbar_test.js
@@ -53,4 +53,15 @@
 
     commandManager.assertLastCommand(Command.DELETE, ['2', '3']);
   });
+
+  test('commands do not trigger from the search field', function() {
+    store.data.selection.items = new Set(['2']);
+    store.notifyObservers();
+
+    var input = toolbar.$$('cr-toolbar').getSearchField().getSearchInput();
+    var modifier = cr.isMac ? 'meta' : 'ctrl';
+    MockInteractions.pressAndReleaseKeyOn(input, 67, modifier, 'c');
+
+    commandManager.assertLastCommand(null);
+  });
 });
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index d0d7419..9b31d03 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -213,8 +213,10 @@
   void OnEndOfStream() override {}
 
   void OnDecoderError() override {
+    VLOG(1) << this << ": " << __func__;
     DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-    OnPushBufferComplete(MediaPipelineBackend::kBufferFailed);
+    if (source_callback_)
+      source_callback_->OnError();
   }
 
   void OnKeyStatusChanged(const std::string& key_id,
diff --git a/chromeos/components/tether/ble_scanner.cc b/chromeos/components/tether/ble_scanner.cc
index ed9256f..8f5a7547 100644
--- a/chromeos/components/tether/ble_scanner.cc
+++ b/chromeos/components/tether/ble_scanner.cc
@@ -31,18 +31,6 @@
 // advertising device to the scanning device.
 const size_t kMinNumBytesInServiceData = 4;
 
-// Returns out |string|s data as a hex string.
-std::string StringToHexOfContents(const std::string& string) {
-  std::stringstream ss;
-  ss << "0x" << std::hex;
-
-  for (size_t i = 0; i < string.size(); i++) {
-    ss << static_cast<int>(string.data()[i]);
-  }
-
-  return ss.str();
-}
-
 }  // namespace
 
 BleScanner::ServiceDataProviderImpl::ServiceDataProviderImpl() {}
@@ -263,17 +251,16 @@
       eid_generator_->IdentifyRemoteDeviceByAdvertisement(
           service_data, registered_remote_devices_, beacon_seeds);
 
-  if (identified_device) {
-    PA_LOG(INFO) << "Received advertisement from remote device with ID "
-                 << identified_device->GetTruncatedDeviceIdForLogs() << ".";
-    for (auto& observer : observer_list_) {
-      observer.OnReceivedAdvertisementFromDevice(bluetooth_device->GetAddress(),
-                                                 *identified_device);
-    }
-  } else {
-    PA_LOG(INFO) << "Received advertisement remote device, but could not "
-                 << "identify the device. Service data: "
-                 << StringToHexOfContents(service_data) << ".";
+  // If the service data does not correspond to an advertisement from a device
+  // on this account, ignore it.
+  if (!identified_device)
+    return;
+
+  PA_LOG(INFO) << "Received advertisement from remote device with ID "
+               << identified_device->GetTruncatedDeviceIdForLogs() << ".";
+  for (auto& observer : observer_list_) {
+    observer.OnReceivedAdvertisementFromDevice(bluetooth_device->GetAddress(),
+                                               *identified_device);
   }
 }
 
diff --git a/chromeos/dbus/proto/media_perception.proto b/chromeos/dbus/proto/media_perception.proto
index c14ef236..62ea9877 100644
--- a/chromeos/dbus/proto/media_perception.proto
+++ b/chromeos/dbus/proto/media_perception.proto
@@ -91,6 +91,7 @@
     UNSPECIFIED = 0;
     FACE = 1;
     PERSON = 2;
+    MOTION_REGION = 3;
   }
 
   optional EntityType type = 2;
@@ -100,6 +101,9 @@
 
   // A value for the quality of this detection.
   optional float confidence = 4;
+
+  // Perpendicular distance (depth) from the camera plane to the entity.
+  optional Distance depth = 5;
 }
 
 message BoundingBox {
@@ -119,3 +123,16 @@
   // the point.
   optional float y = 2;
 }
+
+// Generic message object to encapsulate a distance magnitude and units.
+message Distance {
+  enum DistanceUnits {
+    UNITS_UNSPECIFIED = 0;
+    METERS = 1;
+    PIXELS = 2;
+  }
+
+  optional DistanceUnits units = 1;
+
+  optional float magnitude = 2;
+}
diff --git a/components/arc/common/voice_interaction_framework.mojom b/components/arc/common/voice_interaction_framework.mojom
index 88ac74cf..e723c2e6 100644
--- a/components/arc/common/voice_interaction_framework.mojom
+++ b/components/arc/common/voice_interaction_framework.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 4
+// Next MinVersion: 5
 
 module arc.mojom;
 
@@ -41,4 +41,12 @@
 
   // Shows/hides the metalayer in the container.
   [MinVersion=1] SetMetalayerVisibility@3([MinVersion=2] bool visible);
+
+  // Turns on / off voice interaction in container.
+  [MinVersion=4] SetVoiceInteractionEnabled(bool enable);
+
+  // Turns on / off context for voice interaction in container. This function
+  // controls whether screenshot and view hierarchy information should be sent
+  // to container.
+  [MinVersion=4] SetVoiceInteractionContextEnabled(bool enable);
 };
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index b90874ab..0a94920 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -19,8 +19,10 @@
 #include "base/threading/thread.h"
 #include "components/prefs/json_pref_store.h"
 #include "net/nqe/effective_connection_type.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/network_quality_estimator.h"
 #include "net/nqe/network_quality_observation_source.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
 
 class PrefService;
 
@@ -48,8 +50,8 @@
 
 // Adapter between Java CronetUrlRequestContext and net::URLRequestContext.
 class CronetURLRequestContextAdapter
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver,
-      public net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver,
+    : public net::EffectiveConnectionTypeObserver,
+      public net::RTTAndThroughputEstimatesObserver,
       public net::NetworkQualityEstimator::RTTObserver,
       public net::NetworkQualityEstimator::ThroughputObserver {
  public:
diff --git a/components/metrics/net/network_metrics_provider.cc b/components/metrics/net/network_metrics_provider.cc
index cd2f4f5..643b4ae 100644
--- a/components/metrics/net/network_metrics_provider.cc
+++ b/components/metrics/net/network_metrics_provider.cc
@@ -21,6 +21,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "net/base/net_errors.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/network_quality_estimator.h"
 
 #if defined(OS_CHROMEOS)
@@ -45,7 +46,7 @@
 
 // Listens to the changes in the effective conection type.
 class NetworkMetricsProvider::EffectiveConnectionTypeObserver
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver {
+    : public net::EffectiveConnectionTypeObserver {
  public:
   // |network_quality_estimator| is used to provide the network quality
   // estimates. Guaranteed to be non-null. |callback| is run on
diff --git a/components/offline_pages/core/background/network_quality_provider_stub.cc b/components/offline_pages/core/background/network_quality_provider_stub.cc
index 9c5cf28..168d277e 100644
--- a/components/offline_pages/core/background/network_quality_provider_stub.cc
+++ b/components/offline_pages/core/background/network_quality_provider_stub.cc
@@ -30,20 +30,6 @@
   supports_user_data->SetUserData(&kOfflineNQPKey, std::move(stub));
 }
 
-void NetworkQualityProviderStub::AddEffectiveConnectionTypeObserver(
-    net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) {}
-
-void NetworkQualityProviderStub::RemoveEffectiveConnectionTypeObserver(
-    net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer) {}
-
-void NetworkQualityProviderStub::AddRTTAndThroughputEstimatesObserver(
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
-}
-
-void NetworkQualityProviderStub::RemoveRTTAndThroughputEstimatesObserver(
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer) {
-}
-
 net::EffectiveConnectionType
 NetworkQualityProviderStub::GetEffectiveConnectionType() const {
   return connection_type_;
diff --git a/components/offline_pages/core/background/network_quality_provider_stub.h b/components/offline_pages/core/background/network_quality_provider_stub.h
index 54923f023..b6341b9 100644
--- a/components/offline_pages/core/background/network_quality_provider_stub.h
+++ b/components/offline_pages/core/background/network_quality_provider_stub.h
@@ -7,15 +7,14 @@
 
 #include "base/supports_user_data.h"
 #include "net/nqe/effective_connection_type.h"
-#include "net/nqe/network_quality_estimator.h"
+#include "net/nqe/network_quality_provider.h"
 
 namespace offline_pages {
 
 // Test class stubbing out the functionality of NQE::NetworkQualityProvider.
 // It is only used for test support.
-class NetworkQualityProviderStub
-    : public net::NetworkQualityEstimator::NetworkQualityProvider,
-      public base::SupportsUserData::Data {
+class NetworkQualityProviderStub : public net::NetworkQualityProvider,
+                                   public base::SupportsUserData::Data {
  public:
   NetworkQualityProviderStub();
   ~NetworkQualityProviderStub() override;
@@ -27,22 +26,6 @@
 
   net::EffectiveConnectionType GetEffectiveConnectionType() const override;
 
-  void AddEffectiveConnectionTypeObserver(
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-      override;
-
-  void RemoveEffectiveConnectionTypeObserver(
-      net::NetworkQualityEstimator::EffectiveConnectionTypeObserver* observer)
-      override;
-
-  void AddRTTAndThroughputEstimatesObserver(
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-      override;
-
-  void RemoveRTTAndThroughputEstimatesObserver(
-      net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver* observer)
-      override;
-
   void SetEffectiveConnectionTypeForTest(net::EffectiveConnectionType type) {
     connection_type_ = type;
   }
diff --git a/components/omnibox/bug-triage.md b/components/omnibox/bug-triage.md
new file mode 100644
index 0000000..385048e
--- /dev/null
+++ b/components/omnibox/bug-triage.md
@@ -0,0 +1,225 @@
+# Omnibox Bug Triage Process
+
+*last update: 2017/06/05*
+
+*The current triage process owner is `mpearson@`.*
+
+Instructions for Chrome omnibox engineers serving an assigned bug triage
+rotation.
+
+[TOC]
+
+## Goal of the process
+
+Every omnibox bug is triaged, preferably within a week of being filed.  This
+means making the issue clear, marking it as a dup if necessary, revising the
+status, setting a priority, labeling/categorizing as appropriate (or handing off
+to another component), and (possibly) assigning an owner.  The only reason bugs
+should remain untriaged (i.e., *status=Unconfirmed* or *status=Untriaged*) is
+because of they need additional information from someone.  These bugs should be
+labeled as such (*Needs=Feedback* or *Needs=TestConfirmation*).
+
+### Non-goals
+
+* Ensure high priority bugs or regressions are making progress / ping bug owners
+  for progress updates on other important bugs.  (Trust your teammates to work
+  on assigned bugs.)
+* Monitor for changes outside of the bugs database (e.g., UMA regressions, crash
+  database).  (The Speed team monitors UMA for performance regressions and the
+  Stability team monitors the crash database.  Both file bugs as appropriate.)
+
+## Process
+
+* Every other day (weekend excluded), the triage engineer looks over [all
+  *Unconfirmed* and *Untriaged* omnibox bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+  and triages them.
+* Every week on Tuesday, the triage engineer looks over [all *Unconfirmed* and
+  *Untriaged* bugs filed that aren’t categorized as omnibox yet have relevant
+  terms](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=omnibox+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+%E2%80%9Comni+box%E2%80%9D+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+omnibar+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+%E2%80%9Comni+bar%E2%80%9D+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+locationbar+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+%E2%80%9Clocation+bar%E2%80%9D+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+addressbar+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner+OR+%E2%80%9Caddress+bar%E2%80%9D+-component%3AUI%3EBrowser%3EOmnibox+status%3AUnconfirmed%2CUntriaged+-has%3Aowner&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+  to see if any should be moved to the omnibox component and triaged.  (This
+  scan can be limited to those filed in the last week, i.e., since the last
+  check.)
+* Every month (the first Thursday of the month), the triage engineer should
+  look over [all bugs with *Needs=Feedback*](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3AUI%3EBrowser%3EOmnibox+Needs%3DFeedback+&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+  and should take action on those that have been sitting for too long (ping the
+  reporter, close if unactionable, etc.).
+
+Other team members are welcome to triage a bug if they see it before the the
+triage engineer.  The triager owner will cycle among team members by
+arrangement.
+
+## How to triage
+
+### Purpose
+
+The purpose of labels, components, and priority are to make it easy for omnibox
+team members to identify bugs at a glance that affect a particular area.  In
+other words, this bug management process is intended to make the team more
+efficient and provide better visibility for team members to identify what’s
+important to work on in particular areas.
+
+### Identifying the issue
+
+If the bug isn’t clear, or the desired outcome is unclear, please apply the
+label *Needs-Feedback* and courteously ask for clarification.  This is
+appropriate both for external bug filers, Chromium developers on other teams,
+or Googlers.  The label is merely an indication that this bug needs information
+from someone outside the team in order to make progress.  It’s also an
+indication that someone on the team needs to follow-up if feedback is not
+forthcoming.
+
+Often the appropriate request includes a request for chrome://omnibox data;
+[an example such request](#Example-request-for-chrome_omnibox-data) is below.
+
+Also, if the bug is clear, try to reproduce.  If it cannot be reproduced or you
+lack the necessary setup, either ask the reporter for clarification or add the
+label *Needs-TestConfirmation* as appropriate.
+
+Some bugs are feature requests.  Marks these as Feature, not Bug.  It’s likely a
+feature may have been requested before.  Search the bugs database and dup
+appropriately.
+
+Some [commonly requested features and
+commonly reported bugs](#Commonly-referenced-bugs) are listed below.
+
+### Status
+
+Set the Status field to the following value depending on the triage action
+taken:
+
+* *Available*: The typical state for bugs exiting the triage process, assuming
+  none of the other states below apply.
+* *Assigned*: *Available* bugs with Owners; see
+  [section on assigning owners](#Owners).
+* *ExternalDependency*: Bugs that turn out to be in another project's code and
+  you've contacted that other project.  Typically this is problems with
+  Google-sourced suggestions, an IME, or a Chrome extension.  In all cases,
+  file a bug or contact the appropriate team and post information about this
+  outreach (e.g., a bug number) in a comment on the Chromium bug.
+* *Duplicate*: This issue has been reported in another bug or shares the same
+  root cause as another bug and will certainly be fixed simultaneously.
+* *WontFix*: Anything working by design.  Also applies to old non-reproducible
+  bugs or bugs lacking feedback per
+  [standard Chromium policies](http://www.chromium.org/getting-involved/bug-triage#TOC-Cleaning-up-old-bugs).
+* *Unconfirmed* or *Untriaged*:  These labels are generally only appropriate
+  if you labeled the bug with *Needs-Feedback* or *Needs-TestConfirmation*,
+  otherwise in effect you're kicking the can down the road to the next triage
+  engineer.
+
+### Priority
+
+Follow [standard Chromium 
+policies](https://www.chromium.org/for-testers/bug-reporting-guidelines/triage-best-practices).
+*Priority-2* represents wanted for this release but can be punted for a release.
+*Priority-3* are bugs not time sensitive.  There is an even-lower-priority
+state; see the *NextAction=01/09/2018* below.
+
+### Owners
+
+Generally only assign someone else to own a bug if the bug is *Priority-2* or
+better.  *Priority-3* bugs are not likely to be completed soon; for these bugs,
+don’t assign an owner to merely sit on the bug.  To draw someone’s attention to
+a bug, explicitly CC them.
+
+### Categorization
+
+Omnibox bugs use a combination of labels (including hotlists) and subcomponents
+to indicate their topic.
+
+Most omnibox bugs should be in the main omnibox component.  A few will fall
+directly into a subcomponent instead; the available subcomponents are listed
+below.
+
+Add all the labels, components, and next actions dates that seem appropriate to
+the issue.  The main ones encountered by omnibox issues are listed below; feel
+free to use additional suitable ones as well.
+
+The main labels that apply to bugs include:
+
+| Label | Description |
+| --- | --- |
+| Performance-Browser | Bugs that affect performance. |
+| Hotlist-CodeHealth | Bugs about the making the code base easy to work with such as quality of comments.  Refactoring efforts can also be included when for that purpose. |
+| Hotlist-Polish | Bugs about how a feature looks and feels: not whether the feature works or not; instead, more of whether it appears the feature was created with attention to detail.  Often user-visible edge cases fit in this category. |
+| Hotlist-Refactoring | Bugs related to restructuring existing code without changing its behavior. |
+
+The components that additionally apply to bugs include:
+
+| Component | Description |
+| --- | --- |
+| Enterprise | Bugs that mainly affect enterprise environments: enterprise policies, intranet handling, etc. |
+| Tests>{Disabled,Failed,Missing,Flaky} | Bugs related to failing tests or lack of test coverage. |
+| UI>Browser>Search | Bugs related to web search in general whose effects aren’t limited to the omnibox. |
+
+The subcomponents of omnibox bugs include:
+
+| Subcomponent | Description |
+| --- | --- |
+| UI>Browser>Omnibox>AiS | Answers in Suggest. |
+| UI>Browser>Omnibox>SecurityIndicators | Secure/insecure icons; triaged by another team. |
+| UI>Browser>Omnibox>TabToSearch | Custom search engines, omnibox extensions, etc. (including adding, triggering, ranking, etc. for them). |
+| UI>Browser>Omnibox>ZeroSuggest | Suggestions displayed on omnibox focus (both contextual and non-contextual). |
+
+If the bug is extremely low priority, set the **NextAction field** to
+**01/09/2018** and mention that we will "reassess" the bug next year.  This
+NextAction field is for Priority-3 bugs that are somehow less important than
+other *priority-3* bugs.  These are bugs we’re sure no one on the team intends
+to fix this year (e.g., really unimportant, or mostly unimportant and hard to
+fix).  This label should be applied only when confident the whole team will
+agree with you.  When searching the bugs database for things to do, I suggest
+excluding bugs on this hotlist.)
+
+# Appendix
+
+## Example request for chrome://omnibox data
+
+> Please submit chrome://omnibox output for “\_\_\_”.  Check both the "show
+> all details" and "show results per provider" boxes.  This will help us
+> figure out what's going on.
+>
+> Feel free to paste the results in here unformatted; we’ll be able to
+> decipher them.
+
+## Commonly referenced bugs
+
+* “I want the option to turn off inline autocomplete.” Dup against
+  [crbug/91378](https://bugs.chromium.org/p/chromium/issues/detail?id=91378).
+
+  * Try to understand the motivation of the user making the request.  Please
+  ask the user for examples, with chrome://omnibox detail, of times where the
+  omnibox doesn’t do what they want.  Ideally we should be able make to make the
+  omnibox smart enough that such a feature isn’t necessary.
+
+* “I typed in something like go/foo and got redirected to a search results page
+  instead.” See
+  [this internal page](https://docs.google.com/document/d/140jmrHfC9BiNUbHEmUF4ajJ8Zpbc7qd5fjTBulH3I5g/edit#).
+  Follow the guidelines there; generally ask about a message about profile
+  corruption.  If so, the bug can be dupped against
+  [crbug/665253](https://bugs.chromium.org/p/chromium/issues/detail?id=665253)
+
+  * … and no “Did you mean?” infobar appears.  This is likely prerendering; see
+  [crbug/247848](https://bugs.chromium.org/p/chromium/issues/detail?id=247848)
+
+* “I want to disable suggestions from appearing entirely”.  Try to find out
+  why.  Quote freely from
+  [pkasting’s comment on this bug](https://bugs.chromium.org/p/chromium/issues/detail?id=702850#c16).
+
+# References
+
+[General Chromium bug triage guidelines](http://www.chromium.org/getting-involved/bug-triage)
+
+[Omnibox bugs that we intend/hope to tackle this year](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+NextAction%3C2018%2F1%2F1+OR+component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+-has%3ANextAction+&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids),
+broken down:
+
+* [User-facing](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+-Hotlist%3DCodeHealth+-Hotlist%3DRefactoring+-component%3ATest+NextAction%3C2018%2F1%2F1+OR+component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+-Hotlist%3DCodeHealth+-Hotlist%3DRefactoring+-component%3ATest+-has%3ANextAction&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+  (everything not tagged as one of the non-user-facing categories below).  Some
+  of these can be further categorized: Performance, Polish, Enterprise, Answers
+  in Suggest, Tab To Search, Zero Suggest.
+
+* Non user-facing, divided into these categories:
+
+  * [Code health](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+NextAction%3C2018%2F1%2F1+OR+component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+-has%3ANextAction+&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+  * [Refactoring](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+Hotlist%3DRefactoring+NextAction%3C2018%2F1%2F1+OR+component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+Hotlist%3DRefactoring+-has%3ANextAction&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+  * [Testing](https://bugs.chromium.org/p/chromium/issues/list?can=1&q=component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+component%3ATests+NextAction%3C2018%2F1%2F1+OR+component%3AUI%3EBrowser%3EOmnibox+-component%3AUI%3EBrowser%3EOmnibox%3ESecurityIndicators+status%3AAvailable%2CAssigned%2CStarted+component%3ATests+-has%3ANextAction&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
index 877a4d3..76f9f05 100644
--- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
+++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
@@ -4,13 +4,19 @@
 
 #include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
 
+#include <sstream>
+
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
 #include "components/subresource_filter/core/common/time_measurements.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/common/console_message_level.h"
 
 namespace subresource_filter {
 
@@ -86,6 +92,16 @@
   total_defer_time_ += base::TimeTicks::Now() - last_defer_timestamp_;
 
   if (policy == LoadPolicy::DISALLOW) {
+    if (parent_frame_filter_->activation_state().enable_logging) {
+      std::ostringstream oss(kDisallowSubframeConsoleMessage);
+      oss << navigation_handle()->GetURL() << ".";
+      navigation_handle()
+          ->GetWebContents()
+          ->GetMainFrame()
+          ->AddMessageToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR,
+                                oss.str());
+    }
+
     parent_frame_filter_->ReportDisallowedLoad();
     // Other load policies will be reported in WillProcessResponse.
     NotifyLoadPolicy();
diff --git a/components/subresource_filter/core/browser/subresource_filter_constants.cc b/components/subresource_filter/core/browser/subresource_filter_constants.cc
index a1bee67c..fc3aaba 100644
--- a/components/subresource_filter/core/browser/subresource_filter_constants.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_constants.cc
@@ -30,8 +30,11 @@
 const base::FilePath::CharType kUnindexedRulesetDataFileName[] =
     FILE_PATH_LITERAL("Filtering Rules");
 
-// TODO(shivanisha): Update the string when finalized.
+// TODO(shivanisha): Update the strings when finalized.
+
 const std::string kActivationConsoleMessage =
     "Subresource filter is activated on this site";
 
+const std::string kDisallowSubframeConsoleMessage =
+    "Subresource filtering disallowed loading this resource, ";
 }  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_constants.h b/components/subresource_filter/core/browser/subresource_filter_constants.h
index ce2ba43..9e34958 100644
--- a/components/subresource_filter/core/browser/subresource_filter_constants.h
+++ b/components/subresource_filter/core/browser/subresource_filter_constants.h
@@ -50,6 +50,9 @@
 // Console message to be displayed on activation.
 extern const std::string kActivationConsoleMessage;
 
+// Console message to be displayed on disallowing subframe.
+extern const std::string kDisallowSubframeConsoleMessage;
+
 }  // namespace subresource_filter
 
 #endif  // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
diff --git a/components/variations/pref_names.cc b/components/variations/pref_names.cc
index 8bd52ce..52d187f 100644
--- a/components/variations/pref_names.cc
+++ b/components/variations/pref_names.cc
@@ -32,9 +32,6 @@
 // String for the restrict parameter to be appended to the variations URL.
 const char kVariationsRestrictParameter[] = "variations_restrict_parameter";
 
-// Base64-encoded serialized form of the variations seed protobuf.
-const char kVariationsSeed[] = "variations_seed";
-
 // 64-bit integer serialization of the base::Time from the last seed received.
 const char kVariationsSeedDate[] = "variations_seed_date";
 
diff --git a/components/variations/pref_names.h b/components/variations/pref_names.h
index 17cbd88..900a208 100644
--- a/components/variations/pref_names.h
+++ b/components/variations/pref_names.h
@@ -17,7 +17,6 @@
 extern const char kVariationsPermutedEntropyCache[];
 extern const char kVariationsCountry[];
 extern const char kVariationsRestrictParameter[];
-extern const char kVariationsSeed[];
 extern const char kVariationsSeedDate[];
 extern const char kVariationsSeedSignature[];
 
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc
index 880e6c4..a0515f08 100644
--- a/components/variations/service/variations_service_unittest.cc
+++ b/components/variations/service/variations_service_unittest.cc
@@ -479,13 +479,15 @@
   for (size_t i = 0; i < arraysize(non_ok_status_codes); ++i) {
     net::TestURLFetcherFactory factory;
     service.DoActualFetch();
-    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
+    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsCompressedSeed)
+                    ->IsDefaultValue());
 
     net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
     SimulateServerResponse(non_ok_status_codes[i], fetcher);
     service.OnURLFetchComplete(fetcher);
 
-    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsSeed)->IsDefaultValue());
+    EXPECT_TRUE(prefs.FindPreference(prefs::kVariationsCompressedSeed)
+                    ->IsDefaultValue());
   }
 }
 
diff --git a/components/variations/variations_seed_store.cc b/components/variations/variations_seed_store.cc
index aa795192..935ab6e 100644
--- a/components/variations/variations_seed_store.cc
+++ b/components/variations/variations_seed_store.cc
@@ -298,7 +298,6 @@
 // static
 void VariationsSeedStore::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterStringPref(prefs::kVariationsCompressedSeed, std::string());
-  registry->RegisterStringPref(prefs::kVariationsSeed, std::string());
   registry->RegisterInt64Pref(prefs::kVariationsSeedDate,
                               base::Time().ToInternalValue());
   registry->RegisterStringPref(prefs::kVariationsSeedSignature, std::string());
@@ -336,7 +335,6 @@
 
 void VariationsSeedStore::ClearPrefs() {
   local_state_->ClearPref(prefs::kVariationsCompressedSeed);
-  local_state_->ClearPref(prefs::kVariationsSeed);
   local_state_->ClearPref(prefs::kVariationsSeedDate);
   local_state_->ClearPref(prefs::kVariationsSeedSignature);
 }
@@ -378,11 +376,6 @@
 bool VariationsSeedStore::ReadSeedData(std::string* seed_data) {
   std::string base64_seed_data =
       local_state_->GetString(prefs::kVariationsCompressedSeed);
-  const bool is_compressed = !base64_seed_data.empty();
-  // If there's no compressed seed, fall back to the uncompressed one.
-  if (!is_compressed)
-    base64_seed_data = local_state_->GetString(prefs::kVariationsSeed);
-
   if (base64_seed_data.empty()) {
     RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_EMPTY);
     return false;
@@ -396,9 +389,7 @@
     return false;
   }
 
-  if (!is_compressed) {
-    seed_data->swap(decoded_data);
-  } else if (!compression::GzipUncompress(decoded_data, seed_data)) {
+  if (!compression::GzipUncompress(decoded_data, seed_data)) {
     ClearPrefs();
     RecordVariationSeedEmptyHistogram(VARIATIONS_SEED_CORRUPT_GZIP);
     return false;
@@ -446,10 +437,6 @@
   std::string base64_seed_data;
   base::Base64Encode(compressed_seed_data, &base64_seed_data);
 
-  // TODO(asvitkine): This pref is no longer being used. Remove it completely
-  // in M45+.
-  local_state_->ClearPref(prefs::kVariationsSeed);
-
 #if defined(OS_ANDROID)
   // If currently we do not have any stored pref then we mark seed storing as
   // successful on the Java side of Chrome for Android to avoid repeated seed
diff --git a/components/variations/variations_seed_store_unittest.cc b/components/variations/variations_seed_store_unittest.cc
index 6e5dca5..767afa2 100644
--- a/components/variations/variations_seed_store_unittest.cc
+++ b/components/variations/variations_seed_store_unittest.cc
@@ -127,16 +127,12 @@
 }
 
 TEST(VariationsSeedStoreTest, GetInvalidSignature) {
-  const variations::VariationsSeed seed = CreateTestSeed();
-  const std::string base64_seed = SerializeSeedBase64(seed);
-
   TestingPrefServiceSimple prefs;
   VariationsSeedStore::RegisterPrefs(prefs.registry());
-  prefs.SetString(prefs::kVariationsSeed, base64_seed);
 
   // The below seed and signature pair were generated using the server's
   // private key.
-  const std::string base64_seed_data =
+  const std::string uncompressed_base64_seed_data =
       "CigxZDI5NDY0ZmIzZDc4ZmYxNTU2ZTViNTUxYzY0NDdjYmM3NGU1ZmQwEr0BCh9VTUEtVW5p"
       "Zm9ybWl0eS1UcmlhbC0xMC1QZXJjZW50GICckqUFOAFCB2RlZmF1bHRKCwoHZGVmYXVsdBAB"
       "SgwKCGdyb3VwXzAxEAFKDAoIZ3JvdXBfMDIQAUoMCghncm91cF8wMxABSgwKCGdyb3VwXzA0"
@@ -149,8 +145,16 @@
       "AEQCIDD1IVxjzWYncun+9IGzqYjZvqxxujQEayJULTlbTGA/AiAr0oVmEgVUQZBYq5VLOSvy"
       "96JkMYgzTkHPwbv7K/CmgA==";
 
+  std::string uncompressed_seed_data;
+  ASSERT_TRUE(base::Base64Decode(uncompressed_base64_seed_data,
+                                 &uncompressed_seed_data));
+  std::string compressed_base64_seed_data;
+  base::Base64Encode(Compress(uncompressed_seed_data),
+                     &compressed_base64_seed_data);
+
   // Set seed and valid signature in prefs.
-  prefs.SetString(prefs::kVariationsSeed, base64_seed_data);
+  prefs.SetString(prefs::kVariationsCompressedSeed,
+                  compressed_base64_seed_data);
   prefs.SetString(prefs::kVariationsSeedSignature, base64_seed_signature);
 
   VariationsSeedStore seed_store(&prefs);
diff --git a/components/viz/display_compositor/gpu_display_provider.cc b/components/viz/display_compositor/gpu_display_provider.cc
index f89ff10..483eaaa8 100644
--- a/components/viz/display_compositor/gpu_display_provider.cc
+++ b/components/viz/display_compositor/gpu_display_provider.cc
@@ -74,8 +74,9 @@
       display_output_surface->capabilities().max_frames_pending;
   DCHECK_GT(max_frames_pending, 0);
 
-  auto scheduler = base::MakeUnique<cc::DisplayScheduler>(task_runner_.get(),
-                                                          max_frames_pending);
+  auto scheduler = base::MakeUnique<cc::DisplayScheduler>(
+      synthetic_begin_frame_source.get(), task_runner_.get(),
+      max_frames_pending);
 
   cc::RendererSettings settings;
   settings.show_overdraw_feedback =
@@ -87,8 +88,8 @@
 
   return base::MakeUnique<cc::Display>(
       HostSharedBitmapManager::current(), gpu_memory_buffer_manager_.get(),
-      settings, frame_sink_id, begin_frame_source->get(),
-      std::move(display_output_surface), std::move(scheduler),
+      settings, frame_sink_id, std::move(display_output_surface),
+      std::move(scheduler),
       base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get()));
 }
 
diff --git a/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc b/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc
index 0fd4bfa5..2804a0f 100644
--- a/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc
+++ b/components/viz/frame_sinks/gpu_root_compositor_frame_sink.cc
@@ -36,16 +36,22 @@
           this,
           std::move(compositor_frame_sink_private_request)),
       display_private_binding_(this, std::move(display_private_request)) {
+  DCHECK(display_begin_frame_source_);
   compositor_frame_sink_binding_.set_connection_error_handler(
       base::Bind(&GpuRootCompositorFrameSink::OnClientConnectionLost,
                  base::Unretained(this)));
   compositor_frame_sink_private_binding_.set_connection_error_handler(
       base::Bind(&GpuRootCompositorFrameSink::OnPrivateConnectionLost,
                  base::Unretained(this)));
+  surface_manager->RegisterBeginFrameSource(display_begin_frame_source_.get(),
+                                            frame_sink_id);
   display_->Initialize(this, surface_manager);
 }
 
-GpuRootCompositorFrameSink::~GpuRootCompositorFrameSink() = default;
+GpuRootCompositorFrameSink::~GpuRootCompositorFrameSink() {
+  support_->surface_manager()->UnregisterBeginFrameSource(
+      display_begin_frame_source_.get());
+}
 
 void GpuRootCompositorFrameSink::SetDisplayVisible(bool visible) {
   DCHECK(display_);
diff --git a/content/browser/background_fetch/background_fetch_service_unittest.cc b/content/browser/background_fetch/background_fetch_service_unittest.cc
index cbdc87ed..46b495da 100644
--- a/content/browser/background_fetch/background_fetch_service_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_service_unittest.cc
@@ -539,6 +539,9 @@
   // Immediately abort the registration. This also is expected to succeed.
   ASSERT_NO_FATAL_FAILURE(Abort(registration_id, &abort_error));
   ASSERT_EQ(abort_error, blink::mojom::BackgroundFetchError::NONE);
+  // Wait for the response of the Mojo IPC to dispatch
+  // BackgroundFetchAbortEvent.
+  base::RunLoop().RunUntilIdle();
 
   blink::mojom::BackgroundFetchError second_error;
   BackgroundFetchRegistration second_registration;
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index a7db3b40..2dd0458 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -479,8 +479,8 @@
 
     // New embedded service factories should be added to |connection| here.
 
-    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-            switches::kMojoLocalStorage)) {
+    if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kDisableMojoLocalStorage)) {
       ServiceInfo info;
       // TODO(mek): Use sequenced task runner rather than single thread task
       // runner when mojo supports that (http://crbug.com/678155).
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 77b62d4a..aa8fa9b 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1213,6 +1213,11 @@
     midi_service_->Shutdown();
   }
 
+  TRACE_EVENT0("shutdown",
+               "BrowserMainLoop::Subsystem:SpeechRecognitionManager");
+  io_thread_->task_runner()->DeleteSoon(FROM_HERE,
+                                        speech_recognition_manager_.release());
+
   memory_pressure_monitor_.reset();
 
 #if defined(OS_MACOSX)
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index 926fbb6..be9196b5 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -295,6 +295,9 @@
 
   std::unique_ptr<midi::MidiService> midi_service_;
 
+  // Must be deleted on the IO thread.
+  std::unique_ptr<SpeechRecognitionManagerImpl> speech_recognition_manager_;
+
 #if defined(OS_WIN)
   std::unique_ptr<media::SystemMessageWindowWin> system_message_window_;
 #elif defined(OS_LINUX) && defined(USE_UDEV)
@@ -309,7 +312,6 @@
   std::unique_ptr<LoaderDelegateImpl> loader_delegate_;
   std::unique_ptr<ResourceDispatcherHostImpl> resource_dispatcher_host_;
   std::unique_ptr<MediaStreamManager> media_stream_manager_;
-  std::unique_ptr<SpeechRecognitionManagerImpl> speech_recognition_manager_;
   std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager>
       discardable_shared_memory_manager_;
   scoped_refptr<SaveFileManager> save_file_manager_;
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 417dc0f..2f56033 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -591,18 +591,27 @@
   gfx::RenderingWindowManager::GetInstance()->DoSetParentOnChild(
       compositor->widget());
 #endif
+  if (data->synthetic_begin_frame_source) {
+    GetSurfaceManager()->UnregisterBeginFrameSource(
+        data->synthetic_begin_frame_source.get());
+  } else if (data->gpu_vsync_begin_frame_source) {
+    GetSurfaceManager()->UnregisterBeginFrameSource(
+        data->gpu_vsync_begin_frame_source.get());
+  }
 
   std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
-      compositor->task_runner().get(),
+      begin_frame_source, compositor->task_runner().get(),
       display_output_surface->capabilities().max_frames_pending));
 
   // The Display owns and uses the |display_output_surface| created above.
   data->display = base::MakeUnique<cc::Display>(
       viz::HostSharedBitmapManager::current(), GetGpuMemoryBufferManager(),
-      renderer_settings_, compositor->frame_sink_id(), begin_frame_source,
+      renderer_settings_, compositor->frame_sink_id(),
       std::move(display_output_surface), std::move(scheduler),
       base::MakeUnique<cc::TextureMailboxDeleter>(
           compositor->task_runner().get()));
+  GetSurfaceManager()->RegisterBeginFrameSource(begin_frame_source,
+                                                compositor->frame_sink_id());
   // Note that we are careful not to destroy prior BeginFrameSource objects
   // until we have reset |data->display|.
   data->synthetic_begin_frame_source = std::move(synthetic_begin_frame_source);
@@ -662,7 +671,13 @@
   if (data->surface_handle)
     gpu::GpuSurfaceTracker::Get()->RemoveSurface(data->surface_handle);
 #endif
-
+  if (data->synthetic_begin_frame_source) {
+    GetSurfaceManager()->UnregisterBeginFrameSource(
+        data->synthetic_begin_frame_source.get());
+  } else if (data->gpu_vsync_begin_frame_source) {
+    GetSurfaceManager()->UnregisterBeginFrameSource(
+        data->gpu_vsync_begin_frame_source.get());
+  }
   per_compositor_data_.erase(it);
   if (per_compositor_data_.empty()) {
     // Destroying the GLHelper may cause some async actions to be cancelled,
diff --git a/content/browser/dom_storage/dom_storage_browsertest.cc b/content/browser/dom_storage/dom_storage_browsertest.cc
index 238a69d..c9efa24 100644
--- a/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -25,6 +25,11 @@
  public:
   DOMStorageBrowserTest() {}
 
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ContentBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitch(switches::kDisableMojoLocalStorage);
+  }
+
   void SimpleTest(const GURL& test_url, bool incognito) {
     // The test page will perform tests then navigate to either
     // a #pass or #fail ref.
@@ -46,7 +51,6 @@
  public:
   void SetUpCommandLine(base::CommandLine* command_line) override {
     ContentBrowserTest::SetUpCommandLine(command_line);
-    command_line->AppendSwitch(switches::kMojoLocalStorage);
   }
 
   LocalStorageContextMojo* context() {
@@ -120,8 +124,8 @@
     // Only enable mojo local storage if this is not a PRE_ test.
     const testing::TestInfo* test =
         testing::UnitTest::GetInstance()->current_test_info();
-    if (!base::StartsWith(test->name(), "PRE_", base::CompareCase::SENSITIVE))
-      command_line->AppendSwitch(switches::kMojoLocalStorage);
+    if (base::StartsWith(test->name(), "PRE_", base::CompareCase::SENSITIVE))
+      command_line->AppendSwitch(switches::kDisableMojoLocalStorage);
   }
 };
 
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index 1a18095..8c8a9dec 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/barrier_closure.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
@@ -39,22 +40,36 @@
 const char kSessionStorageDirectory[] = "Session Storage";
 
 void InvokeLocalStorageUsageCallbackHelper(
-      const DOMStorageContext::GetLocalStorageUsageCallback& callback,
-      const std::vector<LocalStorageUsageInfo>* infos) {
+    const DOMStorageContext::GetLocalStorageUsageCallback& callback,
+    std::unique_ptr<std::vector<LocalStorageUsageInfo>> infos) {
   callback.Run(*infos);
 }
 
 void GetLocalStorageUsageHelper(
-    std::vector<LocalStorageUsageInfo> mojo_usage,
     base::SingleThreadTaskRunner* reply_task_runner,
     DOMStorageContextImpl* context,
     const DOMStorageContext::GetLocalStorageUsageCallback& callback) {
-  std::vector<LocalStorageUsageInfo>* infos =
-      new std::vector<LocalStorageUsageInfo>(std::move(mojo_usage));
-  context->GetLocalStorageUsage(infos, true);
+  auto infos = base::MakeUnique<std::vector<LocalStorageUsageInfo>>();
+  context->GetLocalStorageUsage(infos.get(), true);
   reply_task_runner->PostTask(
-      FROM_HERE, base::Bind(&InvokeLocalStorageUsageCallbackHelper, callback,
-                            base::Owned(infos)));
+      FROM_HERE, base::BindOnce(&InvokeLocalStorageUsageCallbackHelper,
+                                callback, std::move(infos)));
+}
+
+void CollectLocalStorageUsage(
+    std::vector<LocalStorageUsageInfo>* out_info,
+    base::Closure done_callback,
+    const std::vector<LocalStorageUsageInfo>& in_info) {
+  out_info->insert(out_info->end(), in_info.begin(), in_info.end());
+  done_callback.Run();
+}
+
+void GotMojoLocalStorageUsage(
+    scoped_refptr<base::SingleThreadTaskRunner> reply_task_runner,
+    const DOMStorageContext::GetLocalStorageUsageCallback& callback,
+    std::vector<LocalStorageUsageInfo> usage) {
+  reply_task_runner->PostTask(FROM_HERE,
+                              base::BindOnce(callback, std::move(usage)));
 }
 
 void InvokeSessionStorageUsageCallbackHelper(
@@ -104,8 +119,8 @@
       new DOMStorageWorkerPoolTaskRunner(std::move(primary_sequence),
                                          std::move(commit_sequence)));
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kMojoLocalStorage)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableMojoLocalStorage)) {
     base::FilePath storage_dir;
     if (!profile_path.empty())
       storage_dir = local_partition_path.AppendASCII(kLocalStorageDirectory);
@@ -136,6 +151,12 @@
     const GetLocalStorageUsageCallback& callback) {
   DCHECK(context_.get());
   if (mojo_state_) {
+    auto infos = base::MakeUnique<std::vector<LocalStorageUsageInfo>>();
+    auto* infos_ptr = infos.get();
+    base::RepeatingClosure got_local_storage_usage = base::BarrierClosure(
+        2, base::BindOnce(&InvokeLocalStorageUsageCallbackHelper, callback,
+                          std::move(infos)));
+
     // base::Unretained is safe here, because the mojo_state_ won't be deleted
     // until a ShutdownAndDelete task has been ran on the mojo_task_runner_, and
     // as soon as that task is posted, mojo_state_ is set to null, preventing
@@ -145,16 +166,22 @@
         base::BindOnce(
             &LocalStorageContextMojo::GetStorageUsage,
             base::Unretained(mojo_state_),
-            base::BindOnce(
-                &DOMStorageContextWrapper::GotMojoLocalStorageUsage, this,
-                callback,
-                base::RetainedRef(base::ThreadTaskRunnerHandle::Get()))));
+            base::BindOnce(&GotMojoLocalStorageUsage,
+                           base::ThreadTaskRunnerHandle::Get(),
+                           base::Bind(CollectLocalStorageUsage, infos_ptr,
+                                      got_local_storage_usage))));
+    context_->task_runner()->PostShutdownBlockingTask(
+        FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+        base::Bind(&GetLocalStorageUsageHelper,
+                   base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
+                   base::RetainedRef(context_),
+                   base::Bind(&CollectLocalStorageUsage, infos_ptr,
+                              got_local_storage_usage)));
     return;
   }
   context_->task_runner()->PostShutdownBlockingTask(
       FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
       base::Bind(&GetLocalStorageUsageHelper,
-                 std::vector<LocalStorageUsageInfo>(),
                  base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
                  base::RetainedRef(context_), callback));
 }
@@ -271,7 +298,6 @@
   if (base::FeatureList::IsEnabled(features::kMemoryCoordinator)) {
     base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
   }
-
 }
 
 void DOMStorageContextWrapper::Flush() {
@@ -306,6 +332,20 @@
                                 std::move(request)));
 }
 
+void DOMStorageContextWrapper::SetLocalStorageDatabaseForTesting(
+    leveldb::mojom::LevelDBDatabaseAssociatedPtr database) {
+  if (!mojo_state_)
+    return;
+  // base::Unretained is safe here, because the mojo_state_ won't be deleted
+  // until a ShutdownAndDelete task has been ran on the mojo_task_runner_, and
+  // as soon as that task is posted, mojo_state_ is set to null, preventing
+  // further tasks from being queued.
+  mojo_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&LocalStorageContextMojo::SetDatabaseForTesting,
+                     base::Unretained(mojo_state_), std::move(database)));
+}
+
 void DOMStorageContextWrapper::OnMemoryPressure(
     base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
   DOMStorageContextImpl::PurgeOption purge_option =
@@ -337,15 +377,4 @@
   }
 }
 
-void DOMStorageContextWrapper::GotMojoLocalStorageUsage(
-    GetLocalStorageUsageCallback callback,
-    base::SingleThreadTaskRunner* reply_task_runner,
-    std::vector<LocalStorageUsageInfo> usage) {
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE, DOMStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&GetLocalStorageUsageHelper, base::Passed(&usage),
-                 base::RetainedRef(reply_task_runner),
-                 base::RetainedRef(context_), callback));
-}
-
 }  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index c8945c2..bab7dbe0 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -77,6 +77,9 @@
   void OpenLocalStorage(const url::Origin& origin,
                         mojom::LevelDBWrapperRequest request);
 
+  void SetLocalStorageDatabaseForTesting(
+      leveldb::mojom::LevelDBDatabaseAssociatedPtr database);
+
  private:
   friend class DOMStorageMessageFilter;  // for access to context()
   friend class SessionStorageNamespaceImpl;  // ditto
@@ -95,10 +98,6 @@
 
   void PurgeMemory(DOMStorageContextImpl::PurgeOption purge_option);
 
-  void GotMojoLocalStorageUsage(GetLocalStorageUsageCallback callback,
-                                base::SingleThreadTaskRunner* reply_task_runner,
-                                std::vector<LocalStorageUsageInfo> usage);
-
   // Keep all mojo-ish details together and not bleed them through the public
   // interface. The |mojo_state_| object is owned by this object, but destroyed
   // asynchronously on the |mojo_task_runner_|.
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc
index 2be6213f..3d9c807 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -341,14 +341,12 @@
     it.second->level_db_wrapper()->PurgeMemory();
 }
 
-leveldb::mojom::LevelDBDatabaseAssociatedRequest
-LocalStorageContextMojo::DatabaseRequestForTesting() {
+void LocalStorageContextMojo::SetDatabaseForTesting(
+    leveldb::mojom::LevelDBDatabaseAssociatedPtr database) {
   DCHECK_EQ(connection_state_, NO_CONNECTION);
   connection_state_ = CONNECTION_IN_PROGRESS;
-  leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
-      MakeIsolatedRequest(&database_);
+  database_ = std::move(database);
   OnDatabaseOpened(true, leveldb::mojom::DatabaseError::OK);
-  return request;
 }
 
 // static
@@ -388,7 +386,14 @@
 
 void LocalStorageContextMojo::InitiateConnection(bool in_memory_only) {
   DCHECK_EQ(connection_state_, CONNECTION_IN_PROGRESS);
-  CHECK(connector_);
+
+  // Unit tests might not always have a Connector, use in-memory only if that
+  // happens.
+  if (!connector_) {
+    OnDatabaseOpened(false, leveldb::mojom::DatabaseError::OK);
+    return;
+  }
+
   if (!subdirectory_.empty() && !in_memory_only) {
     // We were given a subdirectory to write to. Get it and use a disk backed
     // database.
@@ -607,6 +612,13 @@
 
 void LocalStorageContextMojo::RetrieveStorageUsage(
     GetStorageUsageCallback callback) {
+  if (!database_) {
+    // If for whatever reason no leveldb database is available, no storage is
+    // used, so return an empty array.
+    std::move(callback).Run(std::vector<LocalStorageUsageInfo>());
+    return;
+  }
+
   database_->GetPrefixed(
       std::vector<uint8_t>(kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix)),
       base::Bind(&LocalStorageContextMojo::OnGotMetaData,
diff --git a/content/browser/dom_storage/local_storage_context_mojo.h b/content/browser/dom_storage/local_storage_context_mojo.h
index 342fe0a..019e605 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.h
+++ b/content/browser/dom_storage/local_storage_context_mojo.h
@@ -28,8 +28,8 @@
 class LevelDBWrapperImpl;
 struct LocalStorageUsageInfo;
 
-// Used for mojo-based LocalStorage implementation (behind --mojo-local-storage
-// for now).
+// Used for mojo-based LocalStorage implementation (can be disabled with
+// --disable-mojo-local-storage for now).
 // Created on the UI thread, but all further methods are called on the IO
 // thread. Furthermore since destruction of this class can involve asynchronous
 // steps, it can only be deleted by calling ShutdownAndDelete (on the IO
@@ -70,7 +70,8 @@
   // storage for a particular origin will reload the data from the database.
   void PurgeMemory();
 
-  leveldb::mojom::LevelDBDatabaseAssociatedRequest DatabaseRequestForTesting();
+  void SetDatabaseForTesting(
+      leveldb::mojom::LevelDBDatabaseAssociatedPtr database);
 
   // Converts a string from the old storage format to the new storage format.
   static std::vector<uint8_t> MigrateString(const base::string16& input);
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 1711de3..e3f7c76 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -138,7 +138,11 @@
           nullptr, task_runner_, temp_path_.GetPath(),
           base::FilePath(FILE_PATH_LITERAL("leveldb")),
           special_storage_policy());
-      db_binding_.Bind(context_->DatabaseRequestForTesting());
+      leveldb::mojom::LevelDBDatabaseAssociatedPtr database_ptr;
+      leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
+          MakeIsolatedRequest(&database_ptr);
+      context_->SetDatabaseForTesting(std::move(database_ptr));
+      db_binding_.Bind(std::move(request));
     }
     return context_;
   }
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 0026338..39fe5c8 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -1571,16 +1571,6 @@
   DCHECK(!GetTargetFilePath().empty());
   DCHECK(!IsDangerous());
 
-  // TODO(rdsmith/benjhayden): Remove as part of SavePackage integration.
-  if (is_save_package_download_) {
-    // Avoid doing anything on the file thread; there's nothing we control
-    // there.  Strictly speaking, this skips giving the embedder a chance to
-    // open the download.  But on a save package download, there's no real
-    // concept of opening.
-    Completed();
-    return;
-  }
-
   DCHECK(download_file_.get());
   // Unilaterally rename; even if it already has the right name,
   // we need theannotation.
diff --git a/content/browser/loader/resource_scheduler.cc b/content/browser/loader/resource_scheduler.cc
index 2e1c500c..f2b329f 100644
--- a/content/browser/loader/resource_scheduler.cc
+++ b/content/browser/loader/resource_scheduler.cc
@@ -227,6 +227,7 @@
         scheduler_(scheduler),
         priority_(priority),
         fifo_ordering_(0),
+        peak_delayable_requests_in_flight_(0u),
         host_port_pair_(net::HostPortPair::FromURL(request->url())),
         weak_ptr_factory_(this) {
     DCHECK(!request_->GetUserData(kUserDataKey));
@@ -234,6 +235,16 @@
   }
 
   ~ScheduledResourceRequest() override {
+    if ((attributes_ & kAttributeLayoutBlocking) == kAttributeLayoutBlocking) {
+      UMA_HISTOGRAM_COUNTS_100(
+          "ResourceScheduler.PeakDelayableRequestsInFlight.LayoutBlocking",
+          peak_delayable_requests_in_flight_);
+    }
+    if (!((attributes_ & kAttributeDelayable) == kAttributeDelayable)) {
+      UMA_HISTOGRAM_COUNTS_100(
+          "ResourceScheduler.PeakDelayableRequestsInFlight.NonDelayable",
+          peak_delayable_requests_in_flight_);
+    }
     request_->RemoveUserData(kUserDataKey);
     scheduler_->RemoveRequest(this);
   }
@@ -274,6 +285,11 @@
     ready_ = true;
   }
 
+  void UpdateDelayableRequestsInFlight(size_t delayable_requests_in_flight) {
+    peak_delayable_requests_in_flight_ = std::max(
+        peak_delayable_requests_in_flight_, delayable_requests_in_flight);
+  }
+
   void set_request_priority_params(const RequestPriorityParams& priority) {
     priority_ = priority;
   }
@@ -328,6 +344,9 @@
   ResourceScheduler* scheduler_;
   RequestPriorityParams priority_;
   uint32_t fifo_ordering_;
+
+  // Maximum number of delayable requests in-flight when |this| was in-flight.
+  size_t peak_delayable_requests_in_flight_;
   // Cached to excessive recomputation in ShouldKeepSearching.
   const net::HostPortPair host_port_pair_;
 
@@ -494,9 +513,40 @@
     YIELD_SCHEDULER
   };
 
+  // Records the metrics related to number of requests in flight.
+  void RecordRequestCountMetrics() const {
+    UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.All",
+                             in_flight_requests_.size());
+    UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.Delayable",
+                             in_flight_delayable_count_);
+    UMA_HISTOGRAM_COUNTS_100(
+        "ResourceScheduler.RequestsCount.NonDelayable",
+        in_flight_requests_.size() - in_flight_delayable_count_);
+    UMA_HISTOGRAM_COUNTS_100(
+        "ResourceScheduler.RequestsCount.TotalLayoutBlocking",
+        total_layout_blocking_count_);
+  }
+
   void InsertInFlightRequest(ScheduledResourceRequest* request) {
     in_flight_requests_.insert(request);
     SetRequestAttributes(request, DetermineRequestAttributes(request));
+    RecordRequestCountMetrics();
+
+    if (RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
+      // Notify all in-flight with the new count of in-flight delayable
+      // requests.
+      for (RequestSet::const_iterator it = in_flight_requests_.begin();
+           it != in_flight_requests_.end(); ++it) {
+        (*it)->UpdateDelayableRequestsInFlight(in_flight_delayable_count_);
+      }
+    }
+
+    if (RequestAttributesAreSet(request->attributes(),
+                                kAttributeLayoutBlocking) ||
+        !RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
+      // |request| is either a layout blocking or a non-delayable request.
+      request->UpdateDelayableRequestsInFlight(in_flight_delayable_count_);
+    }
   }
 
   void EraseInFlightRequest(ScheduledResourceRequest* request) {
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index 482b08c4..15b1dcc 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_param_associator.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/mock_entropy_provider.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/timer/mock_timer.h"
@@ -30,6 +31,7 @@
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/latency/latency_info.h"
 #include "url/scheme_host_port.h"
@@ -505,15 +507,38 @@
 }
 
 TEST_F(ResourceSchedulerTest, NavigationResetsState) {
+  base::HistogramTester histogram_tester;
   scheduler()->OnWillInsertBody(kChildId, kRouteId);
   scheduler()->OnNavigate(kChildId, kRouteId);
-  std::unique_ptr<TestRequest> high(
-      NewRequest("http://host/high", net::HIGHEST));
-  std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
-  std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
-  EXPECT_TRUE(high->started());
-  EXPECT_TRUE(low->started());
-  EXPECT_FALSE(low2->started());
+
+  {
+    std::unique_ptr<TestRequest> high(
+        NewRequest("http://host/high", net::HIGHEST));
+    std::unique_ptr<TestRequest> low(
+        NewRequest("http://host/low", net::LOWEST));
+    std::unique_ptr<TestRequest> low2(
+        NewRequest("http://host/low", net::LOWEST));
+    EXPECT_TRUE(high->started());
+    EXPECT_TRUE(low->started());
+    EXPECT_FALSE(low2->started());
+  }
+
+  histogram_tester.ExpectTotalCount("ResourceScheduler.RequestsCount.All", 2);
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("ResourceScheduler.RequestsCount.All"),
+      testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
+
+  histogram_tester.ExpectTotalCount("ResourceScheduler.RequestsCount.Delayable",
+                                    2);
+  histogram_tester.ExpectTotalCount(
+      "ResourceScheduler.RequestsCount.NonDelayable", 2);
+  histogram_tester.ExpectTotalCount(
+      "ResourceScheduler.RequestsCount.TotalLayoutBlocking", 2);
+
+  histogram_tester.ExpectUniqueSample(
+      "ResourceScheduler.PeakDelayableRequestsInFlight.LayoutBlocking", 1, 1);
+  histogram_tester.ExpectUniqueSample(
+      "ResourceScheduler.PeakDelayableRequestsInFlight.NonDelayable", 1, 1);
 }
 
 TEST_F(ResourceSchedulerTest, BackgroundRequestStartsImmediately) {
diff --git a/content/browser/net/network_quality_observer_impl.cc b/content/browser/net/network_quality_observer_impl.cc
index b7da988..1d871bc7 100644
--- a/content/browser/net/network_quality_observer_impl.cc
+++ b/content/browser/net/network_quality_observer_impl.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
+#include "net/nqe/network_quality_estimator.h"
 
 namespace {
 
@@ -213,7 +214,7 @@
                      last_notified_network_quality_));
 }
 
-std::unique_ptr<net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver>
+std::unique_ptr<net::RTTAndThroughputEstimatesObserver>
 CreateNetworkQualityObserver(
     net::NetworkQualityEstimator* network_quality_estimator) {
   return base::MakeUnique<NetworkQualityObserverImpl>(
diff --git a/content/browser/net/network_quality_observer_impl.h b/content/browser/net/network_quality_observer_impl.h
index 915ec17..2c5a181 100644
--- a/content/browser/net/network_quality_observer_impl.h
+++ b/content/browser/net/network_quality_observer_impl.h
@@ -11,19 +11,25 @@
 
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
+#include "base/time/time.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/network_quality_observer_factory.h"
 #include "net/nqe/effective_connection_type.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/network_quality.h"
-#include "net/nqe/network_quality_estimator.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
+
+namespace net {
+class NetworkQualityEstimator;
+}
 
 namespace content {
 
 // Listens for changes to the network quality and manages sending updates to
 // each RenderProcess via mojo.
 class CONTENT_EXPORT NetworkQualityObserverImpl
-    : public net::NetworkQualityEstimator::EffectiveConnectionTypeObserver,
-      public net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver {
+    : public net::EffectiveConnectionTypeObserver,
+      public net::RTTAndThroughputEstimatesObserver {
  public:
   explicit NetworkQualityObserverImpl(
       net::NetworkQualityEstimator* network_quality_estimator);
@@ -33,13 +39,11 @@
  private:
   class UiThreadObserver;
 
-  // net::NetworkQualityEstimator::EffectiveConnectionTypeObserver
-  // implementation:
+  // net::EffectiveConnectionTypeObserver implementation:
   void OnEffectiveConnectionTypeChanged(
       net::EffectiveConnectionType type) override;
 
-  // net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver
-  // implementation:
+  // net::RTTAndThroughputEstimatesObserver implementation:
   void OnRTTOrThroughputEstimatesComputed(
       base::TimeDelta http_rtt,
       base::TimeDelta transport_rtt,
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 0fe80c4..d939844 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -436,6 +436,8 @@
       compositor_frame_sink_request_pending_(false),
       weak_factory_(this) {
   GetSurfaceManager()->RegisterFrameSinkId(frame_sink_id_);
+  GetSurfaceManager()->RegisterBeginFrameSource(
+      root_window_->GetBeginFrameSource(), frame_sink_id_);
   DCHECK(client);
   DCHECK(root_window);
   DCHECK(root_window->GetLayer() == nullptr);
@@ -453,6 +455,8 @@
   root_window_->SetLayer(nullptr);
   // Clean-up any surface references.
   SetSurface(NULL);
+  GetSurfaceManager()->UnregisterBeginFrameSource(
+      root_window_->GetBeginFrameSource());
   GetSurfaceManager()->InvalidateFrameSinkId(frame_sink_id_);
 }
 
@@ -775,14 +779,14 @@
   cc::SurfaceManager* manager = GetSurfaceManager();
   auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
   std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
-      task_runner, display_output_surface->capabilities().max_frames_pending));
+      root_window_->GetBeginFrameSource(), task_runner,
+      display_output_surface->capabilities().max_frames_pending));
 
   display_.reset(new cc::Display(
       viz::HostSharedBitmapManager::current(),
       BrowserGpuMemoryBufferManager::current(),
       host_->GetSettings().renderer_settings, frame_sink_id_,
-      root_window_->GetBeginFrameSource(), std::move(display_output_surface),
-      std::move(scheduler),
+      std::move(display_output_surface), std::move(scheduler),
       base::MakeUnique<cc::TextureMailboxDeleter>(task_runner)));
 
   auto compositor_frame_sink =
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 9fa9d2b3..5dc4d9f 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1637,9 +1637,8 @@
 void RenderProcessHostImpl::CreateStoragePartitionService(
     const service_manager::BindSourceInfo& source_info,
     mojom::StoragePartitionServiceRequest request) {
-  // DO NOT REMOVE THIS COMMAND LINE CHECK WITHOUT SECURITY REVIEW!
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kMojoLocalStorage)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableMojoLocalStorage)) {
     storage_partition_impl_->Bind(std::move(request));
   }
 }
@@ -2181,7 +2180,7 @@
     switches::kMainFrameResizesAreOrientationChanges,
     switches::kMaxUntiledLayerWidth,
     switches::kMaxUntiledLayerHeight,
-    switches::kMojoLocalStorage,
+    switches::kDisableMojoLocalStorage,
     switches::kMSEAudioBufferSizeLimit,
     switches::kMSEVideoBufferSizeLimit,
     switches::kNoReferrers,
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 55e3168..6fb729c 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -79,17 +79,15 @@
 }
 
 SpeechRecognitionManagerImpl::~SpeechRecognitionManagerImpl() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(g_speech_recognition_manager_impl);
+
   g_speech_recognition_manager_impl = NULL;
 
   for (SessionsTable::iterator it = sessions_.begin(); it != sessions_.end();
        ++it) {
-    // MediaStreamUIProxy must be deleted on the IO thread.
-    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE,
-                              it->second->ui.release());
     delete it->second;
   }
-  sessions_.clear();
 }
 
 int SpeechRecognitionManagerImpl::CreateSession(
diff --git a/content/browser/speech/speech_recognition_manager_impl.h b/content/browser/speech/speech_recognition_manager_impl.h
index 0f06e91d..8c18de8c 100644
--- a/content/browser/speech/speech_recognition_manager_impl.h
+++ b/content/browser/speech/speech_recognition_manager_impl.h
@@ -93,10 +93,13 @@
   SpeechRecognitionManagerDelegate* delegate() const { return delegate_.get(); }
 
  protected:
-  // BrowserMainLoop is the only one allowed to istantiate and free us.
+  // BrowserMainLoop is the only one allowed to instantiate this class.
   friend class BrowserMainLoop;
-  // Needed for dtor.
+
+  // Needed for deletion on the IO thread.
   friend std::default_delete<SpeechRecognitionManagerImpl>;
+  friend class base::DeleteHelper<content::SpeechRecognitionManagerImpl>;
+
   SpeechRecognitionManagerImpl(media::AudioSystem* audio_system,
                                media::AudioManager* audio_manager,
                                MediaStreamManager* media_stream_manager);
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index 1aeac50..dbfae0b 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -13,7 +13,9 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/leveldb/public/cpp/util.h"
 #include "content/browser/browser_thread_impl.h"
+#include "content/browser/dom_storage/local_storage_database.pb.h"
 #include "content/browser/gpu/shader_cache_factory.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/local_storage_usage_info.h"
@@ -21,6 +23,7 @@
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/mock_leveldb_database.h"
 #include "net/base/test_completion_callback.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_store.h"
@@ -66,15 +69,6 @@
 const GURL kOrigin3(kTestOrigin3);
 const GURL kOriginDevTools(kTestOriginDevTools);
 
-const base::FilePath::CharType kDomStorageOrigin1[] =
-    FILE_PATH_LITERAL("http_host1_1.localstorage");
-
-const base::FilePath::CharType kDomStorageOrigin2[] =
-    FILE_PATH_LITERAL("http_host2_1.localstorage");
-
-const base::FilePath::CharType kDomStorageOrigin3[] =
-    FILE_PATH_LITERAL("http_host3_1.localstorage");
-
 const storage::StorageType kTemporary = storage::kStorageTypeTemporary;
 const storage::StorageType kPersistent = storage::kStorageTypePersistent;
 
@@ -183,7 +177,9 @@
 class RemoveLocalStorageTester {
  public:
   explicit RemoveLocalStorageTester(TestBrowserContext* profile)
-      : profile_(profile), dom_storage_context_(NULL) {
+      : dom_storage_context_(NULL),
+        mock_db_(&mock_data_),
+        db_binding_(&mock_db_) {
     dom_storage_context_ =
         content::BrowserContext::GetDefaultStoragePartition(profile)->
             GetDOMStorageContext();
@@ -202,35 +198,64 @@
 
   void AddDOMStorageTestData() {
     // Note: This test depends on details of how the dom_storage library
-    // stores data in the host file system.
-    base::FilePath storage_path =
-        profile_->GetPath().AppendASCII("Local Storage");
-    base::CreateDirectory(storage_path);
+    // stores data in the database.
+    leveldb::mojom::LevelDBDatabaseAssociatedPtr database_ptr;
+    leveldb::mojom::LevelDBDatabaseAssociatedRequest request =
+        MakeIsolatedRequest(&database_ptr);
+    static_cast<DOMStorageContextWrapper*>(dom_storage_context_)
+        ->SetLocalStorageDatabaseForTesting(std::move(database_ptr));
+    db_binding_.Bind(std::move(request));
 
-    // Write some files.
-    base::WriteFile(storage_path.Append(kDomStorageOrigin1), NULL, 0);
-    base::WriteFile(storage_path.Append(kDomStorageOrigin2), NULL, 0);
-    base::WriteFile(storage_path.Append(kDomStorageOrigin3), NULL, 0);
+    LocalStorageOriginMetaData data;
 
-    // Tweak their dates.
     base::Time now = base::Time::Now();
-    base::TouchFile(storage_path.Append(kDomStorageOrigin1), now, now);
+    data.set_last_modified(now.ToInternalValue());
+    data.set_size_bytes(16);
+    mock_data_[CreateMetaDataKey(url::Origin(kOrigin1))] =
+        leveldb::StdStringToUint8Vector(data.SerializeAsString());
+    mock_data_[CreateDataKey(url::Origin(kOrigin1))] = {};
 
     base::Time one_day_ago = now - base::TimeDelta::FromDays(1);
-    base::TouchFile(storage_path.Append(kDomStorageOrigin2),
-                    one_day_ago, one_day_ago);
+    data.set_last_modified(one_day_ago.ToInternalValue());
+    mock_data_[CreateMetaDataKey(url::Origin(kOrigin2))] =
+        leveldb::StdStringToUint8Vector(data.SerializeAsString());
+    mock_data_[CreateDataKey(url::Origin(kOrigin2))] = {};
 
     base::Time sixty_days_ago = now - base::TimeDelta::FromDays(60);
-    base::TouchFile(storage_path.Append(kDomStorageOrigin3),
-                    sixty_days_ago, sixty_days_ago);
+    data.set_last_modified(sixty_days_ago.ToInternalValue());
+    mock_data_[CreateMetaDataKey(url::Origin(kOrigin3))] =
+        leveldb::StdStringToUint8Vector(data.SerializeAsString());
+    mock_data_[CreateDataKey(url::Origin(kOrigin3))] = {};
   }
 
  private:
+  std::vector<uint8_t> CreateDataKey(const url::Origin& origin) {
+    auto serialized_origin =
+        leveldb::StdStringToUint8Vector(origin.Serialize());
+    std::vector<uint8_t> key = {'_'};
+    key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
+    key.push_back(0);
+    key.push_back('X');
+    return key;
+  }
+
+  std::vector<uint8_t> CreateMetaDataKey(const url::Origin& origin) {
+    const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', ':'};
+    auto serialized_origin =
+        leveldb::StdStringToUint8Vector(origin.Serialize());
+    std::vector<uint8_t> key;
+    key.reserve(arraysize(kMetaPrefix) + serialized_origin.size());
+    key.insert(key.end(), kMetaPrefix, kMetaPrefix + arraysize(kMetaPrefix));
+    key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
+    return key;
+  }
+
   void GetLocalStorageUsage() {
     dom_storage_context_->GetLocalStorageUsage(
         base::Bind(&RemoveLocalStorageTester::OnGotLocalStorageUsage,
                    base::Unretained(this)));
   }
+
   void OnGotLocalStorageUsage(
       const std::vector<content::LocalStorageUsageInfo>& infos) {
     infos_ = infos;
@@ -238,9 +263,12 @@
   }
 
   // We don't own these pointers.
-  TestBrowserContext* profile_;
   content::DOMStorageContext* dom_storage_context_;
 
+  std::map<std::vector<uint8_t>, std::vector<uint8_t>> mock_data_;
+  MockLevelDBDatabase mock_db_;
+  mojo::AssociatedBinding<leveldb::mojom::LevelDBDatabase> db_binding_;
+
   std::vector<content::LocalStorageUsageInfo> infos_;
 
   AwaitCompletionHelper await_completion_;
@@ -1155,6 +1183,10 @@
                  partition, base::Time(), base::Time::Max(),
                  base::Bind(&DoesOriginMatchForUnprotectedWeb), &run_loop));
   run_loop.Run();
+  // ClearData only guarantees that tasks to delete data are scheduled when its
+  // callback is invoked. It doesn't guarantee data has actually been cleared.
+  // So run all scheduled tasks to make sure data is cleared.
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
@@ -1187,6 +1219,10 @@
                  base::Bind(&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
                  &run_loop));
   run_loop.Run();
+  // ClearData only guarantees that tasks to delete data are scheduled when its
+  // callback is invoked. It doesn't guarantee data has actually been cleared.
+  // So run all scheduled tasks to make sure data is cleared.
+  base::RunLoop().RunUntilIdle();
 
   // Even if kOrigin1 is protected, it will be deleted since we specify
   // ClearData to delete protected data.
@@ -1216,6 +1252,10 @@
                  base::Bind(&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
                  &run_loop));
   run_loop.Run();
+  // ClearData only guarantees that tasks to delete data are scheduled when its
+  // callback is invoked. It doesn't guarantee data has actually been cleared.
+  // So run all scheduled tasks to make sure data is cleared.
+  base::RunLoop().RunUntilIdle();
 
   // kOrigin1 and kOrigin2 do not have age more than a week.
   EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
diff --git a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
index 53b22d9..9d1e517 100644
--- a/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
+++ b/content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java
@@ -1055,7 +1055,6 @@
 
     @CalledByNative
     private void onSelectionChanged(String text) {
-        mLastSelectedText = text;
         if (mSelectionClient != null) {
             mSelectionClient.onSelectionChanged(text);
         }
diff --git a/content/public/browser/network_quality_observer_factory.h b/content/public/browser/network_quality_observer_factory.h
index b6102a0ba..f0ae95b 100644
--- a/content/public/browser/network_quality_observer_factory.h
+++ b/content/public/browser/network_quality_observer_factory.h
@@ -12,14 +12,17 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
-#include "net/nqe/network_quality_estimator.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
+
+namespace net {
+class NetworkQualityEstimator;
+}
 
 namespace content {
 
 // Creates network quality observer that listens for changes to the network
 // quality and manages sending updates to each RenderProcess.
-CONTENT_EXPORT std::unique_ptr<
-    net::NetworkQualityEstimator::RTTAndThroughputEstimatesObserver>
+CONTENT_EXPORT std::unique_ptr<net::RTTAndThroughputEstimatesObserver>
 CreateNetworkQualityObserver(
     net::NetworkQualityEstimator* network_quality_estimator);
 
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 61e1cd08..920d57a6 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -205,6 +205,9 @@
 // Disables using CODECAPI_AVLowLatencyMode when creating DXVA decoders.
 const char kDisableLowLatencyDxva[]         = "disable-low-latency-dxva";
 
+// Dont use a Mojo-based LocalStorage implementation.
+const char kDisableMojoLocalStorage[] = "disable-mojo-local-storage";
+
 // Disables usage of the namespace sandbox.
 const char kDisableNamespaceSandbox[]       = "disable-namespace-sandbox";
 
@@ -637,9 +640,6 @@
 // Use Mojo-based Input Event routing.
 const char kMojoInputMessages[] = "mojo-input-messages";
 
-// Use a Mojo-based LocalStorage implementation.
-const char kMojoLocalStorage[]              = "mojo-local-storage";
-
 // Mutes audio sent to the audio device so it is not audible during
 // automated testing.
 const char kMuteAudio[]                     = "mute-audio";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index f629bdb..2c78940 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -70,6 +70,7 @@
 CONTENT_EXPORT extern const char kDisableKillAfterBadIPC[];
 CONTENT_EXPORT extern const char kDisableLocalStorage[];
 CONTENT_EXPORT extern const char kDisableLogging[];
+CONTENT_EXPORT extern const char kDisableMojoLocalStorage[];
 CONTENT_EXPORT extern const char kDisableNamespaceSandbox[];
 CONTENT_EXPORT extern const char kDisableNotifications[];
 CONTENT_EXPORT extern const char kDisablePartialRaster[];
@@ -194,7 +195,6 @@
 CONTENT_EXPORT extern const char kMHTMLSkipNostoreMain[];
 CONTENT_EXPORT extern const char kMHTMLSkipNostoreAll[];
 CONTENT_EXPORT extern const char kMojoInputMessages[];
-CONTENT_EXPORT extern const char kMojoLocalStorage[];
 CONTENT_EXPORT extern const char kMuteAudio[];
 CONTENT_EXPORT extern const char kNoReferrers[];
 CONTENT_EXPORT extern const char kNoSandbox[];
diff --git a/content/renderer/accessibility/blink_ax_enum_conversion.cc b/content/renderer/accessibility/blink_ax_enum_conversion.cc
index 26d72eb..4b405ba1 100644
--- a/content/renderer/accessibility/blink_ax_enum_conversion.cc
+++ b/content/renderer/accessibility/blink_ax_enum_conversion.cc
@@ -443,6 +443,8 @@
       return ui::AX_MARKER_TYPE_GRAMMAR;
     case blink::kWebAXMarkerTypeTextMatch:
       return ui::AX_MARKER_TYPE_TEXT_MATCH;
+    case blink::kWebAXMarkerTypeActiveSuggestion:
+      return ui::AX_MARKER_TYPE_ACTIVE_SUGGESTION;
   }
   NOTREACHED();
   return ui::AX_MARKER_TYPE_NONE;
diff --git a/content/renderer/android/synchronous_compositor_frame_sink.cc b/content/renderer/android/synchronous_compositor_frame_sink.cc
index a5d7fb8..18fc97375 100644
--- a/content/renderer/android/synchronous_compositor_frame_sink.cc
+++ b/content/renderer/android/synchronous_compositor_frame_sink.cc
@@ -198,8 +198,7 @@
   // process so there is no reason for it to use a SharedBitmapManager.
   display_.reset(new cc::Display(
       shared_bitmap_manager_, nullptr /* gpu_memory_buffer_manager */,
-      software_renderer_settings, kRootFrameSinkId,
-      nullptr /* begin_frame_source */, std::move(output_surface),
+      software_renderer_settings, kRootFrameSinkId, std::move(output_surface),
       nullptr /* scheduler */, nullptr /* texture_mailbox_deleter */));
   display_->Initialize(&display_client_, surface_manager_.get());
   display_->SetVisible(true);
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 9a8d0e84..398c49a8 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3325,12 +3325,14 @@
   }
 
   // Carry over the user agent override flag, if it exists.
+  // TODO(lukasza): https://crbug.com/426555: Need OOPIF support for propagating
+  // user agent overrides.
   blink::WebView* webview = render_view_->webview();
   if (content_initiated && webview && webview->MainFrame() &&
       webview->MainFrame()->IsWebLocalFrame() &&
-      webview->MainFrame()->DataSource()) {
-    DocumentState* old_document_state =
-        DocumentState::FromDataSource(webview->MainFrame()->DataSource());
+      webview->MainFrame()->ToWebLocalFrame()->DataSource()) {
+    DocumentState* old_document_state = DocumentState::FromDataSource(
+        webview->MainFrame()->ToWebLocalFrame()->DataSource());
     if (old_document_state) {
       InternalDocumentStateData* internal_data =
           InternalDocumentStateData::FromDocumentState(document_state);
@@ -4568,10 +4570,11 @@
   // return early and fix properly as part of https://crbug.com/426555.
   if (render_view_->webview()->MainFrame()->IsWebRemoteFrame())
     return blink::WebString();
+  WebLocalFrame* main_frame =
+      render_view_->webview()->MainFrame()->ToWebLocalFrame();
 
   // If we're in the middle of committing a load, the data source we need
   // will still be provisional.
-  WebFrame* main_frame = render_view_->webview()->MainFrame();
   WebDataSource* data_source = NULL;
   if (main_frame->ProvisionalDataSource())
     data_source = main_frame->ProvisionalDataSource();
@@ -4754,7 +4757,7 @@
 
 // Tell the embedding application that the URL of the active page has changed.
 void RenderFrameImpl::SendDidCommitProvisionalLoad(
-    blink::WebFrame* frame,
+    blink::WebLocalFrame* frame,
     blink::WebHistoryCommitType commit_type) {
   DCHECK_EQ(frame_, frame);
   WebDataSource* ds = frame->DataSource();
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index aecba8d..81015a3f 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -93,6 +93,7 @@
 
 namespace blink {
 class WebContentDecryptionModule;
+class WebLocalFrame;
 class WebPresentationClient;
 class WebPushClient;
 class WebSecurityOrigin;
@@ -826,7 +827,7 @@
   const RenderFrameImpl* GetLocalRoot() const;
 
   // Builds and sends DidCommitProvisionalLoad to the host.
-  void SendDidCommitProvisionalLoad(blink::WebFrame* frame,
+  void SendDidCommitProvisionalLoad(blink::WebLocalFrame* frame,
                                     blink::WebHistoryCommitType commit_type);
 
   // Swaps the current frame into the frame tree, replacing the
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 5ac16ec..06e60c54 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -466,8 +466,8 @@
 
 std::unique_ptr<WebStorageNamespace>
 RendererBlinkPlatformImpl::CreateLocalStorageNamespace() {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kMojoLocalStorage)) {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableMojoLocalStorage)) {
     if (!local_storage_cached_areas_) {
       local_storage_cached_areas_.reset(new LocalStorageCachedAreas(
           RenderThreadImpl::current()->GetStoragePartitionService()));
diff --git a/content/shell/test_runner/test_runner.cc b/content/shell/test_runner/test_runner.cc
index 416872b6d..9763472d 100644
--- a/content/shell/test_runner/test_runner.cc
+++ b/content/shell/test_runner/test_runner.cc
@@ -2558,8 +2558,12 @@
 void TestRunner::SetDisallowedSubresourcePathSuffixes(
     const std::vector<std::string>& suffixes) {
   DCHECK(main_view_);
-  main_view_->MainFrame()->DataSource()->SetSubresourceFilter(
-      new MockWebDocumentSubresourceFilter(suffixes));
+  if (!main_view_->MainFrame()->IsWebLocalFrame())
+    return;
+  main_view_->MainFrame()
+      ->ToWebLocalFrame()
+      ->DataSource()
+      ->SetSubresourceFilter(new MockWebDocumentSubresourceFilter(suffixes));
 }
 
 void TestRunner::DumpSpellCheckCallbacks() {
@@ -2791,7 +2795,11 @@
   if (!main_view_)
     return;
 
-  WebDataSource* data_source = main_view_->MainFrame()->DataSource();
+  if (!main_view_->MainFrame()->IsWebLocalFrame())
+    return;
+
+  WebDataSource* data_source =
+      main_view_->MainFrame()->ToWebLocalFrame()->DataSource();
   if (!data_source)
     return;
 
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 572907cb..ad54843 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -756,8 +756,6 @@
     # This test causes a lost device and then the next test fails.
     self.Skip('conformance2/rendering/blitframebuffer-size-overflow.html',
         ['linux', ('nvidia', 0x1cb3)], bug=709320)
-    self.Fail('deqp/functional/gles3/multisample.html',
-        ['linux', ('nvidia', 0x1cb3)], bug=702861)
 
     # Linux Intel
     self.Fail('conformance2/extensions/ext-color-buffer-float.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index 33fbb01..715d537 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
+++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@
 # AUTOGENERATED FILE - DO NOT EDIT
 # SEE roll_webgl_conformance.py
-Current webgl revision 9422979e2a13b6d80de866a271a34653998d4c85
+Current webgl revision 331fe3a462b2e1f5c9baa1a710312a1b5888e404
diff --git a/extensions/browser/api/media_perception_private/conversion_utils.cc b/extensions/browser/api/media_perception_private/conversion_utils.cc
index ea303fc5..ef73053 100644
--- a/extensions/browser/api/media_perception_private/conversion_utils.cc
+++ b/extensions/browser/api/media_perception_private/conversion_utils.cc
@@ -43,6 +43,31 @@
   return bounding_box_result;
 }
 
+DistanceUnits DistanceUnitsProtoToIdl(const mri::Distance& distance) {
+  if (distance.has_units()) {
+    switch (distance.units()) {
+      case mri::Distance::METERS:
+        return DISTANCE_UNITS_METERS;
+      case mri::Distance::PIXELS:
+        return DISTANCE_UNITS_PIXELS;
+      case mri::Distance::UNITS_UNSPECIFIED:
+        return DISTANCE_UNITS_UNSPECIFIED;
+    }
+    NOTREACHED() << "Unknown distance units: " << distance.units();
+  }
+  return DISTANCE_UNITS_UNSPECIFIED;
+}
+
+std::unique_ptr<Distance> DistanceProtoToIdl(const mri::Distance& distance) {
+  std::unique_ptr<Distance> distance_result = base::MakeUnique<Distance>();
+  distance_result->units = DistanceUnitsProtoToIdl(distance);
+
+  if (distance.has_magnitude())
+    distance_result->magnitude = base::MakeUnique<double>(distance.magnitude());
+
+  return distance_result;
+}
+
 EntityType EntityTypeProtoToIdl(const mri::Entity& entity) {
   if (entity.has_type()) {
     switch (entity.type()) {
@@ -50,6 +75,8 @@
         return ENTITY_TYPE_FACE;
       case mri::Entity::PERSON:
         return ENTITY_TYPE_PERSON;
+      case mri::Entity::MOTION_REGION:
+        return ENTITY_TYPE_MOTION_REGION;
       case mri::Entity::UNSPECIFIED:
         return ENTITY_TYPE_UNSPECIFIED;
     }
@@ -70,6 +97,9 @@
   if (entity.has_bounding_box())
     entity_result.bounding_box = BoundingBoxProtoToIdl(entity.bounding_box());
 
+  if (entity.has_depth())
+    entity_result.depth = DistanceProtoToIdl(entity.depth());
+
   return entity_result;
 }
 
diff --git a/extensions/browser/api/media_perception_private/conversion_utils_unittest.cc b/extensions/browser/api/media_perception_private/conversion_utils_unittest.cc
index 0c3aa0f..6217fb4 100644
--- a/extensions/browser/api/media_perception_private/conversion_utils_unittest.cc
+++ b/extensions/browser/api/media_perception_private/conversion_utils_unittest.cc
@@ -23,15 +23,21 @@
   frame_perception->set_frame_height_in_px(4);
   frame_perception->set_timestamp(5);
 
+  // Add a couple fake entities to the frame perception. Note: PERSON
+  // EntityType is currently unused.
   mri::Entity* entity_one = frame_perception->add_entity();
   entity_one->set_id(6);
   entity_one->set_type(mri::Entity::FACE);
   entity_one->set_confidence(7);
 
-  mri::Entity* e_two = frame_perception->add_entity();
-  e_two->set_id(8);
-  e_two->set_type(mri::Entity::PERSON);
-  e_two->set_confidence(9);
+  mri::Distance* distance = entity_one->mutable_depth();
+  distance->set_units(mri::Distance::METERS);
+  distance->set_magnitude(7.5);
+
+  mri::Entity* entity_two = frame_perception->add_entity();
+  entity_two->set_id(8);
+  entity_two->set_type(mri::Entity::MOTION_REGION);
+  entity_two->set_confidence(9);
 
   mri::BoundingBox* bounding_box_one = entity_one->mutable_bounding_box();
   bounding_box_one->mutable_top_left()->set_x(10);
@@ -40,7 +46,7 @@
   bounding_box_one->mutable_bottom_right()->set_y(13);
   bounding_box_one->set_normalized(false);
 
-  mri::BoundingBox* bounding_box_two = e_two->mutable_bounding_box();
+  mri::BoundingBox* bounding_box_two = entity_two->mutable_bounding_box();
   bounding_box_two->mutable_top_left()->set_x(14);
   bounding_box_two->mutable_top_left()->set_y(15);
   bounding_box_two->set_normalized(true);
@@ -67,13 +73,20 @@
   EXPECT_EQ(*entity_result_one.confidence, 7);
   EXPECT_EQ(entity_result_one.type, media_perception::ENTITY_TYPE_FACE);
 
+  const media_perception::Distance* distance = entity_result_one.depth.get();
+  ASSERT_TRUE(distance);
+  EXPECT_EQ(media_perception::DISTANCE_UNITS_METERS, distance->units);
+  ASSERT_TRUE(distance->magnitude);
+  EXPECT_EQ(7.5f, *distance->magnitude);
+
   const media_perception::Entity& entity_result_two =
       frame_perception_result.entities->at(1);
   ASSERT_TRUE(entity_result_two.id);
   EXPECT_EQ(*entity_result_two.id, 8);
   ASSERT_TRUE(entity_result_two.confidence);
   EXPECT_EQ(*entity_result_two.confidence, 9);
-  EXPECT_EQ(entity_result_two.type, media_perception::ENTITY_TYPE_PERSON);
+  EXPECT_EQ(entity_result_two.type,
+            media_perception::ENTITY_TYPE_MOTION_REGION);
 
   const media_perception::BoundingBox* bounding_box_result_one =
       entity_result_one.bounding_box.get();
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc
index b3d8b4e..6a94bdf 100644
--- a/extensions/browser/extension_web_contents_observer.cc
+++ b/extensions/browser/extension_web_contents_observer.cc
@@ -147,14 +147,8 @@
   const Extension* frame_extension =
       GetExtensionFromFrame(render_frame_host, true);
   if (pm->IsRenderFrameHostRegistered(render_frame_host)) {
-    if (frame_extension && !navigation_handle->IsSameDocument()) {
-      // Notify ProcessManager, because some clients do not just want to know
-      // whether the frame is in an extension process, but also whether the
-      // frame was navigated.
-      pm->DidNavigateRenderFrameHost(render_frame_host);
-    } else if (!frame_extension) {
+    if (!frame_extension)
       pm->UnregisterRenderFrameHost(render_frame_host);
-    }
   } else if (frame_extension) {
     pm->RegisterRenderFrameHost(web_contents(), render_frame_host,
                                 frame_extension);
diff --git a/extensions/browser/process_manager.cc b/extensions/browser/process_manager.cc
index 5a8ff38..cb63e501 100644
--- a/extensions/browser/process_manager.cc
+++ b/extensions/browser/process_manager.cc
@@ -292,19 +292,6 @@
   }
 }
 
-void ProcessManager::DidNavigateRenderFrameHost(
-    content::RenderFrameHost* render_frame_host) {
-  ExtensionRenderFrames::iterator frame =
-      all_extension_frames_.find(render_frame_host);
-
-  if (frame != all_extension_frames_.end()) {
-    std::string extension_id = GetExtensionID(render_frame_host);
-
-    for (auto& observer : observer_list_)
-      observer.OnExtensionFrameNavigated(extension_id, render_frame_host);
-  }
-}
-
 scoped_refptr<content::SiteInstance> ProcessManager::GetSiteInstanceForURL(
     const GURL& url) {
   return site_instance_->GetRelatedSiteInstance(url);
diff --git a/extensions/browser/process_manager.h b/extensions/browser/process_manager.h
index 209aff7..e4843160 100644
--- a/extensions/browser/process_manager.h
+++ b/extensions/browser/process_manager.h
@@ -64,7 +64,6 @@
                                content::RenderFrameHost* render_frame_host,
                                const Extension* extension);
   void UnregisterRenderFrameHost(content::RenderFrameHost* render_frame_host);
-  void DidNavigateRenderFrameHost(content::RenderFrameHost* render_frame_host);
 
   // Returns the SiteInstance that the given URL belongs to.
   // TODO(aa): This only returns correct results for extensions and packaged
diff --git a/extensions/browser/process_manager_observer.h b/extensions/browser/process_manager_observer.h
index 47883ef..037c4b6c 100644
--- a/extensions/browser/process_manager_observer.h
+++ b/extensions/browser/process_manager_observer.h
@@ -39,12 +39,6 @@
   virtual void OnExtensionFrameUnregistered(
       const std::string& extension_id,
       content::RenderFrameHost* render_frame_host) {}
-
-  // Called when a RenderFrameHost was navigated to another page within the
-  // extension process.
-  virtual void OnExtensionFrameNavigated(
-      const std::string& extension_id,
-      content::RenderFrameHost* render_frame_host) {}
 };
 
 }  // namespace extensions
diff --git a/extensions/common/api/media_perception_private.idl b/extensions/common/api/media_perception_private.idl
index 07ea801c..131ba69 100644
--- a/extensions/common/api/media_perception_private.idl
+++ b/extensions/common/api/media_perception_private.idl
@@ -28,7 +28,7 @@
     SUSPENDED
   };
 
-  // The system and configuration state of the analytics process and v4lplugin.
+  // The system and configuration state of the analytics process.
   dictionary State {
     Status status;
 
@@ -55,10 +55,26 @@
     Point? bottomRight;
   };
 
+  enum DistanceUnits {
+    UNSPECIFIED,
+    METERS,
+    PIXELS
+  };
+
+  // Generic dictionary to encapsulate a distance magnitude and units.
+  dictionary Distance {
+    // This field provides flexibility to report depths or distances of
+    // different entity types with different units.
+    DistanceUnits? units;
+
+    double? magnitude;
+  };
+
   enum EntityType {
     UNSPECIFIED,
     FACE,
-    PERSON
+    PERSON,
+    MOTION_REGION
   };
 
   dictionary Entity {
@@ -75,7 +91,7 @@
     double? confidence;
 
     // The estimated depth of the entity from the camera.
-    double? depthInMeters;
+    Distance? depth;
   };
 
   // The set of computer vision metadata for an image frame.
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index a7acb93..b5416c7f 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -105,6 +105,8 @@
 static_library("test_support") {
   testonly = true
   sources = [
+    "command_buffer/client/client_test_helper.cc",
+    "command_buffer/client/client_test_helper.h",
     "command_buffer/client/gles2_interface_stub.cc",
     "command_buffer/client/gles2_interface_stub.h",
     "command_buffer/service/error_state_mock.cc",
@@ -121,6 +123,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//ui/gl:gl_unittest_utils",
+    "//ui/latency:test_support",
   ]
 }
 
@@ -219,8 +222,6 @@
   sources = [
     "command_buffer/client/buffer_tracker_unittest.cc",
     "command_buffer/client/client_discardable_manager_unittest.cc",
-    "command_buffer/client/client_test_helper.cc",
-    "command_buffer/client/client_test_helper.h",
     "command_buffer/client/cmd_buffer_helper_test.cc",
     "command_buffer/client/fenced_allocator_test.cc",
     "command_buffer/client/gles2_implementation_unittest.cc",
diff --git a/gpu/command_buffer/client/client_test_helper.cc b/gpu/command_buffer/client/client_test_helper.cc
index e1cbda5..cbfb70ee 100644
--- a/gpu/command_buffer/client/client_test_helper.cc
+++ b/gpu/command_buffer/client/client_test_helper.cc
@@ -35,7 +35,7 @@
 // Get's the Id of the next transfer buffer that will be returned
 // by CreateTransferBuffer. This is useful for testing expected ids.
 int32_t FakeCommandBufferServiceBase::GetNextFreeTransferBufferId() {
-  for (size_t ii = 0; ii < arraysize(transfer_buffer_buffers_); ++ii) {
+  for (int32_t ii = 0; ii < kMaxTransferBuffers; ++ii) {
     if (!transfer_buffer_buffers_[ii].get()) {
       return kTransferBufferBaseId + ii;
     }
diff --git a/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/gpu/command_buffer/client/cmd_buffer_helper_test.cc
index 3cada6a..9027ae5 100644
--- a/gpu/command_buffer/client/cmd_buffer_helper_test.cc
+++ b/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -42,9 +42,8 @@
 class CommandBufferDirectLocked : public CommandBufferDirect {
  public:
   explicit CommandBufferDirectLocked(
-      TransferBufferManager* transfer_buffer_manager,
-      AsyncAPIInterface* handler)
-      : CommandBufferDirect(transfer_buffer_manager, handler),
+      TransferBufferManager* transfer_buffer_manager)
+      : CommandBufferDirect(transfer_buffer_manager),
         flush_locked_(false),
         last_flush_(-1),
         previous_put_offset_(0),
@@ -98,19 +97,17 @@
 class CommandBufferHelperTest : public testing::Test {
  protected:
   virtual void SetUp() {
-    api_mock_.reset(new AsyncAPIMock(true));
+    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
+    command_buffer_.reset(
+        new CommandBufferDirectLocked(transfer_buffer_manager_.get()));
+    api_mock_.reset(new AsyncAPIMock(true, command_buffer_->service()));
+    command_buffer_->set_handler(api_mock_.get());
 
     // ignore noops in the mock - we don't want to inspect the internals of the
     // helper.
     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
         .WillRepeatedly(Return(error::kNoError));
 
-    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
-    command_buffer_.reset(new CommandBufferDirectLocked(
-        transfer_buffer_manager_.get(), api_mock_.get()));
-
-    api_mock_->set_command_buffer_service(command_buffer_->service());
-
     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
     helper_->Initialize(kCommandBufferSizeBytes);
 
@@ -253,9 +250,9 @@
 
   CommandBufferOffset get_helper_put() { return helper_->put_; }
 
-  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<CommandBufferDirectLocked> command_buffer_;
+  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<CommandBufferHelper> helper_;
   std::vector<std::unique_ptr<CommandBufferEntry[]>> test_command_args_;
   unsigned int test_command_next_id_;
diff --git a/gpu/command_buffer/client/fenced_allocator_test.cc b/gpu/command_buffer/client/fenced_allocator_test.cc
index c19a066..000738d7a 100644
--- a/gpu/command_buffer/client/fenced_allocator_test.cc
+++ b/gpu/command_buffer/client/fenced_allocator_test.cc
@@ -38,7 +38,12 @@
   static const int kAllocAlignment = 16;
 
   void SetUp() override {
-    api_mock_.reset(new AsyncAPIMock(true));
+    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
+    command_buffer_.reset(
+        new CommandBufferDirect(transfer_buffer_manager_.get()));
+    api_mock_.reset(new AsyncAPIMock(true, command_buffer_->service()));
+    command_buffer_->set_handler(api_mock_.get());
+
     // ignore noops in the mock - we don't want to inspect the internals of the
     // helper.
     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
@@ -48,21 +53,15 @@
         .WillRepeatedly(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                               Return(error::kNoError)));
 
-    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
-    command_buffer_.reset(new CommandBufferDirect(
-        transfer_buffer_manager_.get(), api_mock_.get()));
-
-    api_mock_->set_command_buffer_service(command_buffer_->service());
-
     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
     helper_->Initialize(kBufferSize);
   }
 
   int32_t GetToken() { return command_buffer_->GetLastState().token; }
 
-  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<CommandBufferDirect> command_buffer_;
+  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<CommandBufferHelper> helper_;
   base::MessageLoop message_loop_;
 };
diff --git a/gpu/command_buffer/client/mapped_memory_unittest.cc b/gpu/command_buffer/client/mapped_memory_unittest.cc
index 134f55a..c36f663 100644
--- a/gpu/command_buffer/client/mapped_memory_unittest.cc
+++ b/gpu/command_buffer/client/mapped_memory_unittest.cc
@@ -35,7 +35,12 @@
   static const unsigned int kBufferSize = 1024;
 
   void SetUp() override {
-    api_mock_.reset(new AsyncAPIMock(true));
+    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
+    command_buffer_.reset(
+        new CommandBufferDirect(transfer_buffer_manager_.get()));
+    api_mock_.reset(new AsyncAPIMock(true, command_buffer_->service()));
+    command_buffer_->set_handler(api_mock_.get());
+
     // ignore noops in the mock - we don't want to inspect the internals of the
     // helper.
     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
@@ -45,21 +50,15 @@
         .WillRepeatedly(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
                               Return(error::kNoError)));
 
-    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
-    command_buffer_.reset(new CommandBufferDirect(
-        transfer_buffer_manager_.get(), api_mock_.get()));
-
-    api_mock_->set_command_buffer_service(command_buffer_->service());
-
     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
     helper_->Initialize(kBufferSize);
   }
 
   int32_t GetToken() { return command_buffer_->GetLastState().token; }
 
-  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<CommandBufferDirect> command_buffer_;
+  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<CommandBufferHelper> helper_;
   base::MessageLoop message_loop_;
 };
diff --git a/gpu/command_buffer/client/ring_buffer_test.cc b/gpu/command_buffer/client/ring_buffer_test.cc
index 86ffa7d9..242e369 100644
--- a/gpu/command_buffer/client/ring_buffer_test.cc
+++ b/gpu/command_buffer/client/ring_buffer_test.cc
@@ -60,7 +60,12 @@
 
   void SetUp() override {
     delay_set_token_ = false;
-    api_mock_.reset(new AsyncAPIMock(true));
+    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
+    command_buffer_.reset(
+        new CommandBufferDirect(transfer_buffer_manager_.get()));
+    api_mock_.reset(new AsyncAPIMock(true, command_buffer_->service()));
+    command_buffer_->set_handler(api_mock_.get());
+
     // ignore noops in the mock - we don't want to inspect the internals of the
     // helper.
     EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
@@ -70,21 +75,15 @@
         .WillRepeatedly(DoAll(Invoke(this, &BaseRingBufferTest::SetToken),
                               Return(error::kNoError)));
 
-    transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
-    command_buffer_.reset(new CommandBufferDirect(
-        transfer_buffer_manager_.get(), api_mock_.get()));
-
-    api_mock_->set_command_buffer_service(command_buffer_->service());
-
     helper_.reset(new CommandBufferHelper(command_buffer_.get()));
     helper_->Initialize(kBufferSize);
   }
 
   int32_t GetToken() { return command_buffer_->GetLastState().token; }
 
-  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<CommandBufferDirect> command_buffer_;
+  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<CommandBufferHelper> helper_;
   std::vector<const volatile void*> set_token_arguments_;
   bool delay_set_token_;
diff --git a/gpu/command_buffer/service/command_buffer_direct.cc b/gpu/command_buffer/service/command_buffer_direct.cc
index 765edd1b..890cd6b 100644
--- a/gpu/command_buffer/service/command_buffer_direct.cc
+++ b/gpu/command_buffer/service/command_buffer_direct.cc
@@ -13,27 +13,17 @@
 namespace {
 
 uint64_t g_next_command_buffer_id = 1;
-bool AlwaysTrue() {
-  return true;
-}
 
 }  // anonymous namespace
 
 CommandBufferDirect::CommandBufferDirect(
-    TransferBufferManager* transfer_buffer_manager,
-    AsyncAPIInterface* handler)
-    : CommandBufferDirect(transfer_buffer_manager,
-                          handler,
-                          base::Bind(&AlwaysTrue),
-                          nullptr) {}
+    TransferBufferManager* transfer_buffer_manager)
+    : CommandBufferDirect(transfer_buffer_manager, nullptr) {}
 
 CommandBufferDirect::CommandBufferDirect(
     TransferBufferManager* transfer_buffer_manager,
-    AsyncAPIInterface* handler,
-    const MakeCurrentCallback& callback,
     SyncPointManager* sync_point_manager)
-    : service_(this, transfer_buffer_manager, handler),
-      make_current_callback_(callback),
+    : service_(this, transfer_buffer_manager),
       sync_point_manager_(sync_point_manager),
       command_buffer_id_(
           CommandBufferId::FromUnsafeValue(g_next_command_buffer_id++)) {
@@ -84,10 +74,7 @@
 }
 
 void CommandBufferDirect::Flush(int32_t put_offset) {
-  if (!make_current_callback_.Run()) {
-    service_.SetParseError(error::kLostContext);
-    return;
-  }
+  DCHECK(handler_);
   uint32_t order_num = 0;
   if (sync_point_manager_) {
     // If sync point manager is supported, assign order numbers to commands.
@@ -109,7 +96,7 @@
     return;
   }
 
-  service_.Flush(put_offset);
+  service_.Flush(put_offset, handler_);
   if (sync_point_manager_) {
     // Finish processing order number here.
     sync_point_order_data_->FinishProcessingOrderNumber(order_num);
@@ -140,6 +127,34 @@
 
 void CommandBufferDirect::OnParseError() {}
 
+void CommandBufferDirect::OnConsoleMessage(int32_t id,
+                                           const std::string& message) {}
+
+void CommandBufferDirect::CacheShader(const std::string& key,
+                                      const std::string& shader) {}
+
+void CommandBufferDirect::OnFenceSyncRelease(uint64_t release) {
+  DCHECK(sync_point_client_state_);
+  service_.SetReleaseCount(release);
+  sync_point_client_state_->ReleaseFenceSync(release);
+}
+
+bool CommandBufferDirect::OnWaitSyncToken(const gpu::SyncToken& sync_token) {
+  DCHECK(sync_point_manager_);
+  if (sync_point_manager_->IsSyncTokenReleased(sync_token))
+    return false;
+  service_.SetScheduled(false);
+  return true;
+}
+
+void CommandBufferDirect::OnDescheduleUntilFinished() {
+  service_.SetScheduled(false);
+}
+
+void CommandBufferDirect::OnRescheduleAfterFinished() {
+  service_.SetScheduled(true);
+}
+
 gpu::CommandBufferNamespace CommandBufferDirect::GetNamespaceID() const {
   return gpu::CommandBufferNamespace::IN_PROCESS;
 }
@@ -152,20 +167,6 @@
   pause_commands_ = paused;
 }
 
-void CommandBufferDirect::OnFenceSyncRelease(uint64_t release) {
-  DCHECK(sync_point_client_state_);
-  service_.SetReleaseCount(release);
-  sync_point_client_state_->ReleaseFenceSync(release);
-}
-
-bool CommandBufferDirect::OnWaitSyncToken(const SyncToken& sync_token) {
-  DCHECK(sync_point_manager_);
-  if (sync_point_manager_->IsSyncTokenReleased(sync_token))
-    return false;
-  service_.SetScheduled(false);
-  return true;
-}
-
 void CommandBufferDirect::SignalSyncToken(const gpu::SyncToken& sync_token,
                                           const base::Closure& callback) {
   if (sync_point_manager_) {
diff --git a/gpu/command_buffer/service/command_buffer_direct.h b/gpu/command_buffer/service/command_buffer_direct.h
index 1c94cc6..ba491f62 100644
--- a/gpu/command_buffer/service/command_buffer_direct.h
+++ b/gpu/command_buffer/service/command_buffer_direct.h
@@ -9,6 +9,7 @@
 #include "gpu/command_buffer/common/command_buffer_id.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/gpu_export.h"
 
 namespace gpu {
@@ -21,19 +22,18 @@
 struct SyncToken;
 
 class GPU_EXPORT CommandBufferDirect : public CommandBuffer,
-                                       public CommandBufferServiceClient {
+                                       public CommandBufferServiceClient,
+                                       public gles2::GLES2DecoderClient {
  public:
   using MakeCurrentCallback = base::Callback<bool()>;
 
   CommandBufferDirect(TransferBufferManager* transfer_buffer_manager,
-                      AsyncAPIInterface* handler,
-                      const MakeCurrentCallback& callback,
                       SyncPointManager* sync_point_manager);
-  CommandBufferDirect(TransferBufferManager* transfer_buffer_manager,
-                      AsyncAPIInterface* handler);
+  explicit CommandBufferDirect(TransferBufferManager* transfer_buffer_manager);
 
   ~CommandBufferDirect() override;
 
+  void set_handler(AsyncAPIInterface* handler) { handler_ = handler; }
   CommandBufferServiceBase* service() { return &service_; }
 
   // CommandBuffer implementation:
@@ -52,12 +52,18 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
+  // GLES2DecoderClient implementation
+  void OnConsoleMessage(int32_t id, const std::string& message) override;
+  void CacheShader(const std::string& key, const std::string& shader) override;
+  void OnFenceSyncRelease(uint64_t release) override;
+  bool OnWaitSyncToken(const gpu::SyncToken&) override;
+  void OnDescheduleUntilFinished() override;
+  void OnRescheduleAfterFinished() override;
+
   CommandBufferNamespace GetNamespaceID() const;
   CommandBufferId GetCommandBufferID() const;
 
   void SetCommandsPaused(bool paused);
-  void OnFenceSyncRelease(uint64_t release);
-  bool OnWaitSyncToken(const SyncToken& sync_token);
   void SignalSyncToken(const gpu::SyncToken& sync_token,
                        const base::Closure& callback);
 
@@ -65,9 +71,9 @@
 
  private:
   CommandBufferService service_;
-  MakeCurrentCallback make_current_callback_;
   SyncPointManager* sync_point_manager_;
 
+  AsyncAPIInterface* handler_ = nullptr;
   scoped_refptr<SyncPointOrderData> sync_point_order_data_;
   scoped_refptr<SyncPointClientState> sync_point_client_state_;
   bool pause_commands_ = false;
diff --git a/gpu/command_buffer/service/command_buffer_service.cc b/gpu/command_buffer/service/command_buffer_service.cc
index 7ca29e1..74865e9 100644
--- a/gpu/command_buffer/service/command_buffer_service.cc
+++ b/gpu/command_buffer/service/command_buffer_service.cc
@@ -41,14 +41,10 @@
 
 CommandBufferService::CommandBufferService(
     CommandBufferServiceClient* client,
-    TransferBufferManager* transfer_buffer_manager,
-    AsyncAPIInterface* handler)
-    : client_(client),
-      transfer_buffer_manager_(transfer_buffer_manager),
-      handler_(handler) {
+    TransferBufferManager* transfer_buffer_manager)
+    : client_(client), transfer_buffer_manager_(transfer_buffer_manager) {
   DCHECK(client_);
   DCHECK(transfer_buffer_manager_);
-  DCHECK(handler_);
   state_.token = 0;
 }
 
@@ -60,14 +56,16 @@
     shared_state_->Write(state_);
 }
 
-void CommandBufferService::Flush(int32_t put_offset) {
+void CommandBufferService::Flush(int32_t put_offset,
+                                 AsyncAPIInterface* handler) {
+  DCHECK(handler);
   if (put_offset < 0 || put_offset >= num_entries_) {
     SetParseError(gpu::error::kOutOfBounds);
     return;
   }
 
   TRACE_EVENT1("gpu", "CommandBufferService:PutChanged", "handler",
-               handler_->GetLogPrefix().as_string());
+               handler->GetLogPrefix().as_string());
 
   put_offset_ = put_offset;
 
@@ -83,10 +81,21 @@
     TRACE_COUNTER_ID1("gpu", "CommandBufferService::Paused", this, paused_);
   }
 
-  error::Error error = error::kNoError;
-  handler_->BeginDecoding();
+  handler->BeginDecoding();
+  int end = put_offset_ < state_.get_offset ? num_entries_ : put_offset_;
   while (put_offset_ != state_.get_offset) {
-    error = ProcessCommands(kParseCommandsSlice);
+    int num_entries = end - state_.get_offset;
+    int entries_processed = 0;
+    error::Error error =
+        handler->DoCommands(kParseCommandsSlice, buffer_ + state_.get_offset,
+                            num_entries, &entries_processed);
+
+    state_.get_offset += entries_processed;
+    DCHECK_LE(state_.get_offset, num_entries_);
+    if (state_.get_offset == num_entries_) {
+      end = put_offset_;
+      state_.get_offset = 0;
+    }
 
     if (error::IsError(error)) {
       SetParseError(error);
@@ -104,7 +113,7 @@
       break;
   }
 
-  handler_->EndDecoding();
+  handler->EndDecoding();
 }
 
 void CommandBufferService::SetGetBuffer(int32_t transfer_buffer_id) {
@@ -225,21 +234,4 @@
   scheduled_ = scheduled;
 }
 
-error::Error CommandBufferService::ProcessCommands(int num_commands) {
-  int num_entries = put_offset_ < state_.get_offset
-                        ? num_entries_ - state_.get_offset
-                        : put_offset_ - state_.get_offset;
-
-  int entries_processed = 0;
-  error::Error result =
-      handler_->DoCommands(num_commands, buffer_ + state_.get_offset,
-                           num_entries, &entries_processed);
-
-  state_.get_offset += entries_processed;
-  if (state_.get_offset == num_entries_)
-    state_.get_offset = 0;
-
-  return result;
-}
-
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/command_buffer_service.h b/gpu/command_buffer/service/command_buffer_service.h
index 730a9a1..12f8373 100644
--- a/gpu/command_buffer/service/command_buffer_service.h
+++ b/gpu/command_buffer/service/command_buffer_service.h
@@ -73,8 +73,7 @@
   static const int kParseCommandsSlice = 20;
 
   CommandBufferService(CommandBufferServiceClient* client,
-                       TransferBufferManager* transfer_buffer_manager,
-                       AsyncAPIInterface* handler);
+                       TransferBufferManager* transfer_buffer_manager);
   ~CommandBufferService() override;
 
   // CommandBufferServiceBase implementation:
@@ -92,9 +91,8 @@
   // state transfer buffer.
   void UpdateState();
 
-  // Flushes up to the put_offset and calls the PutOffsetChangeCallback to
-  // execute commands.
-  void Flush(int32_t put_offset);
+  // Flushes up to the put_offset and execute commands with the handler.
+  void Flush(int32_t put_offset, AsyncAPIInterface* handler);
 
   // Sets the get buffer and call the GetBufferChangeCallback.
   void SetGetBuffer(int32_t transfer_buffer_id);
@@ -123,11 +121,8 @@
   int32_t put_offset() const { return put_offset_; }
 
  private:
-  error::Error ProcessCommands(int num_commands);
-
   CommandBufferServiceClient* client_;
   TransferBufferManager* transfer_buffer_manager_;
-  AsyncAPIInterface* handler_;
 
   CommandBuffer::State state_;
   int32_t put_offset_ = 0;
diff --git a/gpu/command_buffer/service/command_buffer_service_unittest.cc b/gpu/command_buffer/service/command_buffer_service_unittest.cc
index 1e249a9..7531d5f8 100644
--- a/gpu/command_buffer/service/command_buffer_service_unittest.cc
+++ b/gpu/command_buffer/service/command_buffer_service_unittest.cc
@@ -33,9 +33,6 @@
   MOCK_METHOD0(OnCommandProcessed, void());
 
  protected:
-  virtual void SetUp() { api_mock_.reset(new AsyncAPIMock(false)); }
-  virtual void TearDown() {}
-
   void AddDoCommandsExpect(error::Error _return,
                            int num_entries,
                            int num_processed) {
@@ -49,7 +46,8 @@
   void MakeService(unsigned int entry_count) {
     transfer_buffer_manager_ = base::MakeUnique<TransferBufferManager>(nullptr);
     command_buffer_service_ = base::MakeUnique<CommandBufferService>(
-        this, transfer_buffer_manager_.get(), api_mock());
+        this, transfer_buffer_manager_.get());
+    api_mock_.reset(new AsyncAPIMock(false, command_buffer_service_.get()));
     SetNewGetBuffer(entry_count * sizeof(CommandBufferEntry));
   }
 
@@ -65,7 +63,7 @@
   int32_t GetPut() { return command_buffer_service_->put_offset(); }
 
   error::Error SetPutAndProcessAllCommands(int32_t put) {
-    command_buffer_service_->Flush(put);
+    command_buffer_service_->Flush(put, api_mock());
     EXPECT_EQ(put, GetPut());
     return command_buffer_service_->GetState().error;
   }
@@ -98,9 +96,9 @@
   MOCK_METHOD0(OnParseError, void());
 
  private:
-  std::unique_ptr<AsyncAPIMock> api_mock_;
   std::unique_ptr<TransferBufferManager> transfer_buffer_manager_;
   std::unique_ptr<CommandBufferService> command_buffer_service_;
+  std::unique_ptr<AsyncAPIMock> api_mock_;
   scoped_refptr<Buffer> buffer_;
   Sequence sequence_;
 };
@@ -306,7 +304,7 @@
   EXPECT_EQ(2, GetPut());
 
   EXPECT_CALL(*this, OnParseError()).Times(1);
-  command_buffer_service()->Flush(kNumEntries + 1);
+  command_buffer_service()->Flush(kNumEntries + 1, api_mock());
   CommandBuffer::State state1 = command_buffer_service()->GetState();
   EXPECT_EQ(2, GetPut());
   EXPECT_EQ(error::kOutOfBounds, state1.error);
@@ -317,7 +315,7 @@
   EXPECT_EQ(2, GetPut());
 
   EXPECT_CALL(*this, OnParseError()).Times(1);
-  command_buffer_service()->Flush(-1);
+  command_buffer_service()->Flush(-1, api_mock());
   CommandBuffer::State state2 = command_buffer_service()->GetState();
   EXPECT_EQ(2, GetPut());
   EXPECT_EQ(error::kOutOfBounds, state2.error);
@@ -356,7 +354,7 @@
 
   // Trying to execute commands should fail however.
   EXPECT_CALL(*this, OnParseError()).Times(1);
-  command_buffer_service()->Flush(2);
+  command_buffer_service()->Flush(2, api_mock());
   CommandBuffer::State state4 = command_buffer_service()->GetState();
   EXPECT_EQ(0, GetPut());
   EXPECT_EQ(error::kOutOfBounds, state4.error);
@@ -378,7 +376,7 @@
 
   // Trying to execute commands should fail however.
   EXPECT_CALL(*this, OnParseError()).Times(1);
-  command_buffer_service()->Flush(2);
+  command_buffer_service()->Flush(2, api_mock());
   CommandBuffer::State state3 = command_buffer_service()->GetState();
   EXPECT_EQ(0, GetPut());
   EXPECT_EQ(error::kOutOfBounds, state3.error);
diff --git a/gpu/command_buffer/service/common_decoder.cc b/gpu/command_buffer/service/common_decoder.cc
index ae6920f..e6a55d6 100644
--- a/gpu/command_buffer/service/common_decoder.cc
+++ b/gpu/command_buffer/service/common_decoder.cc
@@ -126,16 +126,17 @@
   return true;
 }
 
-CommonDecoder::CommonDecoder()
-    : command_buffer_service_(nullptr),
-      max_bucket_size_(kDefaultMaxBucketSize) {}
+CommonDecoder::CommonDecoder(CommandBufferServiceBase* command_buffer_service)
+    : command_buffer_service_(command_buffer_service),
+      max_bucket_size_(kDefaultMaxBucketSize) {
+  DCHECK(command_buffer_service_);
+}
 
 CommonDecoder::~CommonDecoder() {}
 
 void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
                                             unsigned int data_offset,
                                             unsigned int data_size) {
-  CHECK(command_buffer_service_);
   scoped_refptr<gpu::Buffer> buffer =
       command_buffer_service_->GetTransferBuffer(shm_id);
   if (!buffer.get())
@@ -147,7 +148,6 @@
                                        unsigned int data_offset,
                                        unsigned int minimum_size,
                                        unsigned int* data_size) {
-  CHECK(command_buffer_service_);
   scoped_refptr<gpu::Buffer> buffer =
       command_buffer_service_->GetTransferBuffer(shm_id);
   if (!buffer.get() || buffer->GetRemainingSize(data_offset) < minimum_size)
@@ -157,7 +157,6 @@
 
 unsigned int CommonDecoder::GetSharedMemorySize(unsigned int shm_id,
                                                 unsigned int offset) {
-  CHECK(command_buffer_service_);
   scoped_refptr<gpu::Buffer> buffer =
       command_buffer_service_->GetTransferBuffer(shm_id);
   if (!buffer.get())
diff --git a/gpu/command_buffer/service/common_decoder.h b/gpu/command_buffer/service/common_decoder.h
index ebf06327..d6122b2 100644
--- a/gpu/command_buffer/service/common_decoder.h
+++ b/gpu/command_buffer/service/common_decoder.h
@@ -109,15 +109,9 @@
     DISALLOW_COPY_AND_ASSIGN(Bucket);
   };
 
-  CommonDecoder();
+  explicit CommonDecoder(CommandBufferServiceBase* command_buffer_service);
   ~CommonDecoder();
 
-  // Sets the engine, to get shared memory buffers from, and to set the token
-  // to.
-  void set_command_buffer_service(
-      CommandBufferServiceBase* command_buffer_service) {
-    command_buffer_service_ = command_buffer_service;
-  }
   CommandBufferServiceBase* command_buffer_service() const {
     return command_buffer_service_;
   }
diff --git a/gpu/command_buffer/service/common_decoder_unittest.cc b/gpu/command_buffer/service/common_decoder_unittest.cc
index dd79712..5368ae6 100644
--- a/gpu/command_buffer/service/common_decoder_unittest.cc
+++ b/gpu/command_buffer/service/common_decoder_unittest.cc
@@ -56,6 +56,8 @@
 
 class TestCommonDecoder : public CommonDecoder {
  public:
+  explicit TestCommonDecoder(CommandBufferServiceBase* command_buffer_service)
+      : CommonDecoder(command_buffer_service) {}
   error::Error DoCommand(unsigned int command,
                          unsigned int arg_count,
                          const volatile void* cmd_data) {
@@ -71,11 +73,11 @@
  protected:
   static const size_t kBufferSize = 1024;
   static const uint32_t kInvalidShmId = UINT32_MAX;
+  CommonDecoderTest() : decoder_(&command_buffer_service_) {}
 
   void SetUp() override {
     command_buffer_service_.CreateTransferBufferHelper(kBufferSize,
                                                        &valid_shm_id_);
-    decoder_.set_command_buffer_service(&command_buffer_service_);
   }
 
   void TearDown() override {}
diff --git a/gpu/command_buffer/service/context_group_unittest.cc b/gpu/command_buffer/service/context_group_unittest.cc
index 263a778..3ef61f90 100644
--- a/gpu/command_buffer/service/context_group_unittest.cc
+++ b/gpu/command_buffer/service/context_group_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
 #include "gpu/command_buffer/service/image_manager.h"
@@ -42,7 +43,7 @@
  protected:
   void SetUp() override {
     GpuServiceTest::SetUp();
-    decoder_.reset(new MockGLES2Decoder());
+    decoder_.reset(new MockGLES2Decoder(&command_buffer_service_));
     scoped_refptr<FeatureInfo> feature_info = new FeatureInfo;
     group_ = scoped_refptr<ContextGroup>(new ContextGroup(
         gpu_preferences_, nullptr /* mailbox_manager */,
@@ -56,6 +57,7 @@
   GpuPreferences gpu_preferences_;
   ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   scoped_refptr<ContextGroup> group_;
 };
@@ -111,7 +113,9 @@
 }
 
 TEST_F(ContextGroupTest, MultipleContexts) {
-  std::unique_ptr<MockGLES2Decoder> decoder2_(new MockGLES2Decoder());
+  FakeCommandBufferServiceBase command_buffer_service2;
+  std::unique_ptr<MockGLES2Decoder> decoder2_(
+      new MockGLES2Decoder(&command_buffer_service2));
   TestHelper::SetupContextGroupInitExpectations(
       gl_.get(), DisallowedFeatures(), "", "",
       CONTEXT_TYPE_OPENGLES2, kBindGeneratesResource);
diff --git a/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
index b415ab5..1ebaeda 100644
--- a/gpu/command_buffer/service/framebuffer_manager_unittest.cc
+++ b/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/error_state_mock.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
@@ -149,7 +150,7 @@
     TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(gl_.get(),
         extensions, "", gl_version, context_type_);
     feature_info_->InitializeForTesting(context_type_);
-    decoder_.reset(new MockGLES2Decoder());
+    decoder_.reset(new MockGLES2Decoder(&command_buffer_service_));
     manager_.CreateFramebuffer(kClient1Id, kService1Id);
     error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
     framebuffer_ = manager_.GetFramebuffer(kClient1Id);
@@ -164,6 +165,7 @@
   std::unique_ptr<TextureManager> texture_manager_;
   std::unique_ptr<RenderbufferManager> renderbuffer_manager_;
   std::unique_ptr<MockErrorState> error_state_;
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
 };
 
diff --git a/gpu/command_buffer/service/gl_context_virtual_unittest.cc b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
index fa6912e..cdac976 100644
--- a/gpu/command_buffer/service/gl_context_virtual_unittest.cc
+++ b/gpu/command_buffer/service/gl_context_virtual_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/command_buffer/service/gl_context_virtual.h"
 
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
 #include "ui/gl/gl_context_stub.h"
@@ -19,10 +20,12 @@
 
 class GLContextVirtualTest : public GpuServiceTest {
  public:
-  GLContextVirtualTest() : decoder_(new gles2::MockGLES2Decoder()) {}
+  GLContextVirtualTest()
+      : decoder_(new gles2::MockGLES2Decoder(&command_buffer_service_)) {}
   ~GLContextVirtualTest() override {}
 
  protected:
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
 };
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index cf5da742e48..9ee479b9 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -479,11 +479,11 @@
   return 0;
 }
 
-GLES2Decoder::GLES2Decoder()
-    : initialized_(false),
+GLES2Decoder::GLES2Decoder(CommandBufferServiceBase* command_buffer_service)
+    : CommonDecoder(command_buffer_service),
+      initialized_(false),
       debug_(false),
-      log_commands_(false) {
-}
+      log_commands_(false) {}
 
 GLES2Decoder::~GLES2Decoder() {
 }
@@ -500,7 +500,9 @@
 // cmd stuff to outside this class.
 class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
  public:
-  explicit GLES2DecoderImpl(ContextGroup* group);
+  GLES2DecoderImpl(GLES2DecoderClient* client,
+                   CommandBufferServiceBase* command_buffer_service,
+                   ContextGroup* group);
   ~GLES2DecoderImpl() override;
 
   error::Error DoCommands(unsigned int num_commands,
@@ -600,16 +602,6 @@
   const ContextState* GetContextState() override { return &state_; }
   scoped_refptr<ShaderTranslatorInterface> GetTranslator(GLenum type) override;
 
-  void SetShaderCacheCallback(const ShaderCacheCallback& callback) override;
-  void SetFenceSyncReleaseCallback(
-      const FenceSyncReleaseCallback& callback) override;
-  void SetWaitSyncTokenCallback(const WaitSyncTokenCallback& callback) override;
-
-  void SetDescheduleUntilFinishedCallback(
-      const NoParamCallback& callback) override;
-  void SetRescheduleAfterFinishedCallback(
-      const NoParamCallback& callback) override;
-
   void SetIgnoreCachedStateForTest(bool ignore) override;
   void SetForceShaderNameHashingForTest(bool force) override;
   uint32_t GetAndClearBackbufferClearBitsForTest() override;
@@ -2236,6 +2228,8 @@
 
   #undef GLES2_CMD_OP
 
+  GLES2DecoderClient* client_;
+
   // The GL context this decoder renders to on behalf of the client.
   scoped_refptr<gl::GLSurface> surface_;
   scoped_refptr<gl::GLContext> context_;
@@ -2342,13 +2336,6 @@
 
   std::unique_ptr<VertexArrayManager> vertex_array_manager_;
 
-  FenceSyncReleaseCallback fence_sync_release_callback_;
-  WaitSyncTokenCallback wait_sync_token_callback_;
-  NoParamCallback deschedule_until_finished_callback_;
-  NoParamCallback reschedule_after_finished_callback_;
-
-  ShaderCacheCallback shader_cache_callback_;
-
   // The format of the back buffer_
   GLenum back_buffer_color_format_;
   bool back_buffer_has_depth_;
@@ -3060,17 +3047,25 @@
   return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
 }
 
-GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) {
+GLES2Decoder* GLES2Decoder::Create(
+    GLES2DecoderClient* client,
+    CommandBufferServiceBase* command_buffer_service,
+    ContextGroup* group) {
   if (group->gpu_preferences().use_passthrough_cmd_decoder) {
-    return new GLES2DecoderPassthroughImpl(group);
+    return new GLES2DecoderPassthroughImpl(client, command_buffer_service,
+                                           group);
   }
-  return new GLES2DecoderImpl(group);
+  return new GLES2DecoderImpl(client, command_buffer_service, group);
 }
 
-GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
-    : GLES2Decoder(),
+GLES2DecoderImpl::GLES2DecoderImpl(
+    GLES2DecoderClient* client,
+    CommandBufferServiceBase* command_buffer_service,
+    ContextGroup* group)
+    : GLES2Decoder(command_buffer_service),
+      client_(client),
       group_(group),
-      logger_(&debug_marker_manager_),
+      logger_(&debug_marker_manager_, client_),
       state_(group_->feature_info(), this, &logger_),
       attrib_0_buffer_id_(0),
       attrib_0_buffer_matches_value_(true),
@@ -3126,6 +3121,7 @@
       texture_manager_service_id_generation_(0),
       force_shader_name_hashing_for_test(false),
       weak_ptr_factory_(this) {
+  DCHECK(client);
   DCHECK(group);
 }
 
@@ -4314,7 +4310,7 @@
 
 void GLES2DecoderImpl::ProcessFinishedAsyncTransfers() {
   ProcessPendingReadPixels(false);
-  if (command_buffer_service() && query_manager_.get())
+  if (query_manager_.get())
     query_manager_->ProcessPendingTransferQueries();
 }
 
@@ -4696,31 +4692,6 @@
   return state_.GetErrorState();
 }
 
-void GLES2DecoderImpl::SetShaderCacheCallback(
-    const ShaderCacheCallback& callback) {
-  shader_cache_callback_ = callback;
-}
-
-void GLES2DecoderImpl::SetFenceSyncReleaseCallback(
-    const FenceSyncReleaseCallback& callback) {
-  fence_sync_release_callback_ = callback;
-}
-
-void GLES2DecoderImpl::SetWaitSyncTokenCallback(
-    const WaitSyncTokenCallback& callback) {
-  wait_sync_token_callback_ = callback;
-}
-
-void GLES2DecoderImpl::SetDescheduleUntilFinishedCallback(
-    const NoParamCallback& callback) {
-  deschedule_until_finished_callback_ = callback;
-}
-
-void GLES2DecoderImpl::SetRescheduleAfterFinishedCallback(
-    const NoParamCallback& callback) {
-  reschedule_after_finished_callback_ = callback;
-}
-
 bool GLES2DecoderImpl::GetServiceTextureId(uint32_t client_texture_id,
                                            uint32_t* service_texture_id) {
   TextureRef* texture_ref = texture_manager()->GetTexture(client_texture_id);
@@ -8732,9 +8703,10 @@
 
   LogClientServiceForInfo(program, program_id, "glLinkProgram");
   if (program->Link(shader_manager(),
-                    workarounds().count_all_in_varyings_packing ?
-                        Program::kCountAll : Program::kCountOnlyStaticallyUsed,
-                    shader_cache_callback_)) {
+                    workarounds().count_all_in_varyings_packing
+                        ? Program::kCountAll
+                        : Program::kCountOnlyStaticallyUsed,
+                    client_)) {
     if (program == state_.current_program.get()) {
       if (workarounds().clear_uniforms_before_first_program_use)
         program_manager()->ClearUniforms(program);
@@ -16023,14 +15995,6 @@
 error::Error GLES2DecoderImpl::HandleDescheduleUntilFinishedCHROMIUM(
     uint32_t immediate_data_size,
     const volatile void* cmd_data) {
-  if (deschedule_until_finished_callback_.is_null() ||
-      reschedule_after_finished_callback_.is_null()) {
-    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
-                       "glDescheduleUntilFinishedCHROMIUM",
-                       "Not fully implemented.");
-    return error::kNoError;
-  }
-
   std::unique_ptr<gl::GLFence> fence(gl::GLFence::Create());
   deschedule_until_finished_fences_.push_back(std::move(fence));
 
@@ -16046,7 +16010,7 @@
 
   TRACE_EVENT_ASYNC_BEGIN0("cc", "GLES2DecoderImpl::DescheduleUntilFinished",
                            this);
-  deschedule_until_finished_callback_.Run();
+  client_->OnDescheduleUntilFinished();
   return error::kDeferLaterCommands;
 }
 
@@ -16058,8 +16022,7 @@
           cmd_data);
 
   const uint64_t release_count = c.release_count();
-  if (!fence_sync_release_callback_.is_null())
-    fence_sync_release_callback_.Run(release_count);
+  client_->OnFenceSyncRelease(release_count);
   // Exit inner command processing loop so that we check the scheduling state
   // and yield if necessary as we may have unblocked a higher priority context.
   ExitCommandProcessingEarly();
@@ -16087,14 +16050,11 @@
   const CommandBufferId command_buffer_id =
       CommandBufferId::FromUnsafeValue(c.command_buffer_id());
   const uint64_t release = c.release_count();
-  if (wait_sync_token_callback_.is_null())
-    return error::kNoError;
 
   gpu::SyncToken sync_token;
   sync_token.Set(namespace_id, 0, command_buffer_id, release);
-  return wait_sync_token_callback_.Run(sync_token)
-             ? error::kDeferCommandUntilLater
-             : error::kNoError;
+  return client_->OnWaitSyncToken(sync_token) ? error::kDeferCommandUntilLater
+                                              : error::kNoError;
 }
 
 error::Error GLES2DecoderImpl::HandleDiscardBackbufferCHROMIUM(
@@ -16179,7 +16139,7 @@
                          this);
   deschedule_until_finished_fences_.erase(
       deschedule_until_finished_fences_.begin());
-  reschedule_after_finished_callback_.Run();
+  client_->OnRescheduleAfterFinished();
 }
 
 bool GLES2DecoderImpl::HasMoreIdleWork() const {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 85b6acc5..8035e93a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -77,8 +77,39 @@
   bool oes_texture_half_float_linear = false;
 };
 
-typedef base::Callback<void(const std::string& key,
-                            const std::string& shader)> ShaderCacheCallback;
+class GPU_EXPORT GLES2DecoderClient {
+ public:
+  virtual ~GLES2DecoderClient() {}
+
+  // Prints a message (error/warning) to the console.
+  virtual void OnConsoleMessage(int32_t id, const std::string& message) = 0;
+
+  // Cache a newly linked shader.
+  virtual void CacheShader(const std::string& key,
+                           const std::string& shader) = 0;
+
+  // Called when the decoder releases a fence sync. Allows the client to
+  // reschedule waiting decoders.
+  virtual void OnFenceSyncRelease(uint64_t release) = 0;
+
+  // Called when the decoder needs to wait on a sync token. If the wait is valid
+  // (fence sync is not released yet), the client must unschedule the command
+  // buffer and return true. The client is responsible for rescheduling the
+  // command buffer when the fence is released.  If the wait is a noop (fence is
+  // already released) or invalid, the client must leave the command buffer
+  // scheduled, and return false.
+  virtual bool OnWaitSyncToken(const gpu::SyncToken&) = 0;
+
+  // Called when the decoder needs to be descheduled while waiting for a fence
+  // completion. The client is responsible for descheduling the command buffer
+  // before returning, and then calling PerformPollingWork periodically to test
+  // for the fence completion and possibly reschedule.
+  virtual void OnDescheduleUntilFinished() = 0;
+
+  // Called from PerformPollingWork when the decoder needs to be rescheduled
+  // because the fence completed.
+  virtual void OnRescheduleAfterFinished() = 0;
+};
 
 // This class implements the AsyncAPIInterface interface, decoding GLES2
 // commands and calling GL.
@@ -86,9 +117,6 @@
                                 NON_EXPORTED_BASE(public AsyncAPIInterface) {
  public:
   typedef error::Error Error;
-  typedef base::Callback<void(uint64_t release)> FenceSyncReleaseCallback;
-  typedef base::Callback<bool(const gpu::SyncToken&)> WaitSyncTokenCallback;
-  typedef base::Callback<void(void)> NoParamCallback;
 
   // The default stencil mask, which has all bits set.  This really should be a
   // GLuint, but we can't #include gl_bindings.h in this file without causing
@@ -96,7 +124,9 @@
   static const unsigned int kDefaultStencilMask;
 
   // Creates a decoder.
-  static GLES2Decoder* Create(ContextGroup* group);
+  static GLES2Decoder* Create(GLES2DecoderClient* client,
+                              CommandBufferServiceBase* command_buffer_service,
+                              ContextGroup* group);
 
   ~GLES2Decoder() override;
 
@@ -280,24 +310,6 @@
 
   virtual ErrorState* GetErrorState() = 0;
 
-  // A callback for messages from the decoder.
-  virtual void SetShaderCacheCallback(const ShaderCacheCallback& callback) = 0;
-
-  // Sets the callback for fence sync release and wait calls. The wait call
-  // returns false if the wait was a nop or invalid and the command buffer is
-  // still scheduled.
-  virtual void SetFenceSyncReleaseCallback(
-      const FenceSyncReleaseCallback& callback) = 0;
-  virtual void SetWaitSyncTokenCallback(
-      const WaitSyncTokenCallback& callback) = 0;
-
-  // Sets the callback for the DescheduleUntilFinished and
-  // RescheduleAfterFinished calls.
-  virtual void SetDescheduleUntilFinishedCallback(
-      const NoParamCallback& callback) = 0;
-  virtual void SetRescheduleAfterFinishedCallback(
-      const NoParamCallback& callback) = 0;
-
   virtual void WaitForReadPixels(base::Closure callback) = 0;
 
   // Returns true if the context was lost either by GL_ARB_robustness, forced
@@ -320,7 +332,7 @@
       unsigned int type) = 0;
 
  protected:
-  GLES2Decoder();
+  explicit GLES2Decoder(CommandBufferServiceBase* command_buffer_service);
 
   base::StringPiece GetLogPrefix() override;
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
index f447b2b..5df3d06 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
@@ -9,7 +9,9 @@
 namespace gpu {
 namespace gles2 {
 
-MockGLES2Decoder::MockGLES2Decoder() : GLES2Decoder(), weak_ptr_factory_(this) {
+MockGLES2Decoder::MockGLES2Decoder(
+    CommandBufferServiceBase* command_buffer_service)
+    : GLES2Decoder(command_buffer_service), weak_ptr_factory_(this) {
   ON_CALL(*this, MakeCurrent())
       .WillByDefault(testing::Return(true));
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index c2629a3..8ecfab8 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -36,7 +36,7 @@
 
 class MockGLES2Decoder : public GLES2Decoder {
  public:
-  MockGLES2Decoder();
+  explicit MockGLES2Decoder(CommandBufferServiceBase* command_buffer_service);
   virtual ~MockGLES2Decoder();
 
   base::WeakPtr<GLES2Decoder> AsWeakPtr() override;
@@ -139,16 +139,6 @@
   MOCK_METHOD0(GetErrorState, ErrorState *());
 
   MOCK_METHOD0(GetLogger, Logger*());
-  MOCK_METHOD1(SetShaderCacheCallback,
-               void(const ShaderCacheCallback& callback));
-  MOCK_METHOD1(SetFenceSyncReleaseCallback,
-               void(const FenceSyncReleaseCallback& callback));
-  MOCK_METHOD1(SetWaitSyncTokenCallback,
-               void(const WaitSyncTokenCallback& callback));
-  MOCK_METHOD1(SetDescheduleUntilFinishedCallback,
-               void(const NoParamCallback& callback));
-  MOCK_METHOD1(SetRescheduleAfterFinishedCallback,
-               void(const NoParamCallback& callback));
   MOCK_METHOD1(WaitForReadPixels,
                void(base::Closure callback));
   MOCK_CONST_METHOD0(WasContextLost, bool());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index d9adaf81..cd026186 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -70,16 +70,22 @@
   texture_object_map.clear();
 }
 
-GLES2DecoderPassthroughImpl::GLES2DecoderPassthroughImpl(ContextGroup* group)
-    : commands_to_process_(0),
+GLES2DecoderPassthroughImpl::GLES2DecoderPassthroughImpl(
+    GLES2DecoderClient* client,
+    CommandBufferServiceBase* command_buffer_service,
+    ContextGroup* group)
+    : GLES2Decoder(command_buffer_service),
+      client_(client),
+      commands_to_process_(0),
       debug_marker_manager_(),
-      logger_(&debug_marker_manager_),
+      logger_(&debug_marker_manager_, client_),
       surface_(),
       context_(),
       offscreen_(false),
       group_(group),
       feature_info_(new FeatureInfo),
       weak_ptr_factory_(this) {
+  DCHECK(client);
   DCHECK(group);
 }
 
@@ -434,22 +440,6 @@
   return 0;
 }
 
-void GLES2DecoderPassthroughImpl::SetFenceSyncReleaseCallback(
-    const FenceSyncReleaseCallback& callback) {
-  fence_sync_release_callback_ = callback;
-}
-
-void GLES2DecoderPassthroughImpl::SetWaitSyncTokenCallback(
-    const WaitSyncTokenCallback& callback) {
-  wait_sync_token_callback_ = callback;
-}
-
-void GLES2DecoderPassthroughImpl::SetDescheduleUntilFinishedCallback(
-    const NoParamCallback& callback) {}
-
-void GLES2DecoderPassthroughImpl::SetRescheduleAfterFinishedCallback(
-    const NoParamCallback& callback) {}
-
 gpu::gles2::QueryManager* GLES2DecoderPassthroughImpl::GetQueryManager() {
   return nullptr;
 }
@@ -542,9 +532,6 @@
   return nullptr;
 }
 
-void GLES2DecoderPassthroughImpl::SetShaderCacheCallback(
-    const ShaderCacheCallback& callback) {}
-
 void GLES2DecoderPassthroughImpl::WaitForReadPixels(base::Closure callback) {}
 
 bool GLES2DecoderPassthroughImpl::WasContextLost() const {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
index a73c57b..7b88a92 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.h
@@ -69,7 +69,9 @@
 
 class GLES2DecoderPassthroughImpl : public GLES2Decoder {
  public:
-  explicit GLES2DecoderPassthroughImpl(ContextGroup* group);
+  GLES2DecoderPassthroughImpl(GLES2DecoderClient* client,
+                              CommandBufferServiceBase* command_buffer_service,
+                              ContextGroup* group);
   ~GLES2DecoderPassthroughImpl() override;
 
   Error DoCommands(unsigned int num_commands,
@@ -145,16 +147,6 @@
   size_t GetSavedBackTextureCountForTest() override;
   size_t GetCreatedBackTextureCountForTest() override;
 
-  // Sets the callback for fence sync release and wait calls. The wait call
-  // returns true if the channel is still scheduled.
-  void SetFenceSyncReleaseCallback(
-      const FenceSyncReleaseCallback& callback) override;
-  void SetWaitSyncTokenCallback(const WaitSyncTokenCallback& callback) override;
-  void SetDescheduleUntilFinishedCallback(
-      const NoParamCallback& callback) override;
-  void SetRescheduleAfterFinishedCallback(
-      const NoParamCallback& callback) override;
-
   // Gets the QueryManager for this context.
   QueryManager* GetQueryManager() override;
 
@@ -227,8 +219,6 @@
 
   ErrorState* GetErrorState() override;
 
-  void SetShaderCacheCallback(const ShaderCacheCallback& callback) override;
-
   void WaitForReadPixels(base::Closure callback) override;
 
   // Returns true if the context was lost either by GL_ARB_robustness, forced
@@ -300,6 +290,8 @@
                                           GLenum internalformat,
                                           GLint image_id);
 
+  GLES2DecoderClient* client_;
+
   int commands_to_process_;
 
   DebugMarkerManager debug_marker_manager_;
@@ -335,10 +327,6 @@
   scoped_refptr<ContextGroup> group_;
   scoped_refptr<FeatureInfo> feature_info_;
 
-  // Callbacks
-  FenceSyncReleaseCallback fence_sync_release_callback_;
-  WaitSyncTokenCallback wait_sync_token_callback_;
-
   // Some objects may generate resources when they are bound even if they were
   // not generated yet: texture, buffer, renderbuffer, framebuffer, transform
   // feedback, vertex array
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 81db3f8a..36afca2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -3639,8 +3639,7 @@
 
 error::Error GLES2DecoderPassthroughImpl::DoInsertFenceSyncCHROMIUM(
     GLuint64 release_count) {
-  if (!fence_sync_release_callback_.is_null())
-    fence_sync_release_callback_.Run(release_count);
+  client_->OnFenceSyncRelease(release_count);
   return error::kNoError;
 }
 
@@ -3648,13 +3647,9 @@
     CommandBufferNamespace namespace_id,
     CommandBufferId command_buffer_id,
     GLuint64 release_count) {
-  if (wait_sync_token_callback_.is_null()) {
-    return error::kNoError;
-  }
   SyncToken sync_token(namespace_id, 0, command_buffer_id, release_count);
-  return wait_sync_token_callback_.Run(sync_token)
-             ? error::kDeferCommandUntilLater
-             : error::kNoError;
+  return client_->OnWaitSyncToken(sync_token) ? error::kDeferCommandUntilLater
+                                              : error::kNoError;
 }
 
 error::Error GLES2DecoderPassthroughImpl::DoDrawBuffersEXT(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 8114c7e..45811dc 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -1593,15 +1593,6 @@
     init.extensions += " GL_ARB_compatibility GL_ARB_sync";
     InitDecoder(init);
 
-    GetDecoder()->SetDescheduleUntilFinishedCallback(
-        base::Bind(&GLES2DecoderDescheduleUntilFinishedTest::
-                       DescheduleUntilFinishedCallback,
-                   base::Unretained(this)));
-    GetDecoder()->SetRescheduleAfterFinishedCallback(
-        base::Bind(&GLES2DecoderDescheduleUntilFinishedTest::
-                       RescheduleAfterFinishedCallback,
-                   base::Unretained(this)));
-
     EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0))
         .Times(2)
         .WillOnce(Return(sync_service_id_))
@@ -1617,10 +1608,10 @@
         .RetiresOnSaturation();
   }
 
-  void DescheduleUntilFinishedCallback() {
+  void OnDescheduleUntilFinished() override {
     deschedule_until_finished_callback_count_++;
   }
-  void RescheduleAfterFinishedCallback() {
+  void OnRescheduleAfterFinished() override {
     reschedule_after_finished_callback_count_++;
   }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
index 11a3b697..e5d4701 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -31,11 +31,6 @@
 namespace gpu {
 namespace gles2 {
 
-namespace {
-void ShaderCacheCb(const std::string& key, const std::string& shader) {
-}
-}  // namespace
-
 class GLES2DecoderTest2 : public GLES2DecoderTestBase {
  public:
   GLES2DecoderTest2() { }
@@ -639,8 +634,7 @@
   attach_cmd.Init(client_program_id_, kClientFragmentShaderId);
   EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
 
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
 };
 
 template <>
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 74be9a9..79d67d33 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -132,6 +132,17 @@
 
 GLES2DecoderTestBase::~GLES2DecoderTestBase() {}
 
+void GLES2DecoderTestBase::OnConsoleMessage(int32_t id,
+                                            const std::string& message) {}
+void GLES2DecoderTestBase::CacheShader(const std::string& key,
+                                       const std::string& shader) {}
+void GLES2DecoderTestBase::OnFenceSyncRelease(uint64_t release) {}
+bool GLES2DecoderTestBase::OnWaitSyncToken(const gpu::SyncToken&) {
+  return false;
+}
+void GLES2DecoderTestBase::OnDescheduleUntilFinished() {}
+void GLES2DecoderTestBase::OnRescheduleAfterFinished() {}
+
 void GLES2DecoderTestBase::SetUp() {
   InitState init;
   // Autogenerated tests do not overwrite version or extension string,
@@ -231,7 +242,8 @@
   // We initialize the ContextGroup with a MockGLES2Decoder so that
   // we can use the ContextGroup to figure out how the real GLES2Decoder
   // will initialize itself.
-  mock_decoder_.reset(new MockGLES2Decoder());
+  command_buffer_service_.reset(new FakeCommandBufferServiceBase());
+  mock_decoder_.reset(new MockGLES2Decoder(command_buffer_service_.get()));
 
   EXPECT_TRUE(group_->Initialize(mock_decoder_.get(), init.context_type,
                                  DisallowedFeatures()));
@@ -458,7 +470,6 @@
   }
 #endif
 
-  command_buffer_service_.reset(new FakeCommandBufferServiceBase());
   scoped_refptr<gpu::Buffer> buffer =
       command_buffer_service_->CreateTransferBufferHelper(kSharedBufferSize,
                                                           &shared_memory_id_);
@@ -476,7 +487,8 @@
       normalized_init.lose_context_when_out_of_memory;
   attribs.context_type = init.context_type;
 
-  decoder_.reset(GLES2Decoder::Create(group_.get()));
+  decoder_.reset(
+      GLES2Decoder::Create(this, command_buffer_service_.get(), group_.get()));
   decoder_->SetIgnoreCachedStateForTest(ignore_cached_state_for_test_);
   decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
   ASSERT_TRUE(decoder_->Initialize(surface_, context_, false,
@@ -488,7 +500,6 @@
         .WillOnce(Return(GL_NO_ERROR));
   }
   decoder_->MakeCurrent();
-  decoder_->set_command_buffer_service(command_buffer_service_.get());
   decoder_->BeginDecoding();
 
   EXPECT_CALL(*gl_, GenBuffersARB(_, _))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index edefc80b..d32f281 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -46,10 +46,18 @@
 
 class MemoryTracker;
 
-class GLES2DecoderTestBase : public ::testing::TestWithParam<bool> {
+class GLES2DecoderTestBase : public ::testing::TestWithParam<bool>,
+                             public GLES2DecoderClient {
  public:
   GLES2DecoderTestBase();
-  virtual ~GLES2DecoderTestBase();
+  ~GLES2DecoderTestBase() override;
+
+  void OnConsoleMessage(int32_t id, const std::string& message) override;
+  void CacheShader(const std::string& key, const std::string& shader) override;
+  void OnFenceSyncRelease(uint64_t release) override;
+  bool OnWaitSyncToken(const gpu::SyncToken&) override;
+  void OnDescheduleUntilFinished() override;
+  void OnRescheduleAfterFinished() override;
 
   // Template to call glGenXXX functions.
   template <typename T>
@@ -657,6 +665,7 @@
   std::unique_ptr<::testing::StrictMock<::gl::MockGLInterface>> gl_;
   scoped_refptr<gl::GLSurfaceStub> surface_;
   scoped_refptr<GLContextMock> context_;
+  std::unique_ptr<FakeCommandBufferServiceBase> command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> mock_decoder_;
   std::unique_ptr<GLES2Decoder> decoder_;
   MemoryTracker* memory_tracker_;
@@ -756,7 +765,6 @@
   void SetupInitStateManualExpectations(bool es3_capable);
   void SetupInitStateManualExpectationsForDoLineWidth(GLfloat width);
 
-  std::unique_ptr<FakeCommandBufferServiceBase> command_buffer_service_;
   GpuPreferences gpu_preferences_;
   gles2::ImageManager image_manager_;
   ServiceDiscardableManager discardable_manager_;
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 06e4856..ac2ab7b5 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -5,6 +5,7 @@
 #include <stdint.h>
 
 #include "base/bind.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
@@ -335,7 +336,8 @@
   void DoBasicTracerTest() {
     ExpectTracerOffsetQueryMocks();
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
@@ -353,7 +355,8 @@
 
     const GpuTracerSource source = static_cast<GpuTracerSource>(0);
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(false);
@@ -380,7 +383,8 @@
     const int64_t expect_end_time =
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
@@ -454,7 +458,8 @@
         offset_time;
     const bool valid_timer = gpu_timing_client_->IsAvailable();
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     GPUTracerTester tracer(&decoder);
     tracer.SetOutputter(outputter_ref_);
@@ -532,7 +537,8 @@
     const int64_t expect_end_time =
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     GPUTracerTester tracer(&decoder);
     tracer.SetTracingEnabled(true);
@@ -594,7 +600,8 @@
     const int64_t expect_end_time =
         (end_timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_time;
 
-    MockGLES2Decoder decoder;
+    FakeCommandBufferServiceBase command_buffer_service;
+    MockGLES2Decoder decoder(&command_buffer_service);
     EXPECT_CALL(decoder, GetGLContext()).WillOnce(Return(GetGLContext()));
     EXPECT_CALL(decoder, MakeCurrent()).WillRepeatedly(Return(true));
     GPUTracerTester tracer(&decoder);
@@ -733,7 +740,7 @@
   void SetUp() override {
     g_fakeCPUTime = 0;
     GpuServiceTest::SetUpWithGLVersion("3.2", "");
-    decoder_.reset(new MockGLES2Decoder());
+    decoder_.reset(new MockGLES2Decoder(&command_buffer_service_));
     EXPECT_CALL(*decoder_, GetGLContext())
         .Times(AtMost(1))
         .WillRepeatedly(Return(GetGLContext()));
@@ -745,6 +752,7 @@
     decoder_ = nullptr;
     GpuServiceTest::TearDown();
   }
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   std::unique_ptr<GPUTracerTester> tracer_tester_;
 };
diff --git a/gpu/command_buffer/service/logger.cc b/gpu/command_buffer/service/logger.cc
index d8311f1..61b2f0d 100644
--- a/gpu/command_buffer/service/logger.cc
+++ b/gpu/command_buffer/service/logger.cc
@@ -8,13 +8,16 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
 
 namespace gpu {
 namespace gles2 {
 
-Logger::Logger(const DebugMarkerManager* debug_marker_manager)
+Logger::Logger(const DebugMarkerManager* debug_marker_manager,
+               GLES2DecoderClient* client)
     : debug_marker_manager_(debug_marker_manager),
+      client_(client),
       log_message_count_(0),
       log_synthesized_gl_errors_(true) {
   Logger* this_temp = this;
@@ -37,9 +40,7 @@
       ::logging::LogMessage(
           filename, line, ::logging::LOG_ERROR).stream() << prefixed_msg;
     }
-    if (!msg_callback_.is_null()) {
-      msg_callback_.Run(0, prefixed_msg);
-    }
+    client_->OnConsoleMessage(0, prefixed_msg);
   } else {
     if (log_message_count_ == kMaxLogMessages) {
       ++log_message_count_;
@@ -55,10 +56,6 @@
   return prefix.empty() ? this_in_hex_ : prefix;
 }
 
-void Logger::SetMsgCallback(const MsgCallback& callback) {
-  msg_callback_ = callback;
-}
-
 }  // namespace gles2
 }  // namespace gpu
 
diff --git a/gpu/command_buffer/service/logger.h b/gpu/command_buffer/service/logger.h
index a1b0a93e6..bb90b72 100644
--- a/gpu/command_buffer/service/logger.h
+++ b/gpu/command_buffer/service/logger.h
@@ -18,15 +18,15 @@
 namespace gpu {
 namespace gles2 {
 
-typedef base::Callback<void(int32_t id, const std::string& msg)> MsgCallback;
-
 class DebugMarkerManager;
+class GLES2DecoderClient;
 
 class GPU_EXPORT Logger {
  public:
   static const int kMaxLogMessages = 256;
 
-  explicit Logger(const DebugMarkerManager* debug_marker_manager);
+  Logger(const DebugMarkerManager* debug_marker_manager,
+         GLES2DecoderClient* client);
   ~Logger();
 
   void LogMessage(const char* filename, int line, const std::string& msg);
@@ -40,17 +40,15 @@
     log_synthesized_gl_errors_ = enabled;
   }
 
-  void SetMsgCallback(const MsgCallback& callback);
-
  private:
   // Uses the current marker to add information to logs.
   const DebugMarkerManager* debug_marker_manager_;
+  GLES2DecoderClient* client_;
   std::string this_in_hex_;
 
   int log_message_count_;
   bool log_synthesized_gl_errors_;
 
-  MsgCallback msg_callback_;
   DISALLOW_COPY_AND_ASSIGN(Logger);
 };
 
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 3b4fe79..93a0b221 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -190,7 +190,7 @@
   (*map)[proto.mapped_name()] = interface_block;
 }
 
-void RunShaderCallback(const ShaderCacheCallback& callback,
+void RunShaderCallback(GLES2DecoderClient* client,
                        GpuProgramProto* proto,
                        std::string sha_string) {
   std::string shader;
@@ -198,7 +198,7 @@
 
   std::string key;
   base::Base64Encode(sha_string, &key);
-  callback.Run(key, shader);
+  client->CacheShader(key, shader);
 }
 
 bool ProgramBinaryExtensionsAvailable() {
@@ -236,7 +236,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    const ShaderCacheCallback& shader_callback) {
+    GLES2DecoderClient* client) {
   if (!ProgramBinaryExtensionsAvailable()) {
     // Early exit if this context can't support program binaries
     return PROGRAM_LOAD_FAILURE;
@@ -289,7 +289,7 @@
   shader_b->set_output_variable_list(value->output_variable_list_1());
   shader_b->set_interface_block_map(value->interface_block_map_1());
 
-  if (!shader_callback.is_null() && !disable_gpu_shader_disk_cache_) {
+  if (!disable_gpu_shader_disk_cache_) {
     std::unique_ptr<GpuProgramProto> proto(
         GpuProgramProto::default_instance().New());
     proto->set_sha(sha, kHashLength);
@@ -298,7 +298,7 @@
 
     FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
     FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
-    RunShaderCallback(shader_callback, proto.get(), sha_string);
+    RunShaderCallback(client, proto.get(), sha_string);
   }
 
   return PROGRAM_LOAD_SUCCESS;
@@ -311,7 +311,7 @@
     const LocationMap* bind_attrib_location_map,
     const std::vector<std::string>& transform_feedback_varyings,
     GLenum transform_feedback_buffer_mode,
-    const ShaderCacheCallback& shader_callback) {
+    GLES2DecoderClient* client) {
   if (!ProgramBinaryExtensionsAvailable()) {
     // Early exit if this context can't support program binaries
     return;
@@ -366,7 +366,7 @@
     store_.Erase(store_.rbegin());
   }
 
-  if (!shader_callback.is_null() && !disable_gpu_shader_disk_cache_) {
+  if (!disable_gpu_shader_disk_cache_) {
     std::unique_ptr<GpuProgramProto> proto(
         GpuProgramProto::default_instance().New());
     proto->set_sha(sha, kHashLength);
@@ -375,7 +375,7 @@
 
     FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
     FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
-    RunShaderCallback(shader_callback, proto.get(), sha_string);
+    RunShaderCallback(client, proto.get(), sha_string);
   }
 
   store_.Put(
diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h
index 4662e91..5cef31f 100644
--- a/gpu/command_buffer/service/memory_program_cache.h
+++ b/gpu/command_buffer/service/memory_program_cache.h
@@ -40,7 +40,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& shader_callback) override;
+      GLES2DecoderClient* client) override;
   void SaveLinkedProgram(
       GLuint program,
       const Shader* shader_a,
@@ -48,7 +48,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& shader_callback) override;
+      GLES2DecoderClient* client) override;
 
   void LoadProgram(const std::string& program) override;
 
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 6cad7e3..62442c9 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -67,7 +67,8 @@
   const char* binary_;
 };
 
-class MemoryProgramCacheTest : public GpuServiceTest {
+class MemoryProgramCacheTest : public GpuServiceTest,
+                               public GLES2DecoderClient {
  public:
   static const size_t kCacheSizeBytes = 1024;
   static const bool kDisableGpuDiskCache = false;
@@ -88,10 +89,15 @@
         shader_cache_count_(0) {}
   ~MemoryProgramCacheTest() override { shader_manager_.Destroy(false); }
 
-  void ShaderCacheCb(const std::string& key, const std::string& shader) {
+  void OnConsoleMessage(int32_t id, const std::string& message) override {}
+  void CacheShader(const std::string& key, const std::string& shader) override {
     shader_cache_count_++;
     shader_cache_shader_ = shader;
   }
+  void OnFenceSyncRelease(uint64_t release) override {}
+  bool OnWaitSyncToken(const gpu::SyncToken&) override { return false; }
+  void OnDescheduleUntilFinished() override {}
+  void OnRescheduleAfterFinished() override {}
 
   int32_t shader_cache_count() { return shader_cache_count_; }
   const std::string& shader_cache_shader() { return shader_cache_shader_; }
@@ -210,10 +216,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
       vertex_shader_->last_compiled_signature(),
@@ -233,10 +237,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
       vertex_shader_->last_compiled_signature(),
@@ -264,10 +266,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
   EXPECT_EQ(1, shader_cache_count());
 
   AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
@@ -291,15 +291,10 @@
   fragment_shader_->set_output_variable_list(OutputVariableList());
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_SUCCESS,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 
   // apparently the hash_map implementation on android doesn't have the
   // equality operator
@@ -328,10 +323,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
   EXPECT_EQ(1, shader_cache_count());
 
   AttributeMap vertex_attrib_map = vertex_shader_->attrib_map();
@@ -359,15 +352,10 @@
   cache_->Clear();
   cache_->LoadProgram(shader_cache_shader());
 
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_SUCCESS,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 
   // apparently the hash_map implementation on android doesn't have the
   // equality operator
@@ -396,21 +384,14 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   SetExpectationsForLoadLinkedProgramFailure(kProgramId, &emulator);
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 }
 
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) {
@@ -424,37 +405,25 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   const std::string vertex_orig_source = vertex_shader_->last_compiled_source();
   vertex_shader_->set_source("different!");
   TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true);
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 
   vertex_shader_->set_source(vertex_orig_source);
   TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true);
   fragment_shader_->set_source("different!");
   TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true);
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 }
 
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) {
@@ -470,34 +439,18 @@
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   ProgramCache::LocationMap binding_map;
   binding_map["test"] = 512;
-  cache_->SaveLinkedProgram(kProgramId,
-                            vertex_shader_,
-                            fragment_shader_,
-                            &binding_map,
-                            varyings_,
-                            GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                            &binding_map, varyings_, GL_NONE, this);
 
   binding_map["different!"] = 59;
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      &binding_map,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                &binding_map, varyings_, GL_NONE, this));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 }
 
 TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentTransformFeedbackVaryings) {
@@ -512,35 +465,19 @@
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
   varyings_.push_back("test");
-  cache_->SaveLinkedProgram(kProgramId,
-                            vertex_shader_,
-                            fragment_shader_,
-                            NULL,
-                            varyings_,
-                            GL_INTERLEAVED_ATTRIBS,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_INTERLEAVED_ATTRIBS, this);
 
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_SEPARATE_ATTRIBS,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_SEPARATE_ATTRIBS, this));
 
   varyings_.push_back("different!");
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_INTERLEAVED_ATTRIBS,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_INTERLEAVED_ATTRIBS, this));
 }
 
 TEST_F(MemoryProgramCacheTest, LoadFailIfTransformFeedbackCachingDisabled) {
@@ -558,23 +495,12 @@
   cache_.reset(new MemoryProgramCache(kCacheSizeBytes, kDisableGpuDiskCache,
                                       true, &activity_flags_));
   varyings_.push_back("test");
-  cache_->SaveLinkedProgram(kProgramId,
-                            vertex_shader_,
-                            fragment_shader_,
-                            NULL,
-                            varyings_,
-                            GL_INTERLEAVED_ATTRIBS,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_INTERLEAVED_ATTRIBS,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_INTERLEAVED_ATTRIBS, this);
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_FAILURE,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_INTERLEAVED_ATTRIBS, this));
 }
 
 TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) {
@@ -589,10 +515,8 @@
 
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   const int kEvictingProgramId = 11;
   const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1;
@@ -612,14 +536,8 @@
                                   bigTestBinary.get());
 
   SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2);
-  cache_->SaveLinkedProgram(kEvictingProgramId,
-                            vertex_shader_,
-                            fragment_shader_,
-                            NULL,
-                            varyings_,
-                            GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kEvictingProgramId, vertex_shader_,
+                            fragment_shader_, NULL, varyings_, GL_NONE, this);
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
       vertex_shader_->last_compiled_signature(),
@@ -643,10 +561,8 @@
 
   vertex_shader_->set_source("different!");
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
       vertex_shader_->last_compiled_signature(),
@@ -665,10 +581,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
       vertex_shader_->last_compiled_signature(),
@@ -678,15 +592,10 @@
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
 
   fragment_shader_->set_source("different!");
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_SUCCESS,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 }
 
 TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) {
@@ -700,11 +609,8 @@
   ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
 
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
-
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   char test_binary2[kBinaryLength];
   for (int i = 0; i < kBinaryLength; ++i) {
@@ -712,21 +618,14 @@
   }
   ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2);
   SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2);
-  cache_->SaveLinkedProgram(kProgramId, vertex_shader_,
-                            fragment_shader_, NULL, varyings_, GL_NONE,
-                            base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                                       base::Unretained(this)));
+  cache_->SaveLinkedProgram(kProgramId, vertex_shader_, fragment_shader_, NULL,
+                            varyings_, GL_NONE, this);
 
   SetExpectationsForLoadLinkedProgram(kProgramId, &emulator2);
-  EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
-      kProgramId,
-      vertex_shader_,
-      fragment_shader_,
-      NULL,
-      varyings_,
-      GL_NONE,
-      base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
-                 base::Unretained(this))));
+  EXPECT_EQ(
+      ProgramCache::PROGRAM_LOAD_SUCCESS,
+      cache_->LoadLinkedProgram(kProgramId, vertex_shader_, fragment_shader_,
+                                NULL, varyings_, GL_NONE, this));
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/mocks.cc b/gpu/command_buffer/service/mocks.cc
index 52b0ea1..e8d115383e 100644
--- a/gpu/command_buffer/service/mocks.cc
+++ b/gpu/command_buffer/service/mocks.cc
@@ -12,7 +12,9 @@
 
 namespace gpu {
 
-AsyncAPIMock::AsyncAPIMock(bool default_do_commands) {
+AsyncAPIMock::AsyncAPIMock(bool default_do_commands,
+                           CommandBufferServiceBase* command_buffer_service)
+    : command_buffer_service_(command_buffer_service) {
   testing::DefaultValue<error::Error>::Set(
       error::kNoError);
 
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h
index 58d32fe..fb06839 100644
--- a/gpu/command_buffer/service/mocks.h
+++ b/gpu/command_buffer/service/mocks.h
@@ -30,7 +30,8 @@
 // Mocks an AsyncAPIInterface, using GMock.
 class AsyncAPIMock : public AsyncAPIInterface {
  public:
-  explicit AsyncAPIMock(bool default_do_commands);
+  explicit AsyncAPIMock(bool default_do_commands,
+                        CommandBufferServiceBase* command_buffer_service);
   virtual ~AsyncAPIMock();
 
   error::Error FakeDoCommands(unsigned int num_commands,
@@ -76,12 +77,6 @@
 
   base::StringPiece GetLogPrefix() override { return "None"; }
 
-  // Sets the engine, to forward SetToken commands to it.
-  void set_command_buffer_service(
-      CommandBufferServiceBase* command_buffer_service) {
-    command_buffer_service_ = command_buffer_service;
-  }
-
   // Forwards the SetToken commands to the engine.
   void SetToken(unsigned int command,
                 unsigned int arg_count,
@@ -125,23 +120,24 @@
   MockProgramCache();
   virtual ~MockProgramCache();
 
-  MOCK_METHOD7(LoadLinkedProgram, ProgramLoadResult(
-      GLuint program,
-      Shader* shader_a,
-      Shader* shader_b,
-      const LocationMap* bind_attrib_location_map,
-      const std::vector<std::string>& transform_feedback_varyings,
-      GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& callback));
+  MOCK_METHOD7(LoadLinkedProgram,
+               ProgramLoadResult(
+                   GLuint program,
+                   Shader* shader_a,
+                   Shader* shader_b,
+                   const LocationMap* bind_attrib_location_map,
+                   const std::vector<std::string>& transform_feedback_varyings,
+                   GLenum transform_feedback_buffer_mode,
+                   GLES2DecoderClient* client));
 
-  MOCK_METHOD7(SaveLinkedProgram, void(
-      GLuint program,
-      const Shader* shader_a,
-      const Shader* shader_b,
-      const LocationMap* bind_attrib_location_map,
-      const std::vector<std::string>& transform_feedback_varyings,
-      GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& callback));
+  MOCK_METHOD7(SaveLinkedProgram,
+               void(GLuint program,
+                    const Shader* shader_a,
+                    const Shader* shader_b,
+                    const LocationMap* bind_attrib_location_map,
+                    const std::vector<std::string>& transform_feedback_varyings,
+                    GLenum transform_feedback_buffer_mode,
+                    GLES2DecoderClient* client));
   MOCK_METHOD1(LoadProgram, void(const std::string&));
 
  private:
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index 661bd71..11fa42b 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/sha1.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/program_manager.h"
 #include "gpu/command_buffer/service/shader_manager.h"
 
 namespace gpu {
@@ -58,7 +58,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& shader_callback) = 0;
+      GLES2DecoderClient* client) = 0;
 
   // Saves the program into the cache.  If successful, the implementation should
   // call LinkedProgramCacheSuccess.
@@ -69,7 +69,7 @@
       const LocationMap* bind_attrib_location_map,
       const std::vector<std::string>& transform_feedback_varyings,
       GLenum transform_feedback_buffer_mode,
-      const ShaderCacheCallback& shader_callback) = 0;
+      GLES2DecoderClient* client) = 0;
 
   virtual void LoadProgram(const std::string& program) = 0;
 
diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc
index 6cb32bc9..6a561298 100644
--- a/gpu/command_buffer/service/program_cache_unittest.cc
+++ b/gpu/command_buffer/service/program_cache_unittest.cc
@@ -23,7 +23,7 @@
       const LocationMap* /* bind_attrib_location_map */,
       const std::vector<std::string>& /* transform_feedback_varyings */,
       GLenum /* transform_feedback_buffer_mode */,
-      const ShaderCacheCallback& /* callback */) override {
+      GLES2DecoderClient* /* client */) override {
     return PROGRAM_LOAD_SUCCESS;
   }
   void SaveLinkedProgram(
@@ -33,7 +33,7 @@
       const LocationMap* /* bind_attrib_location_map */,
       const std::vector<std::string>& /* transform_feedback_varyings */,
       GLenum /* transform_feedback_buffer_mode */,
-      const ShaderCacheCallback& /* callback */) override {}
+      GLES2DecoderClient* /* client */) override {}
 
   void LoadProgram(const std::string& /* program */) override {}
 
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index ff78aa9..0811296 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -1271,7 +1271,7 @@
 
 bool Program::Link(ShaderManager* manager,
                    Program::VaryingsPackingOption varyings_packing_option,
-                   const ShaderCacheCallback& shader_callback) {
+                   GLES2DecoderClient* client) {
   ClearLinkStatus();
 
   if (!AttachedShadersExist()) {
@@ -1296,14 +1296,10 @@
     UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.CacheHit", cache_hit);
 
     if (cache_hit) {
-      ProgramCache::ProgramLoadResult success =
-          cache->LoadLinkedProgram(service_id(),
-                                   attached_shaders_[0].get(),
-                                   attached_shaders_[1].get(),
-                                   &bind_attrib_location_map_,
-                                   transform_feedback_varyings_,
-                                   transform_feedback_buffer_mode_,
-                                   shader_callback);
+      ProgramCache::ProgramLoadResult success = cache->LoadLinkedProgram(
+          service_id(), attached_shaders_[0].get(), attached_shaders_[1].get(),
+          &bind_attrib_location_map_, transform_feedback_varyings_,
+          transform_feedback_buffer_mode_, client);
       link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
       UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
     }
@@ -1401,13 +1397,11 @@
         shader->RefreshTranslatedShaderSource();
       }
       if (cache) {
-        cache->SaveLinkedProgram(service_id(),
-                                 attached_shaders_[0].get(),
-                                 attached_shaders_[1].get(),
-                                 &bind_attrib_location_map_,
-                                 effective_transform_feedback_varyings_,
-                                 effective_transform_feedback_buffer_mode_,
-                                 shader_callback);
+        cache->SaveLinkedProgram(
+            service_id(), attached_shaders_[0].get(),
+            attached_shaders_[1].get(), &bind_attrib_location_map_,
+            effective_transform_feedback_varyings_,
+            effective_transform_feedback_buffer_mode_, client);
       }
       UMA_HISTOGRAM_CUSTOM_COUNTS(
           "GPU.ProgramCache.BinaryCacheMissTime",
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 3126c57..a7913bb 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -18,7 +18,6 @@
 #include "base/memory/ref_counted.h"
 #include "gpu/command_buffer/service/common_decoder.h"
 #include "gpu/command_buffer/service/gl_utils.h"
-#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/shader_manager.h"
 #include "gpu/gpu_export.h"
 
@@ -29,6 +28,7 @@
 namespace gles2 {
 
 class FeatureInfo;
+class GLES2DecoderClient;
 class ProgramCache;
 class ProgramManager;
 class ProgressReporter;
@@ -323,7 +323,7 @@
   // Performs glLinkProgram and related activities.
   bool Link(ShaderManager* manager,
             VaryingsPackingOption varyings_packing_option,
-            const ShaderCacheCallback& shader_callback);
+            GLES2DecoderClient* client);
 
   // Performs glValidateProgram and related activities.
   void Validate();
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 7d6cdacf..d67f216 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -47,8 +47,6 @@
 const uint32_t kMaxDualSourceDrawBuffers = 8;
 const uint32_t kMaxVertexAttribs = 8;
 
-void ShaderCacheCb(const std::string& key, const std::string& shader) {}
-
 uint32_t ComputeOffset(const void* start, const void* position) {
   return static_cast<const uint8_t*>(position) -
          static_cast<const uint8_t*>(start);
@@ -56,7 +54,8 @@
 
 }  // namespace anonymous
 
-class ProgramManagerTestBase : public GpuServiceTest {
+class ProgramManagerTestBase : public GpuServiceTest,
+                               public GLES2DecoderClient {
  protected:
   virtual void SetupProgramManager() {
     manager_.reset(new ProgramManager(
@@ -86,6 +85,14 @@
     GpuServiceTest::TearDown();
   }
 
+  void OnConsoleMessage(int32_t id, const std::string& message) override {}
+  void CacheShader(const std::string& key, const std::string& shader) override {
+  }
+  void OnFenceSyncRelease(uint64_t release) override {}
+  bool OnWaitSyncToken(const gpu::SyncToken&) override { return false; }
+  void OnDescheduleUntilFinished() override {}
+  void OnRescheduleAfterFinished() override {}
+
   std::unique_ptr<ProgramManager> manager_;
   GpuPreferences gpu_preferences_;
   scoped_refptr<FeatureInfo> feature_info_;
@@ -283,8 +290,7 @@
 
     program->AttachShader(&shader_manager_, vertex_shader);
     program->AttachShader(&shader_manager_, fragment_shader);
-    program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                  base::Bind(&ShaderCacheCb));
+    program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
     return program;
   }
 
@@ -312,8 +318,7 @@
       SetupShaderExpectations(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
                               service_id);
     }
-    program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                  base::Bind(&ShaderCacheCb));
+    program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
     GLint link_status;
     program->GetProgramiv(GL_LINK_STATUS, &link_status);
     return (static_cast<bool>(link_status) == expected_link_status);
@@ -762,8 +767,7 @@
   ASSERT_TRUE(program != NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
   GLint value = 0;
   program->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &value);
   EXPECT_EQ(3, value);
@@ -827,8 +831,7 @@
   ASSERT_TRUE(program != NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
 
   // Check that we get the correct locations.
   EXPECT_EQ(kUniform2FakeLocation,
@@ -922,8 +925,7 @@
   ASSERT_TRUE(program!= NULL);
   EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
   EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
   // Check that we got the good type, not the bad.
   // Check Attribs
   for (unsigned index = 0; index < kNumAttribs; ++index) {
@@ -1975,8 +1977,7 @@
     const size_t kNumUniforms = arraysize(kUniforms);
     SetupShaderExpectations(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
                             kServiceProgramId);
-    program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                  base::Bind(&ShaderCacheCb));
+    program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
     SetupExpectationsForClearingUniforms(kUniforms, kNumUniforms);
     manager_->ClearUniforms(program);
   }
@@ -2041,8 +2042,7 @@
   const size_t kNumUniforms = arraysize(kUniforms);
   SetupShaderExpectations(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
                           kServiceProgramId);
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
 
   EXPECT_EQ(kUniform1DesiredLocation,
             program->GetUniformFakeLocation(kUniform1Name));
@@ -2256,8 +2256,7 @@
   SetShadersCompiled();
   SetExpectationsForProgramLink();
   SetExpectationsForProgramCached();
-  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                             base::Bind(&ShaderCacheCb)));
+  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed, this));
 }
 
 TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) {
@@ -2270,8 +2269,7 @@
   SetExpectationsForNotCachingProgram();
   SetExpectationsForProgramLoadSuccess();
 
-  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                             base::Bind(&ShaderCacheCb)));
+  EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed, this));
 }
 
 class ProgramManagerWithPathRenderingTest
@@ -2394,8 +2392,7 @@
       gl_.get(), feature_info_.get(), nullptr, 0, nullptr, 0,
       kFragmentInputExpectationInfos, arraysize(kFragmentInputExpectationInfos),
       nullptr, 0, kServiceProgramId);
-  program->Link(NULL, Program::kCountOnlyStaticallyUsed,
-                base::Bind(&ShaderCacheCb));
+  program->Link(NULL, Program::kCountOnlyStaticallyUsed, this);
   const Program::FragmentInputInfo* info1 =
       program->GetFragmentInputInfoByFakeLocation(
           kFragmentInput1DesiredLocation);
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 798885f3..e582bf1 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -69,8 +69,7 @@
     buffer = command_buffer_service_->CreateTransferBufferHelper(
         kSharedBufferSize, &shared_memory2_id_);
     memset(buffer->memory(), kInitialMemoryValue, kSharedBufferSize);
-    decoder_.reset(new MockGLES2Decoder());
-    decoder_->set_command_buffer_service(command_buffer_service_.get());
+    decoder_.reset(new MockGLES2Decoder(command_buffer_service_.get()));
     TestHelper::SetupFeatureInfoInitExpectations(
         gl_.get(), extension_expectations);
     EXPECT_CALL(*decoder_.get(), GetGLContext())
@@ -104,14 +103,12 @@
     EXPECT_TRUE(manager_->EndQuery(query, submit_count));
   }
 
+  std::unique_ptr<FakeCommandBufferServiceBase> command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   std::unique_ptr<QueryManager> manager_;
 
   int32_t shared_memory_id_ = 0;
   int32_t shared_memory2_id_ = 0;
-
- private:
-  std::unique_ptr<FakeCommandBufferServiceBase> command_buffer_service_;
 };
 
 class QueryManagerManualSetupTest : public QueryManagerTest {
diff --git a/gpu/command_buffer/service/scheduler.cc b/gpu/command_buffer/service/scheduler.cc
index e854cf1..ca080e4 100644
--- a/gpu/command_buffer/service/scheduler.cc
+++ b/gpu/command_buffer/service/scheduler.cc
@@ -29,8 +29,6 @@
     return order_data_;
   }
 
-  const SchedulingState& scheduling_state() const { return scheduling_state_; }
-
   bool enabled() const { return enabled_; }
 
   bool scheduled() const { return running_state_ == SCHEDULED; }
@@ -41,17 +39,23 @@
   // by wait fences.
   bool IsRunnable() const;
 
+  // Returns true if this sequence's scheduling state changed and it needs to be
+  // reinserted into the scheduling queue.
   bool NeedsRescheduling() const;
 
-  void UpdateSchedulingState();
+  // Returns true if this sequence should yield to another sequence. Uses the
+  // cached scheduling state for comparison.
+  bool ShouldYieldTo(const Sequence* other) const;
 
-  // If this sequence runs before the other sequence.
-  bool RunsBefore(const Sequence* other) const;
-
+  // Enables or disables the sequence.
   void SetEnabled(bool enabled);
 
-  // Sets running state to SCHEDULED.
-  void SetScheduled();
+  // Sets running state to SCHEDULED. Returns scheduling state for this sequence
+  // used for inserting in the scheduling queue.
+  SchedulingState SetScheduled();
+
+  // Update cached scheduling priority while running.
+  void UpdateRunningPriority();
 
   // Returns the next order number and closure. Sets running state to RUNNING.
   uint32_t BeginTask(base::OnceClosure* closure);
@@ -105,8 +109,8 @@
 
   RunningState running_state_ = IDLE;
 
-  // Cached scheduling state used for comparison with other sequences using
-  // |RunsBefore|. Updated in |UpdateSchedulingState|.
+  // Cached scheduling state used for comparison with other sequences while
+  // running. Updated in |SetScheduled| and |UpdateRunningPriority|.
   SchedulingState scheduling_state_;
 
   const SequenceId sequence_id_;
@@ -159,6 +163,12 @@
   order_data_->Destroy();
 }
 
+SchedulingPriority Scheduler::Sequence::GetSchedulingPriority() const {
+  if (!release_fences_.empty())
+    return std::min(priority_, SchedulingPriority::kHigh);
+  return priority_;
+}
+
 bool Scheduler::Sequence::NeedsRescheduling() const {
   return running_state_ != IDLE &&
          scheduling_state_.priority != GetSchedulingPriority();
@@ -170,14 +180,10 @@
           wait_fences_.front().order_num > tasks_.front().order_num);
 }
 
-SchedulingPriority Scheduler::Sequence::GetSchedulingPriority() const {
-  if (!release_fences_.empty())
-    return std::min(priority_, SchedulingPriority::kHigh);
-  return priority_;
-}
-
-bool Scheduler::Sequence::RunsBefore(const Scheduler::Sequence* other) const {
-  return scheduling_state_.RunsBefore(other->scheduling_state());
+bool Scheduler::Sequence::ShouldYieldTo(const Sequence* other) const {
+  if (!running() || !other->scheduled())
+    return false;
+  return other->scheduling_state_.RunsBefore(scheduling_state_);
 }
 
 void Scheduler::Sequence::SetEnabled(bool enabled) {
@@ -187,24 +193,22 @@
   enabled_ = enabled;
 }
 
-void Scheduler::Sequence::SetScheduled() {
+Scheduler::SchedulingState Scheduler::Sequence::SetScheduled() {
+  DCHECK(IsRunnable());
   DCHECK_NE(running_state_, RUNNING);
-  running_state_ = SCHEDULED;
-  UpdateSchedulingState();
-}
 
-void Scheduler::Sequence::UpdateSchedulingState() {
+  running_state_ = SCHEDULED;
+
   scheduling_state_.sequence_id = sequence_id_;
   scheduling_state_.priority = GetSchedulingPriority();
+  scheduling_state_.order_num = tasks_.front().order_num;
 
-  uint32_t order_num = UINT32_MAX;  // IDLE
-  if (running_state_ == SCHEDULED) {
-    DCHECK(!tasks_.empty());
-    order_num = tasks_.front().order_num;
-  } else if (running_state_ == RUNNING) {
-    order_num = order_data_->current_order_num();
-  }
-  scheduling_state_.order_num = order_num;
+  return scheduling_state_;
+}
+
+void Scheduler::Sequence::UpdateRunningPriority() {
+  DCHECK_EQ(running_state_, RUNNING);
+  scheduling_state_.priority = GetSchedulingPriority();
 }
 
 void Scheduler::Sequence::ContinueTask(base::OnceClosure closure) {
@@ -223,23 +227,20 @@
 uint32_t Scheduler::Sequence::BeginTask(base::OnceClosure* closure) {
   DCHECK(closure);
   DCHECK(!tasks_.empty());
-
   DCHECK_EQ(running_state_, SCHEDULED);
+
   running_state_ = RUNNING;
 
   *closure = std::move(tasks_.front().closure);
   uint32_t order_num = tasks_.front().order_num;
   tasks_.pop_front();
 
-  UpdateSchedulingState();
-
   return order_num;
 }
 
 void Scheduler::Sequence::FinishTask() {
   DCHECK_EQ(running_state_, RUNNING);
   running_state_ = IDLE;
-  UpdateSchedulingState();
 }
 
 void Scheduler::Sequence::AddWaitFence(const SyncToken& sync_token,
@@ -365,24 +366,23 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   base::AutoLock auto_lock(lock_);
 
-  Sequence* sequence = GetSequence(sequence_id);
-  DCHECK(sequence);
-  DCHECK(sequence->running());
-
   if (should_yield_)
     return true;
 
   RebuildSchedulingQueue();
 
-  sequence->UpdateSchedulingState();
+  if (scheduling_queue_.empty())
+    return false;
 
-  if (!scheduling_queue_.empty()) {
-    Sequence* next_sequence =
-        GetSequence(scheduling_queue_.front().sequence_id);
-    DCHECK(next_sequence);
-    if (next_sequence->RunsBefore(sequence))
-      should_yield_ = true;
-  }
+  Sequence* running_sequence = GetSequence(sequence_id);
+  DCHECK(running_sequence);
+  DCHECK(running_sequence->running());
+
+  Sequence* next_sequence = GetSequence(scheduling_queue_.front().sequence_id);
+  DCHECK(next_sequence);
+  DCHECK(next_sequence->scheduled());
+
+  should_yield_ = running_sequence->ShouldYieldTo(next_sequence);
 
   return should_yield_;
 }
@@ -407,24 +407,27 @@
 void Scheduler::TryScheduleSequence(Sequence* sequence) {
   lock_.AssertAcquired();
 
-  if (sequence->running())
-    return;
-
-  if (sequence->NeedsRescheduling()) {
+  if (sequence->running()) {
+    // Update priority of running sequence because of sync token releases.
+    DCHECK(running_);
+    sequence->UpdateRunningPriority();
+  } else if (sequence->NeedsRescheduling()) {
+    // Rebuild scheduling queue if priority changed for a scheduled sequence.
+    DCHECK(running_);
     DCHECK(sequence->IsRunnable());
     rebuild_scheduling_queue_ = true;
   } else if (!sequence->scheduled() && sequence->IsRunnable()) {
-    sequence->SetScheduled();
-    scheduling_queue_.push_back(sequence->scheduling_state());
+    // Insert into scheduling queue if sequence isn't already scheduled.
+    SchedulingState scheduling_state = sequence->SetScheduled();
+    scheduling_queue_.push_back(scheduling_state);
     std::push_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
                    &SchedulingState::Comparator);
-  }
-
-  if (!running_) {
-    TRACE_EVENT_ASYNC_BEGIN0("gpu", "Scheduler::Running", this);
-    running_ = true;
-    task_runner_->PostTask(FROM_HERE, base::Bind(&Scheduler::RunNextTask,
-                                                 weak_factory_.GetWeakPtr()));
+    if (!running_) {
+      TRACE_EVENT_ASYNC_BEGIN0("gpu", "Scheduler::Running", this);
+      running_ = true;
+      task_runner_->PostTask(FROM_HERE, base::Bind(&Scheduler::RunNextTask,
+                                                   weak_factory_.GetWeakPtr()));
+    }
   }
 }
 
@@ -441,8 +444,8 @@
     Sequence* sequence = kv.second.get();
     if (!sequence->IsRunnable() || sequence->running())
       continue;
-    sequence->SetScheduled();
-    scheduling_queue_.push_back(sequence->scheduling_state());
+    SchedulingState scheduling_state = sequence->SetScheduled();
+    scheduling_queue_.push_back(scheduling_state);
   }
 
   std::make_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
@@ -493,8 +496,8 @@
   if (sequence) {
     sequence->FinishTask();
     if (sequence->IsRunnable()) {
-      sequence->SetScheduled();
-      scheduling_queue_.push_back(sequence->scheduling_state());
+      SchedulingState scheduling_state = sequence->SetScheduled();
+      scheduling_queue_.push_back(scheduling_state);
       std::push_heap(scheduling_queue_.begin(), scheduling_queue_.end(),
                      &SchedulingState::Comparator);
     }
diff --git a/gpu/command_buffer/service/service_discardable_manager_unittest.cc b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
index 86eed6d534..6cdffaf 100644
--- a/gpu/command_buffer/service/service_discardable_manager_unittest.cc
+++ b/gpu/command_buffer/service/service_discardable_manager_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/command_buffer/service/service_discardable_manager.h"
 
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "gpu/command_buffer/service/gpu_service_test.h"
 #include "gpu/command_buffer/service/image_manager.h"
@@ -66,7 +67,7 @@
  protected:
   void SetUp() override {
     GpuServiceTest::SetUp();
-    decoder_.reset(new MockGLES2Decoder());
+    decoder_.reset(new MockGLES2Decoder(&command_buffer_service_));
     feature_info_ = new FeatureInfo();
     context_group_ = scoped_refptr<ContextGroup>(
         new ContextGroup(gpu_preferences_, nullptr, nullptr, nullptr, nullptr,
@@ -118,6 +119,7 @@
   scoped_refptr<FeatureInfo> feature_info_;
   MockDestructionObserver destruction_observer_;
   TextureManager* texture_manager_;
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   scoped_refptr<gles2::ContextGroup> context_group_;
 };
diff --git a/gpu/command_buffer/service/texture_manager_unittest.cc b/gpu/command_buffer/service/texture_manager_unittest.cc
index 242a73f..ad82cf3 100644
--- a/gpu/command_buffer/service/texture_manager_unittest.cc
+++ b/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -12,6 +12,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/error_state_mock.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/framebuffer_manager.h"
@@ -674,7 +675,8 @@
         kMaxCubeMapTextureSize, kMaxRectangleTextureSize, kMax3DTextureSize,
         kMaxArrayTextureLayers, kUseDefaultTextures, nullptr,
         &discardable_manager_));
-    decoder_.reset(new ::testing::StrictMock<gles2::MockGLES2Decoder>());
+    decoder_.reset(new ::testing::StrictMock<gles2::MockGLES2Decoder>(
+        &command_buffer_service_));
     error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
     manager_->CreateTexture(kClient1Id, kService1Id);
     texture_ref_ = manager_->GetTexture(kClient1Id);
@@ -706,6 +708,7 @@
         texture_ref, pname, value, error);
   }
 
+  FakeCommandBufferServiceBase command_buffer_service_;
   std::unique_ptr<MockGLES2Decoder> decoder_;
   std::unique_ptr<MockErrorState> error_state_;
   scoped_refptr<FeatureInfo> feature_info_;
diff --git a/gpu/command_buffer/tests/fuzzer_main.cc b/gpu/command_buffer/tests/fuzzer_main.cc
index e010a447..94f86c7 100644
--- a/gpu/command_buffer/tests/fuzzer_main.cc
+++ b/gpu/command_buffer/tests/fuzzer_main.cc
@@ -141,21 +141,16 @@
         true /* bind_generates_resource */, &image_manager_,
         nullptr /* image_factory */, nullptr /* progress_reporter */,
         GpuFeatureInfo(), &discardable_manager_);
-    decoder_.reset(gles2::GLES2Decoder::Create(context_group.get()));
     command_buffer_.reset(new CommandBufferDirect(
-        context_group->transfer_buffer_manager(), decoder_.get(),
-        base::Bind(&gles2::GLES2Decoder::MakeCurrent,
-                   base::Unretained(decoder_.get())),
-        &sync_point_manager_));
+        context_group->transfer_buffer_manager(), &sync_point_manager_));
+
+    decoder_.reset(gles2::GLES2Decoder::Create(command_buffer_.get(),
+                                               command_buffer_->service(),
+                                               context_group.get()));
+    command_buffer_->set_handler(decoder_.get());
+
     InitializeInitialCommandBuffer();
 
-    decoder_->set_command_buffer_service(command_buffer_->service());
-    decoder_->SetFenceSyncReleaseCallback(
-        base::Bind(&CommandBufferDirect::OnFenceSyncRelease,
-                   base::Unretained(command_buffer_.get())));
-    decoder_->SetWaitSyncTokenCallback(
-        base::Bind(&CommandBufferDirect::OnWaitSyncToken,
-                   base::Unretained(command_buffer_.get())));
     decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
 
     gles2::ContextCreationAttribHelper attrib_helper;
@@ -181,6 +176,7 @@
       vertex_translator_ = decoder_->GetTranslator(GL_VERTEX_SHADER);
       fragment_translator_ = decoder_->GetTranslator(GL_FRAGMENT_SHADER);
     }
+    decoder_->MakeCurrent();
   }
 
   void ResetDecoder() {
diff --git a/gpu/command_buffer/tests/gl_deschedule_unittest.cc b/gpu/command_buffer/tests/gl_deschedule_unittest.cc
index 3fc44547..80ba4e8 100644
--- a/gpu/command_buffer/tests/gl_deschedule_unittest.cc
+++ b/gpu/command_buffer/tests/gl_deschedule_unittest.cc
@@ -55,10 +55,6 @@
   glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
                &result);
   EXPECT_EQ(0xFF00FF00u, result);
-
-  // GLManager doesn't implement the callbacks necessary to support
-  // glDescheduleUntilFinishedCHROMIUM, so there should be an error generated.
-  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 33b7b2fc..a22dbd7 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -175,14 +175,9 @@
 class CommandBufferCheckLostContext : public CommandBufferDirect {
  public:
   CommandBufferCheckLostContext(TransferBufferManager* transfer_buffer_manager,
-                                AsyncAPIInterface* handler,
-                                const MakeCurrentCallback& callback,
                                 SyncPointManager* sync_point_manager,
                                 bool context_lost_allowed)
-      : CommandBufferDirect(transfer_buffer_manager,
-                            handler,
-                            callback,
-                            sync_point_manager),
+      : CommandBufferDirect(transfer_buffer_manager, sync_point_manager),
         context_lost_allowed_(context_lost_allowed) {}
 
   ~CommandBufferCheckLostContext() override {}
@@ -323,17 +318,17 @@
         &discardable_manager_);
   }
 
-  decoder_.reset(::gpu::gles2::GLES2Decoder::Create(context_group));
+  command_buffer_.reset(new CommandBufferCheckLostContext(
+      context_group->transfer_buffer_manager(), options.sync_point_manager,
+      options.context_lost_allowed));
+
+  decoder_.reset(::gpu::gles2::GLES2Decoder::Create(
+      command_buffer_.get(), command_buffer_->service(), context_group));
   if (options.force_shader_name_hashing) {
     decoder_->SetForceShaderNameHashingForTest(true);
   }
-  command_buffer_.reset(new CommandBufferCheckLostContext(
-      decoder_->GetContextGroup()->transfer_buffer_manager(), decoder_.get(),
-      base::Bind(&gles2::GLES2Decoder::MakeCurrent,
-                 base::Unretained(decoder_.get())),
-      options.sync_point_manager, options.context_lost_allowed));
 
-  decoder_->set_command_buffer_service(command_buffer_->service());
+  command_buffer_->set_handler(decoder_.get());
 
   surface_ = gl::init::CreateOffscreenGLSurface(gfx::Size());
   ASSERT_TRUE(surface_.get() != NULL) << "could not create offscreen surface";
@@ -366,15 +361,6 @@
     return;
   }
 
-  if (options.sync_point_manager) {
-    decoder_->SetFenceSyncReleaseCallback(
-        base::Bind(&CommandBufferDirect::OnFenceSyncRelease,
-                   base::Unretained(command_buffer_.get())));
-    decoder_->SetWaitSyncTokenCallback(
-        base::Bind(&CommandBufferDirect::OnWaitSyncToken,
-                   base::Unretained(command_buffer_.get())));
-  }
-
   // Create the GLES2 helper, which writes the command buffer protocol.
   gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
   ASSERT_TRUE(gles2_helper_->Initialize(kCommandBufferSize));
@@ -416,6 +402,8 @@
 
 void GLManager::MakeCurrent() {
   ::gles2::SetGLContext(gles2_implementation_.get());
+  if (!decoder_->MakeCurrent())
+    command_buffer_->service()->SetParseError(error::kLostContext);
 }
 
 void GLManager::SetSurface(gl::GLSurface* surface) {
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 9b6c20e..2cc2dea 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -42,7 +42,6 @@
 namespace gles2 {
 
 class MailboxManager;
-class GLES2Decoder;
 class GLES2CmdHelper;
 class GLES2Implementation;
 
diff --git a/gpu/gles2_conform_support/egl/context.cc b/gpu/gles2_conform_support/egl/context.cc
index de8cdbdc..39613b68 100644
--- a/gpu/gles2_conform_support/egl/context.cc
+++ b/gpu/gles2_conform_support/egl/context.cc
@@ -266,18 +266,16 @@
       nullptr /* progress_reporter */, gpu::GpuFeatureInfo(),
       &discardable_manager_));
 
-  std::unique_ptr<gpu::gles2::GLES2Decoder> decoder(
-      gpu::gles2::GLES2Decoder::Create(group.get()));
-  if (!decoder.get())
-    return false;
-
   transfer_buffer_manager_ =
       base::MakeUnique<gpu::TransferBufferManager>(nullptr);
   std::unique_ptr<gpu::CommandBufferDirect> command_buffer(
-      new gpu::CommandBufferDirect(transfer_buffer_manager_.get(),
-                                   decoder.get()));
+      new gpu::CommandBufferDirect(transfer_buffer_manager_.get()));
 
-  decoder->set_command_buffer_service(command_buffer->service());
+  std::unique_ptr<gpu::gles2::GLES2Decoder> decoder(
+      gpu::gles2::GLES2Decoder::Create(command_buffer.get(),
+                                       command_buffer->service(), group.get()));
+
+  command_buffer->set_handler(decoder.get());
 
   gl::GLContextAttribs context_attribs;
   context_attribs.gpu_preference = gl::PreferDiscreteGpu;
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 8c50eca9..24e53f8b 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -143,8 +143,6 @@
 
   bool EnsureBackbuffer();
 
-  void SetOnConsoleMessageCallback(const GpuConsoleMessageCallback& callback);
-
   using SwapBuffersCompletionCallback = base::Callback<void(
       const std::vector<ui::LatencyInfo>& latency_info,
       gfx::SwapResult result,
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 4212fde..4f70fead 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -314,12 +314,10 @@
                 nullptr /* image_factory */, nullptr /* progress_reporter */,
                 GpuFeatureInfo(), service_->discardable_manager());
 
-  decoder_.reset(gles2::GLES2Decoder::Create(context_group_.get()));
-
   command_buffer_ = base::MakeUnique<CommandBufferService>(
-      this, transfer_buffer_manager_.get(), decoder_.get());
-
-  decoder_->set_command_buffer_service(command_buffer_.get());
+      this, transfer_buffer_manager_.get());
+  decoder_.reset(gles2::GLES2Decoder::Create(this, command_buffer_.get(),
+                                             context_group_.get()));
 
   if (!surface_.get()) {
     if (params.is_offscreen) {
@@ -411,19 +409,6 @@
   }
   *params.capabilities = decoder_->GetCapabilities();
 
-  decoder_->SetFenceSyncReleaseCallback(
-      base::Bind(&InProcessCommandBuffer::FenceSyncReleaseOnGpuThread,
-                 base::Unretained(this)));
-  decoder_->SetWaitSyncTokenCallback(
-      base::Bind(&InProcessCommandBuffer::WaitSyncTokenOnGpuThread,
-                 base::Unretained(this)));
-  decoder_->SetDescheduleUntilFinishedCallback(
-      base::Bind(&InProcessCommandBuffer::DescheduleUntilFinishedOnGpuThread,
-                 base::Unretained(this)));
-  decoder_->SetRescheduleAfterFinishedCallback(
-      base::Bind(&InProcessCommandBuffer::RescheduleAfterFinishedOnGpuThread,
-                 base::Unretained(this)));
-
   image_factory_ = params.image_factory;
 
   return true;
@@ -447,13 +432,13 @@
 bool InProcessCommandBuffer::DestroyOnGpuThread() {
   CheckSequencedThread();
   gpu_thread_weak_ptr_factory_.InvalidateWeakPtrs();
-  command_buffer_.reset();
   // Clean up GL resources if possible.
   bool have_context = context_.get() && context_->MakeCurrent(surface_.get());
   if (decoder_) {
     decoder_->Destroy(have_context);
     decoder_.reset();
   }
+  command_buffer_.reset();
   context_ = nullptr;
   surface_ = nullptr;
   if (sync_point_order_data_) {
@@ -580,7 +565,7 @@
   if (!MakeCurrent())
     return;
 
-  command_buffer_->Flush(put_offset);
+  command_buffer_->Flush(put_offset, decoder_.get());
   // Update state before signaling the flush event.
   UpdateLastStateOnGpuThread();
 
@@ -849,7 +834,17 @@
   image_manager->RemoveImage(id);
 }
 
-void InProcessCommandBuffer::FenceSyncReleaseOnGpuThread(uint64_t release) {
+void InProcessCommandBuffer::OnConsoleMessage(int32_t id,
+                                              const std::string& message) {
+  // TODO(piman): implement this.
+}
+
+void InProcessCommandBuffer::CacheShader(const std::string& key,
+                                         const std::string& shader) {
+  // TODO(piman): implement this.
+}
+
+void InProcessCommandBuffer::OnFenceSyncRelease(uint64_t release) {
   SyncToken sync_token(GetNamespaceID(), GetStreamId(), GetCommandBufferID(),
                        release);
 
@@ -860,8 +855,7 @@
   sync_point_client_state_->ReleaseFenceSync(release);
 }
 
-bool InProcessCommandBuffer::WaitSyncTokenOnGpuThread(
-    const SyncToken& sync_token) {
+bool InProcessCommandBuffer::OnWaitSyncToken(const SyncToken& sync_token) {
   DCHECK(!waiting_for_sync_point_);
   gpu::SyncPointManager* sync_point_manager = service_->sync_point_manager();
   DCHECK(sync_point_manager);
@@ -908,7 +902,7 @@
       &InProcessCommandBuffer::ProcessTasksOnGpuThread, gpu_thread_weak_ptr_));
 }
 
-void InProcessCommandBuffer::DescheduleUntilFinishedOnGpuThread() {
+void InProcessCommandBuffer::OnDescheduleUntilFinished() {
   if (!service_->BlockThreadOnWaitSyncToken()) {
     DCHECK(command_buffer_->scheduled());
     DCHECK(decoder_->HasPollingWork());
@@ -917,7 +911,7 @@
   }
 }
 
-void InProcessCommandBuffer::RescheduleAfterFinishedOnGpuThread() {
+void InProcessCommandBuffer::OnRescheduleAfterFinished() {
   if (!service_->BlockThreadOnWaitSyncToken()) {
     DCHECK(!command_buffer_->scheduled());
 
diff --git a/gpu/ipc/in_process_command_buffer.h b/gpu/ipc/in_process_command_buffer.h
index 39dbaa7..a058e16 100644
--- a/gpu/ipc/in_process_command_buffer.h
+++ b/gpu/ipc/in_process_command_buffer.h
@@ -27,6 +27,7 @@
 #include "gpu/command_buffer/common/command_buffer.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/gpu_preferences.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/gpu_export.h"
@@ -61,7 +62,6 @@
 namespace gles2 {
 struct ContextCreationAttribHelper;
 class FramebufferCompletenessCache;
-class GLES2Decoder;
 class MailboxManager;
 class ProgramCache;
 class ShaderTranslatorCache;
@@ -78,6 +78,7 @@
 class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer,
                                           public GpuControl,
                                           public CommandBufferServiceClient,
+                                          public gles2::GLES2DecoderClient,
                                           public ImageTransportSurfaceDelegate {
  public:
   class Service;
@@ -144,6 +145,14 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
+  // GLES2DecoderClient implementation:
+  void OnConsoleMessage(int32_t id, const std::string& message) override;
+  void CacheShader(const std::string& key, const std::string& shader) override;
+  void OnFenceSyncRelease(uint64_t release) override;
+  bool OnWaitSyncToken(const SyncToken& sync_token) override;
+  void OnDescheduleUntilFinished() override;
+  void OnRescheduleAfterFinished() override;
+
 // ImageTransportSurfaceDelegate implementation:
 #if defined(OS_WIN)
   void DidCreateAcceleratedSurfaceChildWindow(
@@ -257,11 +266,7 @@
   void QueueTask(bool out_of_order, const base::Closure& task);
   void ProcessTasksOnGpuThread();
   void CheckSequencedThread();
-  void FenceSyncReleaseOnGpuThread(uint64_t release);
-  bool WaitSyncTokenOnGpuThread(const SyncToken& sync_token);
   void OnWaitSyncTokenCompleted(const SyncToken& sync_token);
-  void DescheduleUntilFinishedOnGpuThread();
-  void RescheduleAfterFinishedOnGpuThread();
   void SignalSyncTokenOnGpuThread(const SyncToken& sync_token,
                                   const base::Closure& callback);
   void SignalQueryOnGpuThread(unsigned query_id, const base::Closure& callback);
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index b9bdf6ac..c5f6a811 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -633,18 +633,15 @@
     use_virtualized_gl_context_ = false;
 #endif
 
-
-  decoder_.reset(gles2::GLES2Decoder::Create(context_group_.get()));
-
   command_buffer_.reset(new CommandBufferService(
-      this, context_group_->transfer_buffer_manager(), decoder_.get()));
+      this, context_group_->transfer_buffer_manager()));
+  decoder_.reset(gles2::GLES2Decoder::Create(this, command_buffer_.get(),
+                                             context_group_.get()));
 
   sync_point_client_state_ =
       channel_->sync_point_manager()->CreateSyncPointClientState(
           CommandBufferNamespace::GPU_IO, command_buffer_id_, sequence_id_);
 
-  decoder_->set_command_buffer_service(command_buffer_.get());
-
   if (offscreen) {
     // Do we want to create an offscreen rendering context suitable
     // for directly drawing to a separately supplied surface? In that
@@ -778,21 +775,6 @@
     decoder_->set_log_commands(true);
   }
 
-  decoder_->GetLogger()->SetMsgCallback(base::Bind(
-      &GpuCommandBufferStub::SendConsoleMessage, base::Unretained(this)));
-  decoder_->SetShaderCacheCallback(base::Bind(
-      &GpuCommandBufferStub::SendCachedShader, base::Unretained(this)));
-  decoder_->SetFenceSyncReleaseCallback(base::Bind(
-      &GpuCommandBufferStub::OnFenceSyncRelease, base::Unretained(this)));
-  decoder_->SetWaitSyncTokenCallback(base::Bind(
-      &GpuCommandBufferStub::OnWaitSyncToken, base::Unretained(this)));
-  decoder_->SetDescheduleUntilFinishedCallback(
-      base::Bind(&GpuCommandBufferStub::OnDescheduleUntilFinished,
-                 base::Unretained(this)));
-  decoder_->SetRescheduleAfterFinishedCallback(
-      base::Bind(&GpuCommandBufferStub::OnRescheduleAfterFinished,
-                 base::Unretained(this)));
-
   const size_t kSharedStateSize = sizeof(CommandBufferSharedState);
   if (!shared_state_shm->Map(kSharedStateSize)) {
     DLOG(ERROR) << "Failed to map shared state buffer.";
@@ -970,7 +952,7 @@
   last_flush_count_ = flush_count;
   CommandBuffer::State pre_state = command_buffer_->GetState();
   FastSetActiveURL(active_url_, active_url_hash_, channel_);
-  command_buffer_->Flush(put_offset);
+  command_buffer_->Flush(put_offset, decoder_.get());
   CommandBuffer::State post_state = command_buffer_->GetState();
 
   if (pre_state.get_offset != post_state.get_offset)
@@ -1163,8 +1145,8 @@
   image_manager->RemoveImage(id);
 }
 
-void GpuCommandBufferStub::SendConsoleMessage(int32_t id,
-                                              const std::string& message) {
+void GpuCommandBufferStub::OnConsoleMessage(int32_t id,
+                                            const std::string& message) {
   GPUCommandBufferConsoleMessage console_message;
   console_message.id = id;
   console_message.message = message;
@@ -1174,8 +1156,8 @@
   Send(msg);
 }
 
-void GpuCommandBufferStub::SendCachedShader(const std::string& key,
-                                            const std::string& shader) {
+void GpuCommandBufferStub::CacheShader(const std::string& key,
+                                       const std::string& shader) {
   channel_->CacheShader(key, shader);
 }
 
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.h b/gpu/ipc/service/gpu_command_buffer_stub.h
index 1bc8325f..6916ab7 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.h
+++ b/gpu/ipc/service/gpu_command_buffer_stub.h
@@ -22,6 +22,7 @@
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
 #include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
 #include "gpu/command_buffer/service/sequence_id.h"
 #include "gpu/gpu_export.h"
 #include "gpu/ipc/common/surface_handle.h"
@@ -55,6 +56,7 @@
     : public IPC::Listener,
       public IPC::Sender,
       public CommandBufferServiceClient,
+      public gles2::GLES2DecoderClient,
       public ImageTransportSurfaceDelegate,
       public base::SupportsWeakPtr<GpuCommandBufferStub> {
  public:
@@ -95,6 +97,14 @@
   CommandBatchProcessedResult OnCommandBatchProcessed() override;
   void OnParseError() override;
 
+  // GLES2DecoderClient implementation:
+  void OnConsoleMessage(int32_t id, const std::string& message) override;
+  void CacheShader(const std::string& key, const std::string& shader) override;
+  void OnFenceSyncRelease(uint64_t release) override;
+  bool OnWaitSyncToken(const SyncToken& sync_token) override;
+  void OnDescheduleUntilFinished() override;
+  void OnRescheduleAfterFinished() override;
+
 // ImageTransportSurfaceDelegate implementation:
 #if defined(OS_WIN)
   void DidCreateAcceleratedSurfaceChildWindow(
@@ -128,11 +138,6 @@
 
   int32_t stream_id() const { return stream_id_; }
 
-  // Sends a message to the console.
-  void SendConsoleMessage(int32_t id, const std::string& message);
-
-  void SendCachedShader(const std::string& key, const std::string& shader);
-
   gl::GLSurface* surface() const { return surface_.get(); }
 
   void AddDestructionObserver(DestructionObserver* observer);
@@ -179,7 +184,6 @@
                                 uint32_t size);
   void OnDestroyTransferBuffer(int32_t id);
   void OnGetTransferBuffer(int32_t id, IPC::Message* reply_message);
-  bool OnWaitSyncToken(const SyncToken& sync_token);
 
   void OnEnsureBackbuffer();
 
@@ -187,12 +191,8 @@
   void OnSignalAck(uint32_t id);
   void OnSignalQuery(uint32_t query, uint32_t id);
 
-  void OnFenceSyncRelease(uint64_t release);
   void OnWaitSyncTokenCompleted(const SyncToken& sync_token);
 
-  void OnDescheduleUntilFinished();
-  void OnRescheduleAfterFinished();
-
   void OnCreateImage(const GpuCommandBufferMsg_CreateImage_Params& params);
   void OnDestroyImage(int32_t id);
   void OnCreateStreamTexture(uint32_t texture_id,
diff --git a/ios/build/bots/tests/common_tests.json b/ios/build/bots/tests/common_tests.json
index 36a06e25..c7a6aef9 100644
--- a/ios/build/bots/tests/common_tests.json
+++ b/ios/build/bots/tests/common_tests.json
@@ -22,9 +22,6 @@
       "app": "google_apis_unittests"
     },
     {
-      "app": "ios_chrome_unittests"
-    },
-    {
       "app": "ios_net_unittests"
     },
     {
@@ -34,9 +31,6 @@
       "app": "ios_web_unittests"
     },
     {
-      "app": "net_unittests"
-    },
-    {
       "app": "skia_unittests"
     },
     {
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index d6bf5805..eb4b15e 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -77,6 +77,7 @@
 }
 
 source_set("browsing_data_internal") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
     "browsing_data_removal_controller.h",
     "browsing_data_removal_controller.mm",
diff --git a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
index 50ce158..f13a5eb 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_removal_controller.mm
@@ -11,7 +11,6 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/containers/hash_tables.h"
-#import "base/ios/weak_nsobject.h"
 #include "base/logging.h"
 #import "base/mac/bind_objc_block.h"
 #include "base/memory/ref_counted.h"
@@ -37,6 +36,10 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace {
 // Empty callback used by DeleteAllCreatedBetweenAsync below.
 void DoNothing(int n) {}
@@ -111,7 +114,7 @@
   // operations.
   std::unique_ptr<BrowsingDataRemoverHelper> _browsingDataRemoverHelper;
   // The delegate.
-  base::WeakNSProtocol<id<BrowsingDataRemovalControllerDelegate>> _delegate;
+  __weak id<BrowsingDataRemovalControllerDelegate> _delegate;
   // A map that tracks the number of pending removals for a given
   // ChromeBrowserState.
   base::hash_map<ios::ChromeBrowserState*, int> _pendingRemovalCount;
@@ -122,7 +125,7 @@
   if ((self = [super init])) {
     DCHECK(delegate);
     _browsingDataRemoverHelper.reset(new BrowsingDataRemoverHelper());
-    _delegate.reset(delegate);
+    _delegate = delegate;
   }
   return self;
 }
@@ -158,7 +161,7 @@
   };
 
   scoped_refptr<CallbackCounter> callbackCounter =
-      new CallbackCounter(base::BindBlock(browsingDataCleared));
+      new CallbackCounter(base::BindBlockArc(browsingDataCleared));
   ProceduralBlock decrementCallbackCounterCount = ^{
     callbackCounter->DecrementCount();
   };
@@ -184,7 +187,7 @@
   if (!browserState->IsOffTheRecord()) {
     callbackCounter->IncrementCount();
     _browsingDataRemoverHelper->Remove(browserState, mask, timePeriod,
-                                       base::BindBlock(^{
+                                       base::BindBlockArc(^{
                                          callbackCounter->DecrementCount();
                                        }));
   }
@@ -276,10 +279,10 @@
     }
     return;
   }
-  scoped_refptr<CallbackCounter> callbackCounter =
-      new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
-                                                            : ^{
-                                                              }));
+  scoped_refptr<CallbackCounter> callbackCounter = new CallbackCounter(
+      base::BindBlockArc(completionHandler ? completionHandler
+                                           : ^{
+                                             }));
 
   // Note: Before adding any method below, make sure that it can finish clearing
   // browsing data even when |browserState| is destroyed after this method call.
@@ -300,10 +303,10 @@
                                        deleteBegin:(base::Time)deleteBegin
                                  completionHandler:
                                      (ProceduralBlock)completionHandler {
-  scoped_refptr<CallbackCounter> callbackCounter =
-      new CallbackCounter(base::BindBlock(completionHandler ? completionHandler
-                                                            : ^{
-                                                              }));
+  scoped_refptr<CallbackCounter> callbackCounter = new CallbackCounter(
+      base::BindBlockArc(completionHandler ? completionHandler
+                                           : ^{
+                                             }));
   ProceduralBlock decrementCallbackCounterCount = ^{
     callbackCounter->DecrementCount();
   };
@@ -311,8 +314,7 @@
   // Converts browsing data types from
   // IOSChromeBrowsingDataRemover::RemoveDataMask to
   // WKWebsiteDataStore strings.
-  base::scoped_nsobject<NSMutableSet> dataTypesToRemove(
-      [[NSMutableSet alloc] init]);
+  NSMutableSet* dataTypesToRemove = [[NSMutableSet alloc] init];
   if (mask & IOSChromeBrowsingDataRemover::REMOVE_CACHE_STORAGE) {
     [dataTypesToRemove addObject:WKWebsiteDataTypeDiskCache];
     [dataTypesToRemove addObject:WKWebsiteDataTypeMemoryCache];
@@ -409,10 +411,10 @@
   if (mask & IOSChromeBrowsingDataRemover::REMOVE_COOKIES) {
     scoped_refptr<net::URLRequestContextGetter> contextGetter =
         browserState->GetRequestContext();
-    base::Closure callback = base::BindBlock(^{
+    base::Closure callback = base::BindBlockArc(^{
     });
     web::WebThread::PostTask(
-        web::WebThread::IO, FROM_HERE, base::BindBlock(^{
+        web::WebThread::IO, FROM_HERE, base::BindBlockArc(^{
           net::URLRequestContext* requestContext =
               contextGetter->GetURLRequestContext();
           net::ChannelIDService* channelIdService =
diff --git a/ios/chrome/browser/ui/settings/about_chrome_collection_view_controller.h b/ios/chrome/browser/ui/settings/about_chrome_collection_view_controller.h
index 8e97aed..00d74ea0 100644
--- a/ios/chrome/browser/ui/settings/about_chrome_collection_view_controller.h
+++ b/ios/chrome/browser/ui/settings/about_chrome_collection_view_controller.h
@@ -7,6 +7,8 @@
 
 #import "ios/chrome/browser/ui/settings/settings_root_collection_view_controller.h"
 
+// Controller for the About Google Chrome collection view, which allows users to
+// view open source licenses, terms of service, etc.
 @interface AboutChromeCollectionViewController
     : SettingsRootCollectionViewController
 
diff --git a/media/cdm/cdm_paths.cc b/media/cdm/cdm_paths.cc
index b72daea..d8eeb7f 100644
--- a/media/cdm/cdm_paths.cc
+++ b/media/cdm/cdm_paths.cc
@@ -13,6 +13,8 @@
 // Name of the ClearKey CDM library.
 const char kClearKeyCdmLibraryName[] = "clearkeycdm";
 
+const char kClearKeyCdmBaseDirectory[] = "ClearKeyCdm";
+
 const char kClearKeyCdmAdapterFileName[] =
 #if defined(OS_MACOSX)
     "clearkeycdmadapter.plugin";
@@ -22,6 +24,10 @@
     "libclearkeycdmadapter.so";
 #endif
 
+const char kClearKeyCdmDisplayName[] = "Clear Key CDM";
+
+const char kClearKeyCdmPepperMimeType[] = "application/x-ppapi-clearkey-cdm";
+
 // Note: This file must be in sync with cdm_paths.gni.
 // TODO(xhwang): Improve how we enable platform specific path. See
 // http://crbug.com/468584
diff --git a/media/cdm/cdm_paths.h b/media/cdm/cdm_paths.h
index 6060729..75500603 100644
--- a/media/cdm/cdm_paths.h
+++ b/media/cdm/cdm_paths.h
@@ -14,9 +14,18 @@
 // Name of the ClearKey CDM library.
 extern const char kClearKeyCdmLibraryName[];
 
+extern const char kClearKeyCdmBaseDirectory[];
+
 // Platform-specific filename relative to kClearKeyCdmBaseDirectory.
 extern const char kClearKeyCdmAdapterFileName[];
 
+// Display name for Clear Key CDM.
+extern const char kClearKeyCdmDisplayName[];
+
+// Pepper type for Clear Key CDM.
+// TODO(xhwang): Remove after switching to mojo CDM.
+extern const char kClearKeyCdmPepperMimeType[];
+
 // Returns the path of a CDM relative to DIR_COMPONENTS.
 // On platforms where a platform specific path is used, returns
 //   |cdm_base_path|/_platform_specific/<platform>_<arch>
diff --git a/media/cdm/external_clear_key_test_helper.cc b/media/cdm/external_clear_key_test_helper.cc
index d8c36798..660796fe 100644
--- a/media/cdm/external_clear_key_test_helper.cc
+++ b/media/cdm/external_clear_key_test_helper.cc
@@ -21,8 +21,6 @@
 #define STRINGIFY(X) #X
 #define MAKE_STRING(X) STRINGIFY(X)
 
-const char kClearKeyCdmBaseDirectory[] = "ClearKeyCdm";
-
 ExternalClearKeyTestHelper::ExternalClearKeyTestHelper() {
   LoadLibrary();
 }
diff --git a/media/gpu/android_video_decode_accelerator_unittest.cc b/media/gpu/android_video_decode_accelerator_unittest.cc
index b4bad91..b8468b40 100644
--- a/media/gpu/android_video_decode_accelerator_unittest.cc
+++ b/media/gpu/android_video_decode_accelerator_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
 #include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
 #include "media/base/android/media_codec_util.h"
 #include "media/base/android/media_jni_registrar.h"
@@ -137,7 +138,8 @@
 class AndroidVideoDecodeAcceleratorTest : public testing::Test {
  public:
   // We pick this profile since it's always supported.
-  AndroidVideoDecodeAcceleratorTest() : config_(H264PROFILE_BASELINE) {}
+  AndroidVideoDecodeAcceleratorTest()
+      : gl_decoder_(&command_buffer_service_), config_(H264PROFILE_BASELINE) {}
 
   ~AndroidVideoDecodeAcceleratorTest() override {}
 
@@ -243,6 +245,7 @@
   scoped_refptr<gl::GLSurface> surface_;
   scoped_refptr<gl::GLContext> context_;
   scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+  gpu::FakeCommandBufferServiceBase command_buffer_service_;
   NiceMock<gpu::gles2::MockGLES2Decoder> gl_decoder_;
   NiceMock<MockVDAClient> client_;
   FakeCodecAllocator codec_allocator_;
diff --git a/mojo/edk/system/handle_table.cc b/mojo/edk/system/handle_table.cc
index 03b6d0b..d4793bb 100644
--- a/mojo/edk/system/handle_table.cc
+++ b/mojo/edk/system/handle_table.cc
@@ -181,12 +181,14 @@
     }
   }
 
-  base::trace_event::MemoryAllocatorDump* outer_dump =
-      pmd->CreateAllocatorDump("mojo");
+  pmd->CreateAllocatorDump("mojo");
   for (const auto& entry : handle_count) {
-    outer_dump->AddScalar(GetNameForDispatcherType(entry.first),
-                          base::trace_event::MemoryAllocatorDump::kUnitsObjects,
-                          entry.second);
+    base::trace_event::MemoryAllocatorDump* inner_dump =
+        pmd->CreateAllocatorDump(std::string("mojo/") +
+                                 GetNameForDispatcherType(entry.first));
+    inner_dump->AddScalar(
+        base::trace_event::MemoryAllocatorDump::kNameObjectCount,
+        base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
   }
 
   return true;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 48e95595..7e94fbcd 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -992,6 +992,7 @@
       "nqe/cached_network_quality.h",
       "nqe/effective_connection_type.cc",
       "nqe/effective_connection_type.h",
+      "nqe/effective_connection_type_observer.h",
       "nqe/event_creator.cc",
       "nqe/event_creator.h",
       "nqe/external_estimate_provider.h",
@@ -1006,9 +1007,12 @@
       "nqe/network_quality_estimator_params.h",
       "nqe/network_quality_observation.h",
       "nqe/network_quality_observation_source.h",
+      "nqe/network_quality_provider.cc",
+      "nqe/network_quality_provider.h",
       "nqe/network_quality_store.cc",
       "nqe/network_quality_store.h",
       "nqe/observation_buffer.h",
+      "nqe/rtt_throughput_estimates_observer.h",
       "nqe/socket_watcher.cc",
       "nqe/socket_watcher.h",
       "nqe/socket_watcher_factory.cc",
diff --git a/net/nqe/effective_connection_type_observer.h b/net/nqe/effective_connection_type_observer.h
new file mode 100644
index 0000000..ba42b33
--- /dev/null
+++ b/net/nqe/effective_connection_type_observer.h
@@ -0,0 +1,41 @@
+// 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 NET_NQE_NETWORK_QUALITY_EFFECTIVE_CONNECTION_TYPE_OBSERVER_H_
+#define NET_NQE_NETWORK_QUALITY_EFFECTIVE_CONNECTION_TYPE_OBSERVER_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/nqe/effective_connection_type.h"
+
+namespace net {
+
+// Observes changes in effective connection type.
+class NET_EXPORT EffectiveConnectionTypeObserver {
+ public:
+  // Notifies the observer of a change in the effective connection type.
+  // NetworkQualityEstimator computes the effective connection type once in
+  // every interval of duration
+  // |effective_connection_type_recomputation_interval_|. Additionally, when
+  // there is a change in the connection type of the device, then the
+  // effective connection type is immediately recomputed.
+  //
+  // If the computed effective connection type is different from the
+  // previously notified effective connection type, then all the registered
+  // observers are notified of the new effective connection type.
+  virtual void OnEffectiveConnectionTypeChanged(
+      EffectiveConnectionType type) = 0;
+
+ protected:
+  EffectiveConnectionTypeObserver() {}
+  virtual ~EffectiveConnectionTypeObserver() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EffectiveConnectionTypeObserver);
+};
+
+}  // namespace net
+
+#endif  // NET_NQE_NETWORK_QUALITY_EFFECTIVE_CONNECTION_TYPE_OBSERVER_H_
\ No newline at end of file
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index 8759b0f..643a0ef 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -1767,6 +1767,14 @@
   }
 }
 
+base::Optional<base::TimeDelta> NetworkQualityEstimator::GetHttpRTT() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (network_quality_.http_rtt() == nqe::internal::InvalidRTT())
+    return base::Optional<base::TimeDelta>();
+  return network_quality_.http_rtt();
+}
+
 base::Optional<base::TimeDelta> NetworkQualityEstimator::GetTransportRTT()
     const {
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -1776,6 +1784,17 @@
   return network_quality_.transport_rtt();
 }
 
+base::Optional<int32_t> NetworkQualityEstimator::GetDownstreamThroughputKbps()
+    const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (network_quality_.downstream_throughput_kbps() ==
+      nqe::internal::kInvalidThroughput) {
+    return base::Optional<int32_t>();
+  }
+  return network_quality_.downstream_throughput_kbps();
+}
+
 void NetworkQualityEstimator::MaybeUpdateNetworkQualityFromCache(
     const nqe::internal::NetworkID& network_id,
     const nqe::internal::CachedNetworkQuality& cached_network_quality) {
@@ -1832,20 +1851,4 @@
   return "";
 }
 
-base::Optional<base::TimeDelta>
-NetworkQualityEstimator::NetworkQualityProvider::GetHttpRTT() const {
-  return base::Optional<base::TimeDelta>();
-}
-
-base::Optional<base::TimeDelta>
-NetworkQualityEstimator::NetworkQualityProvider::GetTransportRTT() const {
-  return base::Optional<base::TimeDelta>();
-}
-
-base::Optional<int32_t>
-NetworkQualityEstimator::NetworkQualityProvider::GetDownstreamThroughputKbps()
-    const {
-  return base::Optional<int32_t>();
-}
-
 }  // namespace net
diff --git a/net/nqe/network_quality_estimator.h b/net/nqe/network_quality_estimator.h
index 1165b9b..19e460a5 100644
--- a/net/nqe/network_quality_estimator.h
+++ b/net/nqe/network_quality_estimator.h
@@ -24,6 +24,7 @@
 #include "net/base/network_change_notifier.h"
 #include "net/nqe/cached_network_quality.h"
 #include "net/nqe/effective_connection_type.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/event_creator.h"
 #include "net/nqe/external_estimate_provider.h"
 #include "net/nqe/network_id.h"
@@ -31,8 +32,10 @@
 #include "net/nqe/network_quality_estimator_params.h"
 #include "net/nqe/network_quality_observation.h"
 #include "net/nqe/network_quality_observation_source.h"
+#include "net/nqe/network_quality_provider.h"
 #include "net/nqe/network_quality_store.h"
 #include "net/nqe/observation_buffer.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
 #include "net/socket/socket_performance_watcher_factory.h"
 
 namespace base {
@@ -61,65 +64,9 @@
 // observed traffic characteristics.
 class NET_EXPORT NetworkQualityEstimator
     : public NetworkChangeNotifier::ConnectionTypeObserver,
-      public ExternalEstimateProvider::UpdatedEstimateDelegate {
+      public ExternalEstimateProvider::UpdatedEstimateDelegate,
+      public NetworkQualityProvider {
  public:
-  // Observes changes in effective connection type.
-  class NET_EXPORT EffectiveConnectionTypeObserver {
-   public:
-    // Notifies the observer of a change in the effective connection type.
-    // NetworkQualityEstimator computes the effective connection type once in
-    // every interval of duration
-    // |effective_connection_type_recomputation_interval_|. Additionally, when
-    // there is a change in the connection type of the device, then the
-    // effective connection type is immediately recomputed. The observer must
-    // register and unregister itself on the IO thread. All the observers would
-    // be notified on the IO thread.
-    //
-    // If the computed effective connection type is different from the
-    // previously notified effective connection type, then all the registered
-    // observers are notified of the new effective connection type.
-    virtual void OnEffectiveConnectionTypeChanged(
-        EffectiveConnectionType type) = 0;
-
-   protected:
-    EffectiveConnectionTypeObserver() {}
-    virtual ~EffectiveConnectionTypeObserver() {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(EffectiveConnectionTypeObserver);
-  };
-
-  // Observes changes in the network quality.
-  class NET_EXPORT RTTAndThroughputEstimatesObserver {
-   public:
-    // Notifies the observer when estimated HTTP RTT, estimated transport RTT or
-    // estimated downstream throughput is computed. NetworkQualityEstimator
-    // computes the RTT and throughput estimates at regular intervals.
-    // Additionally, when there is a change in the connection type of the
-    // device, then the estimates are immediately computed. The observer must
-    // register and unregister itself on the IO thread. All the observers would
-    // be notified on the IO thread.
-    //
-    // |http_rtt|, |transport_rtt| and |downstream_throughput_kbps| are the
-    // computed estimates of the HTTP RTT, transport RTT and downstream
-    // throughput (in kilobits per second), respectively. If an estimate of the
-    // HTTP or transport RTT is unavailable, it will be set to
-    // nqe::internal::InvalidRTT(). If the throughput estimate is unavailable,
-    // it will be set to nqe::internal::kInvalidThroughput.
-    virtual void OnRTTOrThroughputEstimatesComputed(
-        base::TimeDelta http_rtt,
-        base::TimeDelta transport_rtt,
-        int32_t downstream_throughput_kbps) = 0;
-
-    virtual ~RTTAndThroughputEstimatesObserver() {}
-
-   protected:
-    RTTAndThroughputEstimatesObserver() {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(RTTAndThroughputEstimatesObserver);
-  };
-
   // Observes measurements of round trip time.
   class NET_EXPORT_PRIVATE RTTObserver {
    public:
@@ -156,53 +103,6 @@
     DISALLOW_COPY_AND_ASSIGN(ThroughputObserver);
   };
 
-  // Provides simple interface to obtain the effective connection type.
-  class NET_EXPORT NetworkQualityProvider {
-   public:
-    virtual ~NetworkQualityProvider() {}
-
-    // Returns the current effective connection type.
-    virtual EffectiveConnectionType GetEffectiveConnectionType() const = 0;
-
-    // Adds |observer| to a list of effective connection type observers.
-    virtual void AddEffectiveConnectionTypeObserver(
-        EffectiveConnectionTypeObserver* observer) = 0;
-
-    // Removes |observer| from a list of effective connection type observers.
-    virtual void RemoveEffectiveConnectionTypeObserver(
-        EffectiveConnectionTypeObserver* observer) = 0;
-
-    // Returns the current HTTP RTT estimate. If the estimate is unavailable,
-    // the returned optional value is null.
-    virtual base::Optional<base::TimeDelta> GetHttpRTT() const;
-
-    // Returns the current transport RTT estimate. If the estimate is
-    // unavailable, the returned optional value is null.
-    virtual base::Optional<base::TimeDelta> GetTransportRTT() const;
-
-    // Returns the current downstream throughput estimate (in kilobits per
-    // second). If the estimate is unavailable, the returned optional value is
-    // null.
-    virtual base::Optional<int32_t> GetDownstreamThroughputKbps() const;
-
-    // Adds |observer| to the list of RTT and throughput estimate observers.
-    // |observer| would be notified of the current RTT and throughput estimates
-    // in the next message pump.
-    virtual void AddRTTAndThroughputEstimatesObserver(
-        RTTAndThroughputEstimatesObserver* observer) = 0;
-
-    // Removes |observer| from the list of RTT and throughput estimate
-    // observers.
-    virtual void RemoveRTTAndThroughputEstimatesObserver(
-        RTTAndThroughputEstimatesObserver* observer) = 0;
-
-   protected:
-    NetworkQualityProvider() {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(NetworkQualityProvider);
-  };
-
   // Creates a new NetworkQualityEstimator.
   // |variation_params| is the map containing all field trial parameters
   // related to NetworkQualityEstimator field trial.
@@ -235,39 +135,26 @@
 
   ~NetworkQualityEstimator() override;
 
-  // Returns the last computed effective type of the current connection. The
-  // effective connection type is computed by the network quality estimator at
-  // regular intervals and at certain events (e.g., connection change).
-  // Virtualized for testing.
-  virtual EffectiveConnectionType GetEffectiveConnectionType() const;
-
   // Returns the effective type of the current connection based on only the
   // samples observed after |start_time|. This should only be used for
   // recording the metrics. Virtualized for testing.
   virtual EffectiveConnectionType GetRecentEffectiveConnectionType(
       const base::TimeTicks& start_time) const;
 
-  // Adds |observer| to the list of effective connection type observers. Must be
-  // called on the IO thread. |observer| would be notified of the current
-  // effective connection type in the next message pump.
+  // NetworkQualityProvider implementation:
+  // Must be called on the IO thread.
+  EffectiveConnectionType GetEffectiveConnectionType() const override;
   void AddEffectiveConnectionTypeObserver(
-      EffectiveConnectionTypeObserver* observer);
-
-  // Removes |observer| from the list of effective connection type observers.
-  // Must be called on the IO thread.
+      EffectiveConnectionTypeObserver* observer) override;
   void RemoveEffectiveConnectionTypeObserver(
-      EffectiveConnectionTypeObserver* observer);
-
-  // Adds |observer| to the list of RTT and throughput estimate observers. Must
-  // be called on the IO thread. |observer| would be notified of the current RTT
-  // and throughput estimates in the next message pump.
+      EffectiveConnectionTypeObserver* observer) override;
+  base::Optional<base::TimeDelta> GetHttpRTT() const override;
+  base::Optional<base::TimeDelta> GetTransportRTT() const override;
+  base::Optional<int32_t> GetDownstreamThroughputKbps() const override;
   void AddRTTAndThroughputEstimatesObserver(
-      RTTAndThroughputEstimatesObserver* observer);
-
-  // Removes |observer| from the list of RTT and throughput estimate observers.
-  // Must be called on the IO thread.
+      RTTAndThroughputEstimatesObserver* observer) override;
   void RemoveRTTAndThroughputEstimatesObserver(
-      RTTAndThroughputEstimatesObserver* observer);
+      RTTAndThroughputEstimatesObserver* observer) override;
 
   // Notifies NetworkQualityEstimator that the response header of |request| has
   // been received.
@@ -341,10 +228,6 @@
       const std::map<nqe::internal::NetworkID,
                      nqe::internal::CachedNetworkQuality> read_prefs);
 
-  // Returns the current transport RTT estimate. If the estimate is unavailable,
-  // the returned optional has no value.
-  base::Optional<base::TimeDelta> GetTransportRTT() const;
-
  protected:
   // A protected constructor for testing that allows setting the value of
   // |add_default_platform_observations_|.
diff --git a/net/nqe/network_quality_estimator_unittest.cc b/net/nqe/network_quality_estimator_unittest.cc
index 4f7941ed..29e12aa 100644
--- a/net/nqe/network_quality_estimator_unittest.cc
+++ b/net/nqe/network_quality_estimator_unittest.cc
@@ -33,11 +33,13 @@
 #include "net/http/http_status_code.h"
 #include "net/log/test_net_log.h"
 #include "net/nqe/effective_connection_type.h"
+#include "net/nqe/effective_connection_type_observer.h"
 #include "net/nqe/external_estimate_provider.h"
 #include "net/nqe/network_quality_estimator_test_util.h"
 #include "net/nqe/network_quality_observation.h"
 #include "net/nqe/network_quality_observation_source.h"
 #include "net/nqe/observation_buffer.h"
+#include "net/nqe/rtt_throughput_estimates_observer.h"
 #include "net/socket/socket_performance_watcher.h"
 #include "net/socket/socket_performance_watcher_factory.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -73,7 +75,7 @@
 namespace {
 
 class TestEffectiveConnectionTypeObserver
-    : public NetworkQualityEstimator::EffectiveConnectionTypeObserver {
+    : public EffectiveConnectionTypeObserver {
  public:
   std::vector<EffectiveConnectionType>& effective_connection_types() {
     return effective_connection_types_;
@@ -89,7 +91,7 @@
 };
 
 class TestRTTAndThroughputEstimatesObserver
-    : public NetworkQualityEstimator::RTTAndThroughputEstimatesObserver {
+    : public RTTAndThroughputEstimatesObserver {
  public:
   TestRTTAndThroughputEstimatesObserver()
       : http_rtt_(nqe::internal::InvalidRTT()),
@@ -221,8 +223,10 @@
   // Both RTT and downstream throughput should be updated.
   base::TimeDelta http_rtt;
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &http_rtt));
+  EXPECT_EQ(http_rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
   base::TimeDelta transport_rtt;
   EXPECT_FALSE(estimator.GetTransportRTT());
   EXPECT_FALSE(
@@ -397,8 +401,10 @@
 
   // Both RTT and downstream throughput should be updated.
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
   EXPECT_NE(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             estimator.GetEffectiveConnectionType());
   EXPECT_FALSE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
@@ -504,8 +510,10 @@
 
   // Both RTT and downstream throughput should be updated.
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
   EXPECT_NE(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             estimator.GetEffectiveConnectionType());
   EXPECT_FALSE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
@@ -692,12 +700,14 @@
   // Default estimates should be available.
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(115), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(55), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(1961, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   estimator.AddEffectiveConnectionTypeObserver(
       &effective_connection_type_observer);
@@ -712,12 +722,14 @@
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   // Taken from network_quality_estimator_params.cc.
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(272), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(209), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(749, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   EXPECT_NE(EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
             estimator.GetEffectiveConnectionType());
@@ -788,24 +800,28 @@
 
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(500), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(100, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   // Simulate network change to Wi-Fi.
   estimator.SimulateNetworkChange(
       NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI, "test-1");
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(2000), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(1000), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(200, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   // Peak network quality should not be affected by the network quality
   // estimator field trial.
@@ -821,24 +837,28 @@
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   // Taken from network_quality_estimator_params.cc.
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(1726), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(1531), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(300, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   // Simulate network change to 3G. Default estimates should be available.
   estimator.SimulateNetworkChange(
       NetworkChangeNotifier::ConnectionType::CONNECTION_3G, "test-3");
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(272), rtt);
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(base::TimeDelta::FromMilliseconds(209), rtt);
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
   EXPECT_EQ(749, kbps);
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 }
 
 TEST(NetworkQualityEstimatorTest, ObtainAlgorithmToUseFromParams) {
@@ -1533,10 +1553,12 @@
   base::TimeDelta rtt;
   int32_t kbps;
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_FALSE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_FALSE(estimator.GetTransportRTT());
   EXPECT_TRUE(
       estimator.GetRecentDownlinkThroughputKbps(base::TimeTicks(), &kbps));
+  EXPECT_EQ(kbps, estimator.GetDownstreamThroughputKbps().value());
 
   histogram_tester.ExpectTotalCount("NQE.ExternalEstimateProviderStatus", 5);
 
@@ -2168,6 +2190,7 @@
   EXPECT_EQ(0U, rtt_observer.observations().size());
   base::TimeDelta rtt;
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
+  EXPECT_EQ(rtt, estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
 
@@ -2200,6 +2223,7 @@
         << i;
   }
   EXPECT_TRUE(estimator.GetRecentHttpRTT(base::TimeTicks(), &rtt));
+  EXPECT_NE(nqe::internal::InvalidRTT(), estimator.GetHttpRTT().value());
   EXPECT_TRUE(estimator.GetRecentTransportRTT(base::TimeTicks(), &rtt));
   EXPECT_EQ(rtt, estimator.GetTransportRTT().value());
 
diff --git a/net/nqe/network_quality_provider.cc b/net/nqe/network_quality_provider.cc
new file mode 100644
index 0000000..030e0d8
--- /dev/null
+++ b/net/nqe/network_quality_provider.cc
@@ -0,0 +1,23 @@
+// 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 "net/nqe/network_quality_provider.h"
+
+namespace net {
+
+base::Optional<base::TimeDelta> NetworkQualityProvider::GetHttpRTT() const {
+  return base::Optional<base::TimeDelta>();
+}
+
+base::Optional<base::TimeDelta> NetworkQualityProvider::GetTransportRTT()
+    const {
+  return base::Optional<base::TimeDelta>();
+}
+
+base::Optional<int32_t> NetworkQualityProvider::GetDownstreamThroughputKbps()
+    const {
+  return base::Optional<int32_t>();
+}
+
+}  // namespace net
\ No newline at end of file
diff --git a/net/nqe/network_quality_provider.h b/net/nqe/network_quality_provider.h
new file mode 100644
index 0000000..47eca71
--- /dev/null
+++ b/net/nqe/network_quality_provider.h
@@ -0,0 +1,81 @@
+// 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 NET_NQE_NETWORK_QUALITY_PROVIDER_H_
+#define NET_NQE_NETWORK_QUALITY_PROVIDER_H_
+
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+#include "net/nqe/effective_connection_type.h"
+
+namespace net {
+
+class EffectiveConnectionTypeObserver;
+class RTTAndThroughputEstimatesObserver;
+
+// Provides simple interface to obtain the network quality, and to listen to
+// the changes in the network quality.
+class NET_EXPORT NetworkQualityProvider {
+ public:
+  virtual ~NetworkQualityProvider() {}
+
+  // Returns the current effective connection type.  The effective connection
+  // type is computed by the network quality estimator at regular intervals and
+  // at certain events (e.g., connection change).
+  virtual EffectiveConnectionType GetEffectiveConnectionType() const = 0;
+
+  // Adds |observer| to a list of effective connection type observers.
+  // The observer must register and unregister itself on the same thread.
+  // |observer| would be notified on the thread on which it registered.
+  // |observer| would be notified of the current effective connection
+  // type in the next message pump.
+  virtual void AddEffectiveConnectionTypeObserver(
+      EffectiveConnectionTypeObserver* observer) {}
+
+  // Removes |observer| from a list of effective connection type observers.
+  virtual void RemoveEffectiveConnectionTypeObserver(
+      EffectiveConnectionTypeObserver* observer) {}
+
+  // Returns the current HTTP RTT estimate. If the estimate is unavailable,
+  // the returned optional value is null.
+  virtual base::Optional<base::TimeDelta> GetHttpRTT() const;
+
+  // Returns the current transport RTT estimate. If the estimate is
+  // unavailable, the returned optional value is null.
+  virtual base::Optional<base::TimeDelta> GetTransportRTT() const;
+
+  // Returns the current downstream throughput estimate (in kilobits per
+  // second). If the estimate is unavailable, the returned optional value is
+  // null.
+  virtual base::Optional<int32_t> GetDownstreamThroughputKbps() const;
+
+  // Adds |observer| to the list of RTT and throughput estimate observers.
+  // The observer must register and unregister itself on the same thread.
+  // |observer| would be notified on the thread on which it registered.
+  // |observer| would be notified of the current values in the next message
+  // pump.
+  virtual void AddRTTAndThroughputEstimatesObserver(
+      RTTAndThroughputEstimatesObserver* observer) {}
+
+  // Removes |observer| from the list of RTT and throughput estimate
+  // observers.
+  virtual void RemoveRTTAndThroughputEstimatesObserver(
+      RTTAndThroughputEstimatesObserver* observer) {}
+
+ protected:
+  NetworkQualityProvider() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NetworkQualityProvider);
+};
+
+}  // namespace net
+
+#endif  // NET_NQE_NETWORK_QUALITY_PROVIDER_H_
\ No newline at end of file
diff --git a/net/nqe/rtt_throughput_estimates_observer.h b/net/nqe/rtt_throughput_estimates_observer.h
new file mode 100644
index 0000000..26c77bc
--- /dev/null
+++ b/net/nqe/rtt_throughput_estimates_observer.h
@@ -0,0 +1,48 @@
+// 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 NET_NQE_NETWORK_QUALITY_RTT_THROUGHPUT_ESTIMATES_OBSERVER_H_
+#define NET_NQE_NETWORK_QUALITY_RTT_THROUGHPUT_ESTIMATES_OBSERVER_H_
+
+#include <stdint.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// Observes changes in the network quality.
+class NET_EXPORT RTTAndThroughputEstimatesObserver {
+ public:
+  // Notifies the observer when estimated HTTP RTT, estimated transport RTT or
+  // estimated downstream throughput is computed. NetworkQualityEstimator
+  // computes the RTT and throughput estimates at regular intervals.
+  // Additionally, when there is a change in the connection type of the
+  // device, then the estimates are immediately computed.
+  //
+  // |http_rtt|, |transport_rtt| and |downstream_throughput_kbps| are the
+  // computed estimates of the HTTP RTT, transport RTT and downstream
+  // throughput (in kilobits per second), respectively. If an estimate of the
+  // HTTP or transport RTT is unavailable, it will be set to
+  // nqe::internal::InvalidRTT(). If the throughput estimate is unavailable,
+  // it will be set to nqe::internal::kInvalidThroughput.
+  virtual void OnRTTOrThroughputEstimatesComputed(
+      base::TimeDelta http_rtt,
+      base::TimeDelta transport_rtt,
+      int32_t downstream_throughput_kbps) = 0;
+
+  virtual ~RTTAndThroughputEstimatesObserver() {}
+
+ protected:
+  RTTAndThroughputEstimatesObserver() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RTTAndThroughputEstimatesObserver);
+};
+
+}  // namespace net
+
+#endif  // NET_NQE_NETWORK_QUALITY_RTT_THROUGHPUT_ESTIMATES_OBSERVER_H_
\ No newline at end of file
diff --git a/net/spdy/chromium/spdy_network_transaction_unittest.cc b/net/spdy/chromium/spdy_network_transaction_unittest.cc
index 3c5183e..0e924f3 100644
--- a/net/spdy/chromium/spdy_network_transaction_unittest.cc
+++ b/net/spdy/chromium/spdy_network_transaction_unittest.cc
@@ -2296,161 +2296,165 @@
   EXPECT_TRUE(data.AllWriteDataConsumed());
 }
 
-// Send a spdy request to www.example.org that gets redirected to www.foo.com.
-TEST_F(SpdyNetworkTransactionTest, DISABLED_RedirectGetRequest) {
-  SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
-  headers["user-agent"] = "";
-  headers["accept-encoding"] = "gzip, deflate";
+TEST_F(SpdyNetworkTransactionTest, RedirectGetRequest) {
+  SpdyURLRequestContext spdy_url_request_context;
 
-  // Setup writes/reads to www.example.org
-  SpdySerializedFrame req(
-      spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
-  SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReplyRedirect(1));
-  MockWrite writes[] = {
-      CreateMockWrite(req, 1),
-  };
-  MockRead reads[] = {
-      CreateMockRead(resp, 2), MockRead(ASYNC, 0, 0, 3)  // EOF
-  };
-  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
+  SSLSocketDataProvider ssl_provider0(ASYNC, OK);
+  ssl_provider0.next_proto = kProtoHTTP2;
+  spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
+      &ssl_provider0);
 
-  // Setup writes/reads to www.foo.com
-  SpdyHeaderBlock headers2(
-      spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
-  headers2["user-agent"] = "";
-  headers2["accept-encoding"] = "gzip, deflate";
-  SpdySerializedFrame req2(
-      spdy_util_.ConstructSpdyHeaders(1, std::move(headers2), LOWEST, true));
-  MockWrite writes2[] = {
-      CreateMockWrite(req2, 1),
-  };
+  SpdyHeaderBlock headers0(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+  headers0["user-agent"] = "";
+  headers0["accept-encoding"] = "gzip, deflate";
 
-  SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
-  SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
-  MockRead reads2[] = {
-      CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
-      MockRead(ASYNC, 0, 0, 4)  // EOF
-  };
+  SpdySerializedFrame req0(
+      spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
+  MockWrite writes0[] = {CreateMockWrite(req0, 0)};
 
-  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
-                            arraysize(writes2));
+  const char* const kExtraHeaders[] = {"location",
+                                       "https://www.foo.com/index.php"};
+  SpdySerializedFrame resp0(spdy_util_.ConstructSpdyReplyError(
+      "301", kExtraHeaders, arraysize(kExtraHeaders) / 2, 1));
+  MockRead reads0[] = {CreateMockRead(resp0, 1), MockRead(ASYNC, 0, 2)};
 
-  // TODO(erikchen): Make test support SPDYSSL, SPDYNPN
-  TestDelegate d;
-  {
-    SpdyURLRequestContext spdy_url_request_context;
-    std::unique_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
-        default_url_, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
-    spdy_url_request_context.socket_factory().
-        AddSocketDataProvider(&data);
-    spdy_url_request_context.socket_factory().
-        AddSocketDataProvider(&data2);
+  SequencedSocketData data0(reads0, arraysize(reads0), writes0,
+                            arraysize(writes0));
+  spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
 
-    d.set_quit_on_redirect(true);
-    r->Start();
-    base::RunLoop().Run();
+  SSLSocketDataProvider ssl_provider1(ASYNC, OK);
+  ssl_provider1.next_proto = kProtoHTTP2;
+  spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
+      &ssl_provider1);
 
-    EXPECT_EQ(1, d.received_redirect_count());
+  SpdyTestUtil spdy_util1;
+  SpdyHeaderBlock headers1(
+      spdy_util1.ConstructGetHeaderBlock("https://www.foo.com/index.php"));
+  headers1["user-agent"] = "";
+  headers1["accept-encoding"] = "gzip, deflate";
+  SpdySerializedFrame req1(
+      spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
+  MockWrite writes1[] = {CreateMockWrite(req1, 0)};
 
-    r->FollowDeferredRedirect();
-    base::RunLoop().Run();
-    EXPECT_EQ(1, d.response_started_count());
-    EXPECT_FALSE(d.received_data_before_response());
-    EXPECT_EQ(OK, d.request_status());
-    SpdyString contents("hello!");
-    EXPECT_EQ(contents, d.data_received());
-  }
-  EXPECT_TRUE(data.AllReadDataConsumed());
-  EXPECT_TRUE(data.AllWriteDataConsumed());
-  EXPECT_TRUE(data2.AllReadDataConsumed());
-  EXPECT_TRUE(data2.AllWriteDataConsumed());
+  SpdySerializedFrame resp1(spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
+  SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
+  MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
+                       MockRead(ASYNC, 0, 3)};
+
+  SequencedSocketData data1(reads1, arraysize(reads1), writes1,
+                            arraysize(writes1));
+  spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
+
+  TestDelegate delegate;
+  delegate.set_quit_on_redirect(true);
+
+  std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
+      default_url_, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
+  request->Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(1, delegate.received_redirect_count());
+
+  request->FollowDeferredRedirect();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(1, delegate.response_started_count());
+  EXPECT_FALSE(delegate.received_data_before_response());
+  EXPECT_THAT(delegate.request_status(), IsOk());
+  EXPECT_EQ("hello!", delegate.data_received());
+
+  EXPECT_TRUE(data0.AllReadDataConsumed());
+  EXPECT_TRUE(data0.AllWriteDataConsumed());
+  EXPECT_TRUE(data1.AllReadDataConsumed());
+  EXPECT_TRUE(data1.AllWriteDataConsumed());
 }
 
-// Send a spdy request to www.example.org. Get a pushed stream that redirects to
-// www.foo.com.
-TEST_F(SpdyNetworkTransactionTest, DISABLED_RedirectServerPush) {
-  SpdyHeaderBlock headers(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
-  headers["user-agent"] = "";
-  headers["accept-encoding"] = "gzip, deflate";
+TEST_F(SpdyNetworkTransactionTest, RedirectServerPush) {
+  const char url[] = "https://www.example.org/foo.dat";
+  const char redirected_url[] = "https://www.foo.com/index.php";
+  SpdyURLRequestContext spdy_url_request_context;
 
-  // Setup writes/reads to www.example.org
-  SpdySerializedFrame req(
-      spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
-  SpdySerializedFrame resp(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
-  SpdySerializedFrame rep(spdy_util_.ConstructSpdyPush(
-      nullptr, 0, 2, 1, GetDefaultUrlWithPath("/foo.dat").c_str(),
-      "301 Moved Permanently", "http://www.foo.com/index.php"));
-  SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+  SSLSocketDataProvider ssl_provider0(ASYNC, OK);
+  ssl_provider0.next_proto = kProtoHTTP2;
+  ssl_provider0.cert =
+      ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
+  spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
+      &ssl_provider0);
+
+  SpdyHeaderBlock headers0(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
+  headers0["user-agent"] = "";
+  headers0["accept-encoding"] = "gzip, deflate";
+  SpdySerializedFrame req0(
+      spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
+  SpdySerializedFrame priority(
+      spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
   SpdySerializedFrame rst(
       spdy_util_.ConstructSpdyRstStream(2, ERROR_CODE_CANCEL));
-  MockWrite writes[] = {
-      CreateMockWrite(req, 1), CreateMockWrite(rst, 6),
-  };
-  MockRead reads[] = {
-      CreateMockRead(resp, 2), CreateMockRead(rep, 3), CreateMockRead(body, 4),
-      MockRead(ASYNC, ERR_IO_PENDING, 5),  // Force a pause
-      MockRead(ASYNC, 0, 0, 7)             // EOF
-  };
+  MockWrite writes[] = {CreateMockWrite(req0, 0), CreateMockWrite(priority, 3),
+                        CreateMockWrite(rst, 5)};
 
-  // Setup writes/reads to www.foo.com
-  SpdyHeaderBlock headers2(
-      spdy_util_.ConstructGetHeaderBlock("http://www.foo.com/index.php"));
-  headers2["user-agent"] = "";
-  headers2["accept-encoding"] = "gzip, deflate";
-  SpdySerializedFrame req2(
-      spdy_util_.ConstructSpdyHeaders(1, std::move(headers2), LOWEST, true));
-  SpdySerializedFrame resp2(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
-  SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
-  MockWrite writes2[] = {
-      CreateMockWrite(req2, 1),
-  };
-  MockRead reads2[] = {
-      CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
-      MockRead(ASYNC, 0, 0, 5)  // EOF
-  };
-  SequencedSocketData data(reads, arraysize(reads), writes, arraysize(writes));
-  SequencedSocketData data2(reads2, arraysize(reads2), writes2,
-                            arraysize(writes2));
+  SpdySerializedFrame resp0(spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+  SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url,
+                                                        "301", redirected_url));
+  SpdySerializedFrame body0(spdy_util_.ConstructSpdyDataFrame(1, true));
+  MockRead reads[] = {CreateMockRead(resp0, 1), CreateMockRead(push, 2),
+                      CreateMockRead(body0, 4), MockRead(ASYNC, 0, 6)};
 
-  TestDelegate d;
-  TestDelegate d2;
-  SpdyURLRequestContext spdy_url_request_context;
-  {
-    std::unique_ptr<URLRequest> r(spdy_url_request_context.CreateRequest(
-        default_url_, DEFAULT_PRIORITY, &d, TRAFFIC_ANNOTATION_FOR_TESTS));
-    spdy_url_request_context.socket_factory().
-        AddSocketDataProvider(&data);
+  SequencedSocketData data0(reads, arraysize(reads), writes, arraysize(writes));
+  spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
 
-    r->Start();
-    base::RunLoop().Run();
+  SSLSocketDataProvider ssl_provider1(ASYNC, OK);
+  ssl_provider1.next_proto = kProtoHTTP2;
+  spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
+      &ssl_provider1);
 
-    EXPECT_EQ(0, d.received_redirect_count());
-    SpdyString contents("hello!");
-    EXPECT_EQ(contents, d.data_received());
+  SpdyTestUtil spdy_util1;
+  SpdyHeaderBlock headers1(spdy_util1.ConstructGetHeaderBlock(redirected_url));
+  headers1["user-agent"] = "";
+  headers1["accept-encoding"] = "gzip, deflate";
+  SpdySerializedFrame req1(
+      spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
+  MockWrite writes1[] = {CreateMockWrite(req1, 0)};
 
-    std::unique_ptr<URLRequest> r2(spdy_url_request_context.CreateRequest(
-        GURL(GetDefaultUrlWithPath("/foo.dat")), DEFAULT_PRIORITY, &d2,
-        TRAFFIC_ANNOTATION_FOR_TESTS));
-    spdy_url_request_context.socket_factory().
-        AddSocketDataProvider(&data2);
+  SpdySerializedFrame resp1(spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
+  SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
+  MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
+                       MockRead(ASYNC, 0, 3)};
 
-    d2.set_quit_on_redirect(true);
-    r2->Start();
-    base::RunLoop().Run();
-    EXPECT_EQ(1, d2.received_redirect_count());
+  SequencedSocketData data1(reads1, arraysize(reads1), writes1,
+                            arraysize(writes1));
+  spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
 
-    r2->FollowDeferredRedirect();
-    base::RunLoop().Run();
-    EXPECT_EQ(1, d2.response_started_count());
-    EXPECT_FALSE(d2.received_data_before_response());
-    EXPECT_EQ(OK, d2.request_status());
-    SpdyString contents2("hello!");
-    EXPECT_EQ(contents2, d2.data_received());
-  }
-  EXPECT_TRUE(data.AllReadDataConsumed());
-  EXPECT_TRUE(data.AllWriteDataConsumed());
-  EXPECT_TRUE(data2.AllReadDataConsumed());
-  EXPECT_TRUE(data2.AllWriteDataConsumed());
+  TestDelegate delegate0;
+  std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
+      default_url_, DEFAULT_PRIORITY, &delegate0, TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  request->Start();
+  base::RunLoop().Run();
+
+  EXPECT_EQ(0, delegate0.received_redirect_count());
+  EXPECT_EQ("hello!", delegate0.data_received());
+
+  TestDelegate delegate1;
+  std::unique_ptr<URLRequest> request1 = spdy_url_request_context.CreateRequest(
+      GURL(url), DEFAULT_PRIORITY, &delegate1, TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  delegate1.set_quit_on_redirect(true);
+  request1->Start();
+  base::RunLoop().Run();
+  EXPECT_EQ(1, delegate1.received_redirect_count());
+
+  request1->FollowDeferredRedirect();
+  base::RunLoop().Run();
+  EXPECT_EQ(1, delegate1.response_started_count());
+  EXPECT_FALSE(delegate1.received_data_before_response());
+  EXPECT_EQ(OK, delegate1.request_status());
+  EXPECT_EQ("hello!", delegate1.data_received());
+
+  EXPECT_TRUE(data0.AllReadDataConsumed());
+  EXPECT_TRUE(data0.AllWriteDataConsumed());
+  EXPECT_TRUE(data1.AllReadDataConsumed());
+  EXPECT_TRUE(data1.AllWriteDataConsumed());
 }
 
 TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
diff --git a/net/spdy/chromium/spdy_test_util_common.cc b/net/spdy/chromium/spdy_test_util_common.cc
index d8b106e..28c42764e 100644
--- a/net/spdy/chromium/spdy_test_util_common.cc
+++ b/net/spdy/chromium/spdy_test_util_common.cc
@@ -1026,14 +1026,6 @@
   return ConstructSpdyReply(stream_id, std::move(block));
 }
 
-SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReplyRedirect(int stream_id) {
-  static const char* const kExtraHeaders[] = {
-    "location", "http://www.foo.com/index.php",
-  };
-  return ConstructSpdyReplyError("301", kExtraHeaders,
-                                 arraysize(kExtraHeaders) / 2, stream_id);
-}
-
 SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(int stream_id) {
   return ConstructSpdyReplyError("500", NULL, 0, 1);
 }
diff --git a/net/spdy/chromium/spdy_test_util_common.h b/net/spdy/chromium/spdy_test_util_common.h
index 31aa8e7..be5f429 100644
--- a/net/spdy/chromium/spdy_test_util_common.h
+++ b/net/spdy/chromium/spdy_test_util_common.h
@@ -439,12 +439,6 @@
                                             int extra_header_count,
                                             int stream_id);
 
-  // Constructs a standard SPDY HEADERS frame to match the SPDY GET.
-  // |extra_headers| are the extra header-value pairs, which typically
-  // will vary the most between calls.
-  // Returns a SpdySerializedFrame.
-  SpdySerializedFrame ConstructSpdyGetReplyRedirect(int stream_id);
-
   // Constructs a standard SPDY HEADERS frame with an Internal Server
   // Error status code.
   // Returns a SpdySerializedFrame.
diff --git a/remoting/host/setup/start_host_main.cc b/remoting/host/setup/start_host_main.cc
index 4c0d14b5..df74f6d1 100644
--- a/remoting/host/setup/start_host_main.cc
+++ b/remoting/host/setup/start_host_main.cc
@@ -157,16 +157,21 @@
   }
 #endif  // defined(OS_WIN)
 
-  if (host_name.empty()) {
+  if (command_line->HasSwitch("help") || command_line->HasSwitch("h") ||
+      command_line->HasSwitch("?") || !command_line->GetArgs().empty()) {
     fprintf(stderr,
-            "Usage: %s --name=<hostname> [--code=<auth-code>] [--pin=<PIN>] "
+            "Usage: %s [--name=<hostname>] [--code=<auth-code>] [--pin=<PIN>] "
             "[--redirect-url=<redirectURL>]\n",
             argv[0]);
-    fprintf(stderr, "\nAuthorization URL for Production services:\n");
-    fprintf(stderr, "%s\n", GetAuthorizationCodeUri().c_str());
     return 1;
   }
 
+  if (host_name.empty()) {
+    fprintf(stdout, "Enter a name for this computer: ");
+    fflush(stdout);
+    host_name = ReadString(false);
+  }
+
   if (host_pin.empty()) {
     while (true) {
       fprintf(stdout, "Enter a PIN of at least six digits: ");
@@ -197,6 +202,8 @@
   }
 
   if (auth_code.empty()) {
+    fprintf(stdout, "\nAuthorization URL for Production services:\n");
+    fprintf(stdout, "%s\n\n", GetAuthorizationCodeUri().c_str());
     fprintf(stdout, "Enter an authorization code: ");
     fflush(stdout);
     auth_code = ReadString(true);
diff --git a/remoting/ios/app/BUILD.gn b/remoting/ios/app/BUILD.gn
index 81be7b3..02c5963 100644
--- a/remoting/ios/app/BUILD.gn
+++ b/remoting/ios/app/BUILD.gn
@@ -22,6 +22,8 @@
     "app_delegate.mm",
     "client_connection_view_controller.h",
     "client_connection_view_controller.mm",
+    "host_collection_header_view.h",
+    "host_collection_header_view.mm",
     "host_collection_view_cell.h",
     "host_collection_view_cell.mm",
     "host_collection_view_controller.h",
diff --git a/remoting/ios/app/host_collection_header_view.h b/remoting/ios/app/host_collection_header_view.h
new file mode 100644
index 0000000..b8ad19f
--- /dev/null
+++ b/remoting/ios/app/host_collection_header_view.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 REMOTING_IOS_APP_HOST_COLLECTION_HEADER_VIEW_H_
+#define REMOTING_IOS_APP_HOST_COLLECTION_HEADER_VIEW_H_
+
+#import <UIKit/UIKit.h>
+
+// A simple view that displays a white text label on the collection view.
+@interface HostCollectionHeaderView : UICollectionReusableView
+@property(nonatomic) NSString* text;
+@end
+
+#endif  // REMOTING_IOS_APP_HOST_COLLECTION_HEADER_VIEW_H_
diff --git a/remoting/ios/app/host_collection_header_view.mm b/remoting/ios/app/host_collection_header_view.mm
new file mode 100644
index 0000000..565642bd
--- /dev/null
+++ b/remoting/ios/app/host_collection_header_view.mm
@@ -0,0 +1,57 @@
+// 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.
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+#import "remoting/ios/app/host_collection_header_view.h"
+
+#import <UIKit/UIKit.h>
+
+#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
+
+// Applied on the left and right of the label.
+static const float kTitleMargin = 12.f;
+
+@interface HostCollectionHeaderView () {
+ @private
+  UILabel* _titleLabel;
+}
+@end
+
+@implementation HostCollectionHeaderView
+
+- (instancetype)initWithFrame:(CGRect)frame {
+  self = [super initWithFrame:frame];
+  if (self) {
+    _titleLabel = [[UILabel alloc] init];
+    _titleLabel.font = [MDCTypography body2Font];
+    _titleLabel.textColor = [UIColor whiteColor];
+    _titleLabel.backgroundColor = [UIColor clearColor];
+    _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
+    [self addSubview:_titleLabel];
+
+    [NSLayoutConstraint activateConstraints:@[
+      [[_titleLabel leadingAnchor] constraintEqualToAnchor:[self leadingAnchor]
+                                                  constant:kTitleMargin],
+      [[_titleLabel centerYAnchor]
+          constraintEqualToAnchor:[self centerYAnchor]],
+      [[_titleLabel trailingAnchor]
+          constraintEqualToAnchor:[self trailingAnchor]
+                         constant:-kTitleMargin],
+    ]];
+  }
+  return self;
+}
+
+- (NSString*)text {
+  return _titleLabel.text;
+}
+
+- (void)setText:(NSString*)text {
+  _titleLabel.text = text;
+}
+
+@end
diff --git a/remoting/ios/app/host_collection_view_controller.mm b/remoting/ios/app/host_collection_view_controller.mm
index 0fabb03..72945970 100644
--- a/remoting/ios/app/host_collection_view_controller.mm
+++ b/remoting/ios/app/host_collection_view_controller.mm
@@ -12,11 +12,13 @@
 #import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h"
 #import "ios/third_party/material_components_ios/src/components/ShadowElevations/src/MaterialShadowElevations.h"
 #import "ios/third_party/material_components_ios/src/components/ShadowLayer/src/MaterialShadowLayer.h"
+#import "remoting/ios/app/host_collection_header_view.h"
 
 static NSString* const kReusableIdentifierItem =
     @"remotingHostCollectionViewControllerItem";
 
 static CGFloat kHostCollectionViewControllerCellHeight = 70.f;
+static CGFloat kHostCollectionHeaderViewHeight = 25.f;
 
 @implementation HostCollectionViewController
 
@@ -31,6 +33,10 @@
     [self.collectionView registerClass:[HostCollectionViewCell class]
             forCellWithReuseIdentifier:NSStringFromClass(
                                            [HostCollectionViewCell class])];
+
+    [self.collectionView registerClass:[HostCollectionHeaderView class]
+            forSupplementaryViewOfKind:UICollectionElementKindSectionHeader
+                   withReuseIdentifier:UICollectionElementKindSectionHeader];
   }
   return self;
 }
@@ -39,7 +45,7 @@
 
 - (void)viewDidLoad {
   [super viewDidLoad];
-  self.styler.cellStyle = MDCCollectionViewCellStyleGrouped;
+  self.styler.cellStyle = MDCCollectionViewCellStyleDefault;
   self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList;
 }
 
@@ -74,6 +80,19 @@
   return cell;
 }
 
+- (UICollectionReusableView*)collectionView:(UICollectionView*)collectionView
+          viewForSupplementaryElementOfKind:(NSString*)kind
+                                atIndexPath:(NSIndexPath*)indexPath {
+  HostCollectionHeaderView* supplementaryView =
+      [collectionView dequeueReusableSupplementaryViewOfKind:kind
+                                         withReuseIdentifier:kind
+                                                forIndexPath:indexPath];
+  if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {
+    supplementaryView.text = @"Remote devices";
+  }
+  return supplementaryView;
+}
+
 #pragma mark - UICollectionViewDelegate
 
 - (void)collectionView:(UICollectionView*)collectionView
@@ -100,6 +119,16 @@
       scrollViewDidScroll:scrollView];
 }
 
+#pragma mark - UICollectionViewDelegateFlowLayout
+
+- (CGSize)collectionView:(UICollectionView*)collectionView
+                             layout:
+                                 (UICollectionViewLayout*)collectionViewLayout
+    referenceSizeForHeaderInSection:(NSInteger)section {
+  return CGSizeMake(collectionView.bounds.size.width,
+                    kHostCollectionHeaderViewHeight);
+}
+
 #pragma mark - Private
 
 - (void)setFlexHeaderContainerViewController:
diff --git a/remoting/ios/app/remoting_view_controller.mm b/remoting/ios/app/remoting_view_controller.mm
index d6e6e9c..268820b 100644
--- a/remoting/ios/app/remoting_view_controller.mm
+++ b/remoting/ios/app/remoting_view_controller.mm
@@ -68,23 +68,28 @@
     _appBar = [[MDCAppBar alloc] init];
     [self addChildViewController:_appBar.headerViewController];
 
-    _appBar.headerViewController.headerView.backgroundColor =
-        kChromotingBlueBackground;
-    _appBar.navigationBar.tintColor = [UIColor whiteColor];
+    self.navigationItem.title = @"Chrome Remote Desktop";
 
     UIBarButtonItem* menuButton =
-        [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"Settings"]
+        [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"ic_menu"]
                                          style:UIBarButtonItemStyleDone
                                         target:self
                                         action:@selector(didSelectSettings)];
     self.navigationItem.leftBarButtonItem = menuButton;
 
-    UIBarButtonItem* refreshButton =
-        [[UIBarButtonItem alloc] initWithTitle:@"Refresh"
-                                         style:UIBarButtonItemStyleDone
-                                        target:self
-                                        action:@selector(didSelectRefresh)];
+    UIBarButtonItem* refreshButton = [[UIBarButtonItem alloc]
+        initWithImage:[UIImage imageNamed:@"ic_refresh"]
+                style:UIBarButtonItemStyleDone
+               target:self
+               action:@selector(didSelectRefresh)];
     self.navigationItem.rightBarButtonItem = refreshButton;
+
+    _appBar.headerViewController.headerView.backgroundColor =
+        kChromotingBlueBackground;
+    _appBar.navigationBar.backgroundColor = kChromotingBlueBackground;
+    MDCNavigationBarTextColorAccessibilityMutator* mutator =
+        [[MDCNavigationBarTextColorAccessibilityMutator alloc] init];
+    [mutator mutate:_appBar.navigationBar];
   }
   return self;
 }
diff --git a/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json
index 486721f..85dc959 100644
--- a/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json
+++ b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json
@@ -9,10 +9,6 @@
       "idiom" : "universal",
       "filename" : "bkg1_2x.jpg",
       "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x"
     }
   ],
   "info" : {
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/Contents.json b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/Contents.json
new file mode 100644
index 0000000..29b2ae0
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "ic_menu_white.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "ic_menu_white_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "ic_menu_white_3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white.png b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white.png
new file mode 100644
index 0000000..d3cec056
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white.png
Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_2x.png b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_2x.png
new file mode 100644
index 0000000..193185fd
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_2x.png
Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_3x.png b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_3x.png
new file mode 100644
index 0000000..9cb03482
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_menu.imageset/ic_menu_white_3x.png
Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/Contents.json b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/Contents.json
new file mode 100644
index 0000000..47cd579
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "ic_refresh_white.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "ic_refresh_white_2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "ic_refresh_white_3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white.png b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white.png
new file mode 100644
index 0000000..97e42b5
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white.png
Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_2x.png b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_2x.png
new file mode 100644
index 0000000..1989184
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_2x.png
Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_3x.png b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_3x.png
new file mode 100644
index 0000000..a21d0ec
--- /dev/null
+++ b/remoting/ios/app/resources/Assets.xcassets/ic_refresh.imageset/ic_refresh_white_3x.png
Binary files differ
diff --git a/remoting/ios/app/resources/BUILD.gn b/remoting/ios/app/resources/BUILD.gn
index 5f15eb31c..a9916a3 100644
--- a/remoting/ios/app/resources/BUILD.gn
+++ b/remoting/ios/app/resources/BUILD.gn
@@ -8,6 +8,17 @@
 
 bundle_data("assets") {
   sources = [
+    "Assets.xcassets/Back.imageset/Contents.json",
+    "Assets.xcassets/Back.imageset/ic_keyboard_arrow_left_white_1x_ios_36dp.png",
+    "Assets.xcassets/Back.imageset/ic_keyboard_arrow_left_white_2x_ios_36dp.png",
+    "Assets.xcassets/Back.imageset/ic_keyboard_arrow_left_white_3x_ios_36dp.png",
+    "Assets.xcassets/Background.imageset/Contents.json",
+    "Assets.xcassets/Background.imageset/bkg1.jpg",
+    "Assets.xcassets/Background.imageset/bkg1_2x.jpg",
+    "Assets.xcassets/Settings.imageset/Contents.json",
+    "Assets.xcassets/Settings.imageset/ic_settings_white_1x_ios_24dp.png",
+    "Assets.xcassets/Settings.imageset/ic_settings_white_2x_ios_24dp.png",
+    "Assets.xcassets/Settings.imageset/ic_settings_white_3x_ios_24dp.png",
     "Assets.xcassets/ic_desktop.imageset/Contents.json",
     "Assets.xcassets/ic_desktop.imageset/ic_desktop.png",
     "Assets.xcassets/ic_desktop.imageset/ic_desktop@2x.png",
@@ -24,10 +35,18 @@
     "Assets.xcassets/ic_fullscreen_exit.imageset/ic_fullscreen_exit.png",
     "Assets.xcassets/ic_fullscreen_exit.imageset/ic_fullscreen_exit@2x.png",
     "Assets.xcassets/ic_fullscreen_exit.imageset/ic_fullscreen_exit@3x.png",
+    "Assets.xcassets/ic_menu.imageset/Contents.json",
+    "Assets.xcassets/ic_menu.imageset/ic_menu_white.png",
+    "Assets.xcassets/ic_menu.imageset/ic_menu_white_2x.png",
+    "Assets.xcassets/ic_menu.imageset/ic_menu_white_3x.png",
     "Assets.xcassets/ic_mouse.imageset/Contents.json",
     "Assets.xcassets/ic_mouse.imageset/ic_mouse.png",
     "Assets.xcassets/ic_mouse.imageset/ic_mouse@2x.png",
     "Assets.xcassets/ic_mouse.imageset/ic_mouse@3x.png",
+    "Assets.xcassets/ic_refresh.imageset/Contents.json",
+    "Assets.xcassets/ic_refresh.imageset/ic_refresh_white.png",
+    "Assets.xcassets/ic_refresh.imageset/ic_refresh_white_2x.png",
+    "Assets.xcassets/ic_refresh.imageset/ic_refresh_white_3x.png",
     "Assets.xcassets/ic_touch_app.imageset/Contents.json",
     "Assets.xcassets/ic_touch_app.imageset/ic_touch_app.png",
     "Assets.xcassets/ic_touch_app.imageset/ic_touch_app_2x.png",
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index 751e562..8be6504 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -46,8 +46,7 @@
       capture_window_(nullptr),
       capture_window_client_id_(kInvalidClientId),
       modal_window_controller_(this),
-      event_targeter_(
-          base::MakeUnique<EventTargeter>(this, &modal_window_controller_)),
+      event_targeter_(base::MakeUnique<EventTargeter>(this)),
       mouse_button_down_(false),
       mouse_cursor_source_window_(nullptr),
       mouse_cursor_in_non_client_area_(false) {}
@@ -82,8 +81,7 @@
     const gfx::Point& display_location,
     const int64_t display_id) {
   DCHECK(pointer_targets_.empty());
-  mouse_pointer_last_location_ = display_location;
-  mouse_pointer_display_id_ = display_id;
+  SetMousePointerLocation(display_location, display_id);
   UpdateCursorProviderByLastKnownLocation();
   // Write our initial location back to our shared screen coordinate. This
   // shouldn't cause problems because we already read the cursor before we
@@ -223,30 +221,34 @@
 
 void EventDispatcher::UpdateNonClientAreaForCurrentWindow() {
   if (mouse_cursor_source_window_) {
-    DeepestWindow deepest_window =
-        event_targeter_->FindDeepestVisibleWindowForEvents(
-            &mouse_pointer_last_location_, &mouse_pointer_display_id_);
-    if (deepest_window.window == mouse_cursor_source_window_) {
-      mouse_cursor_in_non_client_area_ = mouse_cursor_source_window_
-                                             ? deepest_window.in_non_client_area
-                                             : false;
+    LocationTarget location_target = event_targeter_->FindTargetForLocation(
+        mouse_pointer_last_location_, mouse_pointer_display_id_);
+    if (location_target.deepest_window.window == mouse_cursor_source_window_) {
+      mouse_cursor_in_non_client_area_ =
+          mouse_cursor_source_window_
+              ? location_target.deepest_window.in_non_client_area
+              : false;
     }
+    SetMousePointerLocation(location_target.location_in_root,
+                            location_target.display_id);
   }
 }
 
 void EventDispatcher::UpdateCursorProviderByLastKnownLocation() {
   if (!mouse_button_down_) {
-    DeepestWindow deepest_window =
-        event_targeter_->FindDeepestVisibleWindowForEvents(
-            &mouse_pointer_last_location_, &mouse_pointer_display_id_);
-    SetMouseCursorSourceWindow(deepest_window.window);
+    LocationTarget location_target = event_targeter_->FindTargetForLocation(
+        mouse_pointer_last_location_, mouse_pointer_display_id_);
+    SetMouseCursorSourceWindow(location_target.deepest_window.window);
     if (mouse_cursor_source_window_) {
-      mouse_cursor_in_non_client_area_ = deepest_window.in_non_client_area;
+      mouse_cursor_in_non_client_area_ =
+          location_target.deepest_window.in_non_client_area;
     } else {
       SetMouseCursorSourceWindow(delegate_->GetRootWindowContaining(
           &mouse_pointer_last_location_, &mouse_pointer_display_id_));
       mouse_cursor_in_non_client_area_ = true;
     }
+    SetMousePointerLocation(location_target.location_in_root,
+                            location_target.display_id);
   }
 }
 
@@ -333,6 +335,13 @@
     ObserveWindow(mouse_cursor_source_window_);
 }
 
+void EventDispatcher::SetMousePointerLocation(
+    const gfx::Point& new_mouse_location,
+    int64_t new_mouse_display_id) {
+  mouse_pointer_last_location_ = new_mouse_location;
+  mouse_pointer_display_id_ = new_mouse_display_id;
+}
+
 void EventDispatcher::ProcessKeyEvent(const ui::KeyEvent& event,
                                       AcceleratorMatchPhase match_phase) {
   Accelerator* post_target =
@@ -361,13 +370,33 @@
 
 void EventDispatcher::ProcessPointerEvent(const ui::PointerEvent& event) {
   DCHECK(event.IsPointerEvent());
+
+  PointerTarget pointer_target;
+  LocationTarget location_target = event_targeter_->FindTargetForLocation(
+      event.root_location(), event_display_id_);
+  pointer_target.window = modal_window_controller_.GetTargetForWindow(
+      location_target.deepest_window.window);
+  pointer_target.is_mouse_event = event.IsMousePointerEvent();
+  pointer_target.in_nonclient_area =
+      location_target.deepest_window.window != pointer_target.window ||
+      !pointer_target.window ||
+      location_target.deepest_window.in_non_client_area;
+  pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
+
+  std::unique_ptr<ui::Event> cloned_event = ui::Event::Clone(event);
+  if (location_target.display_id != event_display_id_) {
+    event_display_id_ = location_target.display_id;
+    cloned_event->AsLocatedEvent()->set_root_location(
+        location_target.location_in_root);
+  }
+
   const bool is_mouse_event = event.IsMousePointerEvent();
 
   if (is_mouse_event) {
-    mouse_pointer_last_location_ = event.root_location();
-    mouse_pointer_display_id_ = event_display_id_;
-    delegate_->OnMouseCursorLocationChanged(event.root_location(),
-                                            event_display_id_);
+    SetMousePointerLocation(location_target.location_in_root,
+                            location_target.display_id);
+    delegate_->OnMouseCursorLocationChanged(location_target.location_in_root,
+                                            location_target.display_id);
   }
 
   // Release capture on pointer up. For mouse we only release if there are
@@ -386,15 +415,15 @@
   }
 
   if (drag_controller_) {
-    const PointerTarget target =
-        event_targeter_->PointerTargetForEvent(event, &event_display_id_);
-    if (drag_controller_->DispatchPointerEvent(event, target.window))
+    if (drag_controller_->DispatchPointerEvent(*cloned_event->AsPointerEvent(),
+                                               pointer_target.window))
       return;
   }
 
   if (capture_window_) {
     SetMouseCursorSourceWindow(capture_window_);
-    DispatchToClient(capture_window_, capture_window_client_id_, event);
+    DispatchToClient(capture_window_, capture_window_client_id_,
+                     *cloned_event->AsPointerEvent());
     return;
   }
 
@@ -402,7 +431,8 @@
   if (!IsTrackingPointer(pointer_id) ||
       !pointer_targets_[pointer_id].is_pointer_down) {
     const bool any_pointers_down = AreAnyPointersDown();
-    UpdateTargetForPointer(pointer_id, event);
+    UpdateTargetForPointer(pointer_id, *cloned_event->AsPointerEvent(),
+                           pointer_target);
     if (is_mouse_event)
       SetMouseCursorSourceWindow(pointer_targets_[pointer_id].window);
 
@@ -415,7 +445,8 @@
           delegate_->SetFocusedWindowFromEventDispatcher(pointer_target.window);
         ServerWindow* capture_window = pointer_target.window;
         if (!capture_window) {
-          gfx::Point event_location = event.root_location();
+          gfx::Point event_location =
+              cloned_event->AsPointerEvent()->root_location();
           int64_t event_display_id = event_display_id_;
           capture_window = delegate_->GetRootWindowContaining(
               &event_location, &event_display_id);
@@ -433,7 +464,8 @@
   if (is_pointer_going_up && is_mouse_event)
     UpdateCursorProviderByLastKnownLocation();
 
-  DispatchToPointerTarget(pointer_targets_[pointer_id], event);
+  DispatchToPointerTarget(pointer_targets_[pointer_id],
+                          *cloned_event->AsPointerEvent());
 
   if (is_pointer_going_up) {
     if (is_mouse_event)
@@ -462,16 +494,15 @@
     UnobserveWindow(window);
 }
 
-void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id,
-                                             const ui::LocatedEvent& event) {
+void EventDispatcher::UpdateTargetForPointer(
+    int32_t pointer_id,
+    const ui::PointerEvent& event,
+    const PointerTarget& pointer_target) {
   if (!IsTrackingPointer(pointer_id)) {
-    StartTrackingPointer(pointer_id, event_targeter_->PointerTargetForEvent(
-                                         event, &event_display_id_));
+    StartTrackingPointer(pointer_id, pointer_target);
     return;
   }
 
-  const PointerTarget pointer_target =
-      event_targeter_->PointerTargetForEvent(event, &event_display_id_);
   if (pointer_target.window == pointer_targets_[pointer_id].window &&
       pointer_target.in_nonclient_area ==
           pointer_targets_[pointer_id].in_nonclient_area) {
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index 1da07968..8d075b2 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -158,8 +158,40 @@
  private:
   friend class test::EventDispatcherTestApi;
 
+  // Keeps track of state associated with an active pointer.
+  struct PointerTarget {
+    PointerTarget()
+        : window(nullptr),
+          is_mouse_event(false),
+          in_nonclient_area(false),
+          is_pointer_down(false) {}
+
+    // The target window, which may be null. null is used in two situations:
+    // when there is no valid window target, or there was a target but the
+    // window is destroyed before a corresponding release/cancel.
+    ServerWindow* window;
+
+    bool is_mouse_event;
+
+    // Did the pointer event start in the non-client area.
+    bool in_nonclient_area;
+
+    bool is_pointer_down;
+  };
+
   void SetMouseCursorSourceWindow(ServerWindow* window);
 
+  // Called after we found the target for the current mouse cursor to see if
+  // |mouse_pointer_last_location_| and |mouse_pointer_display_id_| need to be
+  // updated based on the new target we found. No need to call delegate's
+  // OnMouseCursorLocationChanged since mouse location is the same in
+  // screen-coord.
+  // TODO(riajiang): No need to update mouse location after ozone drm can tell
+  // us the right display the cursor is on for drag-n-drop events.
+  // crbug.com/726470
+  void SetMousePointerLocation(const gfx::Point& new_mouse_location,
+                               int64_t new_mouse_display_id);
+
   void ProcessKeyEvent(const ui::KeyEvent& event,
                        AcceleratorMatchPhase match_phase);
 
@@ -189,7 +221,8 @@
   // pointer sends the appropriate event to the delegate and updates the
   // currently tracked PointerTarget appropriately.
   void UpdateTargetForPointer(int32_t pointer_id,
-                              const ui::LocatedEvent& event);
+                              const ui::PointerEvent& event,
+                              const PointerTarget& pointer_target);
 
   // Returns true if any pointers are in the pressed/down state.
   bool AreAnyPointersDown() const;
diff --git a/services/ui/ws/event_targeter.cc b/services/ui/ws/event_targeter.cc
index 7e1f3a4..1fb3f79e 100644
--- a/services/ui/ws/event_targeter.cc
+++ b/services/ui/ws/event_targeter.cc
@@ -5,45 +5,28 @@
 #include "services/ui/ws/event_targeter.h"
 
 #include "services/ui/ws/event_targeter_delegate.h"
-#include "services/ui/ws/modal_window_controller.h"
-#include "services/ui/ws/window_finder.h"
-#include "ui/events/event.h"
-#include "ui/gfx/geometry/point.h"
 
 namespace ui {
 namespace ws {
 
-EventTargeter::EventTargeter(EventTargeterDelegate* event_targeter_delegate,
-                             ModalWindowController* modal_window_controller)
-    : event_targeter_delegate_(event_targeter_delegate),
-      modal_window_controller_(modal_window_controller) {}
+EventTargeter::EventTargeter(EventTargeterDelegate* event_targeter_delegate)
+    : event_targeter_delegate_(event_targeter_delegate) {}
 
 EventTargeter::~EventTargeter() {}
 
-PointerTarget EventTargeter::PointerTargetForEvent(
-    const ui::LocatedEvent& event,
-    int64_t* display_id) {
-  PointerTarget pointer_target;
-  gfx::Point event_root_location(event.root_location());
-  DeepestWindow deepest_window =
-      FindDeepestVisibleWindowForEvents(&event_root_location, display_id);
-  pointer_target.window =
-      modal_window_controller_->GetTargetForWindow(deepest_window.window);
-  pointer_target.is_mouse_event = event.IsMousePointerEvent();
-  pointer_target.in_nonclient_area =
-      deepest_window.window != pointer_target.window ||
-      !pointer_target.window || deepest_window.in_non_client_area;
-  pointer_target.is_pointer_down = event.type() == ui::ET_POINTER_DOWN;
-  return pointer_target;
-}
-
-DeepestWindow EventTargeter::FindDeepestVisibleWindowForEvents(
-    gfx::Point* location,
-    int64_t* display_id) {
-  ServerWindow* root =
-      event_targeter_delegate_->GetRootWindowContaining(location, display_id);
-  return root ? ui::ws::FindDeepestVisibleWindowForEvents(root, *location)
-              : DeepestWindow();
+LocationTarget EventTargeter::FindTargetForLocation(const gfx::Point& location,
+                                                    int64_t display_id) {
+  LocationTarget location_target;
+  location_target.location_in_root = location;
+  location_target.display_id = display_id;
+  ServerWindow* root = event_targeter_delegate_->GetRootWindowContaining(
+      &location_target.location_in_root, &location_target.display_id);
+  if (root) {
+    location_target.deepest_window =
+        ui::ws::FindDeepestVisibleWindowForLocation(
+            root, location_target.location_in_root);
+  }
+  return location_target;
 }
 
 }  // namespace ws
diff --git a/services/ui/ws/event_targeter.h b/services/ui/ws/event_targeter.h
index 91dfaf3..c71650a 100644
--- a/services/ui/ws/event_targeter.h
+++ b/services/ui/ws/event_targeter.h
@@ -8,62 +8,35 @@
 #include <stdint.h>
 
 #include "base/macros.h"
-
-namespace gfx {
-class Point;
-}
+#include "services/ui/ws/window_finder.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/gfx/geometry/point.h"
 
 namespace ui {
-class LocatedEvent;
-
 namespace ws {
-struct DeepestWindow;
 class EventTargeterDelegate;
-class ModalWindowController;
-class ServerWindow;
 
-// Keeps track of state associated with an active pointer.
-struct PointerTarget {
-  PointerTarget()
-      : window(nullptr),
-        is_mouse_event(false),
-        in_nonclient_area(false),
-        is_pointer_down(false) {}
-
-  // The target window, which may be null. null is used in two situations:
-  // when there is no valid window target, or there was a target but the
-  // window is destroyed before a corresponding release/cancel.
-  ServerWindow* window;
-
-  bool is_mouse_event;
-
-  // Did the pointer event start in the non-client area.
-  bool in_nonclient_area;
-
-  bool is_pointer_down;
+// The target |window| for a given location, |location| and |display_id| are
+// associated with the display |window| is on.
+struct LocationTarget {
+  DeepestWindow deepest_window;
+  gfx::Point location_in_root;
+  int64_t display_id = display::kInvalidDisplayId;
 };
 
-// Finds the PointerTarget for an event or the DeepestWindow for a location.
+// Finds the target window for a location.
 class EventTargeter {
  public:
-  EventTargeter(EventTargeterDelegate* event_targeter_delegate,
-                ModalWindowController* modal_window_controller);
+  explicit EventTargeter(EventTargeterDelegate* event_targeter_delegate);
   ~EventTargeter();
 
-  // Returns a PointerTarget for the supplied |event|. If there is no valid
-  // event target for the specified location |window| in the returned value is
-  // null.
-  PointerTarget PointerTargetForEvent(const ui::LocatedEvent& event,
-                                      int64_t* display_id);
-
-  // Returns a DeepestWindow for the supplied |location|. If there is no valid
+  // Returns a LocationTarget for the supplied |location|. If there is no valid
   // root window, |window| in the returned value is null.
-  DeepestWindow FindDeepestVisibleWindowForEvents(gfx::Point* location,
-                                                  int64_t* display_id);
+  LocationTarget FindTargetForLocation(const gfx::Point& location,
+                                       int64_t display_id);
 
  private:
   EventTargeterDelegate* event_targeter_delegate_;
-  ModalWindowController* modal_window_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(EventTargeter);
 };
diff --git a/services/ui/ws/window_finder.cc b/services/ui/ws/window_finder.cc
index fa2d95b..e16747a9 100644
--- a/services/ui/ws/window_finder.cc
+++ b/services/ui/ws/window_finder.cc
@@ -46,7 +46,7 @@
   return transform;
 }
 
-bool FindDeepestVisibleWindowForEventsImpl(
+bool FindDeepestVisibleWindowForLocationImpl(
     ServerWindow* window,
     const gfx::Point& location_in_root,
     const gfx::Point& location_in_window,
@@ -91,7 +91,7 @@
         continue;
       }
 
-      if (FindDeepestVisibleWindowForEventsImpl(
+      if (FindDeepestVisibleWindowForLocationImpl(
               child, location_in_root, location_in_child, child_transform,
               deepest_window)) {
         return true;
@@ -109,11 +109,11 @@
 
 }  // namespace
 
-DeepestWindow FindDeepestVisibleWindowForEvents(ServerWindow* root_window,
-                                                const gfx::Point& location) {
+DeepestWindow FindDeepestVisibleWindowForLocation(ServerWindow* root_window,
+                                                  const gfx::Point& location) {
   DeepestWindow result;
-  FindDeepestVisibleWindowForEventsImpl(root_window, location, location,
-                                        gfx::Transform(), &result);
+  FindDeepestVisibleWindowForLocationImpl(root_window, location, location,
+                                          gfx::Transform(), &result);
   return result;
 }
 
diff --git a/services/ui/ws/window_finder.h b/services/ui/ws/window_finder.h
index 9ea4d2bb..b467bdb 100644
--- a/services/ui/ws/window_finder.h
+++ b/services/ui/ws/window_finder.h
@@ -23,8 +23,8 @@
 // |location|. |location| is in the coordinate space of |root_window|. The
 // |window| field in the returned structure is set to the child window. If no
 // valid child window is found |window| is set to null.
-DeepestWindow FindDeepestVisibleWindowForEvents(ServerWindow* root_window,
-                                                const gfx::Point& location);
+DeepestWindow FindDeepestVisibleWindowForLocation(ServerWindow* root_window,
+                                                  const gfx::Point& location);
 
 }  // namespace ws
 }  // namespace ui
diff --git a/services/ui/ws/window_finder_unittest.cc b/services/ui/ws/window_finder_unittest.cc
index 3d5729c..da327b7 100644
--- a/services/ui/ws/window_finder_unittest.cc
+++ b/services/ui/ws/window_finder_unittest.cc
@@ -34,21 +34,21 @@
 
   EXPECT_EQ(
       &child2,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(16, 16)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(16, 16)).window);
 
   EXPECT_EQ(
       &child1,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(13, 14)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(13, 14)).window);
 
   child1.set_event_targeting_policy(mojom::EventTargetingPolicy::NONE);
   EXPECT_EQ(
       nullptr,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(13, 14)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(13, 14)).window);
 
   child2.set_extended_hit_test_region(gfx::Insets(10, 10, 10, 10));
   EXPECT_EQ(
       &child2,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(13, 14)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(13, 14)).window);
 }
 
 TEST(WindowFinderTest, FindDeepestVisibleWindowNonClientArea) {
@@ -64,35 +64,35 @@
   child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
 
   DeepestWindow result =
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(13, 14));
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(13, 14));
   EXPECT_EQ(&child1, result.window);
   EXPECT_FALSE(result.in_non_client_area);
 
-  result = FindDeepestVisibleWindowForEvents(&root, gfx::Point(11, 11));
+  result = FindDeepestVisibleWindowForLocation(&root, gfx::Point(11, 11));
   EXPECT_EQ(&child1, result.window);
   EXPECT_FALSE(result.in_non_client_area);
 
   // 11, 11 is over the non-client area.
   child1.SetClientArea(gfx::Insets(2, 3, 4, 5), std::vector<gfx::Rect>());
-  result = FindDeepestVisibleWindowForEvents(&root, gfx::Point(11, 11));
+  result = FindDeepestVisibleWindowForLocation(&root, gfx::Point(11, 11));
   EXPECT_EQ(&child1, result.window);
   EXPECT_TRUE(result.in_non_client_area);
 
   // 15, 15 is over the client area.
-  result = FindDeepestVisibleWindowForEvents(&root, gfx::Point(15, 15));
+  result = FindDeepestVisibleWindowForLocation(&root, gfx::Point(15, 15));
   EXPECT_EQ(&child1, result.window);
   EXPECT_FALSE(result.in_non_client_area);
 
   // EventTargetingPolicy::NONE should not impact the result for the
   // non-client area.
   child1.set_event_targeting_policy(mojom::EventTargetingPolicy::NONE);
-  result = FindDeepestVisibleWindowForEvents(&root, gfx::Point(11, 11));
+  result = FindDeepestVisibleWindowForLocation(&root, gfx::Point(11, 11));
   child1.SetClientArea(gfx::Insets(2, 3, 4, 5), std::vector<gfx::Rect>());
   EXPECT_EQ(&child1, result.window);
   EXPECT_TRUE(result.in_non_client_area);
 
   // EventTargetingPolicy::NONE means the client area won't be matched though.
-  result = FindDeepestVisibleWindowForEvents(&root, gfx::Point(15, 15));
+  result = FindDeepestVisibleWindowForLocation(&root, gfx::Point(15, 15));
   EXPECT_EQ(&root, result.window);
   EXPECT_FALSE(result.in_non_client_area);
 }
@@ -113,12 +113,12 @@
   // Test a point inside the window but outside the mask.
   EXPECT_EQ(
       &root,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(11, 11)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(11, 11)).window);
 
   // Test a point inside the window and inside the mask.
   EXPECT_EQ(
       &child_with_mask,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(15, 15)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(15, 15)).window);
 }
 
 TEST(WindowFinderTest, FindDeepestVisibleWindowOverNonTarget) {
@@ -145,7 +145,7 @@
   // target |child1| should be picked.
   EXPECT_EQ(
       &child1,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(16, 16)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(16, 16)).window);
 }
 
 TEST(WindowFinderTest, NonClientPreferredOverChild) {
@@ -170,8 +170,9 @@
   child_child.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
 
   // |child| was should be returned as the event is over the non-client area.
-  EXPECT_EQ(&child,
-            FindDeepestVisibleWindowForEvents(&root, gfx::Point(1, 1)).window);
+  EXPECT_EQ(
+      &child,
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(1, 1)).window);
 }
 
 TEST(WindowFinderTest, FindDeepestVisibleWindowWithTransform) {
@@ -192,16 +193,19 @@
 
   EXPECT_EQ(
       &child,
-      FindDeepestVisibleWindowForEvents(&root, gfx::Point(49, 49)).window);
-  EXPECT_EQ(nullptr,
-            FindDeepestVisibleWindowForEvents(&root, gfx::Point(9, 9)).window);
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(49, 49)).window);
+  EXPECT_EQ(
+      nullptr,
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(9, 9)).window);
 
   // Verify extended hit test with transform is picked up.
   child.set_extended_hit_test_region(gfx::Insets(2, 2, 2, 2));
-  EXPECT_EQ(&child,
-            FindDeepestVisibleWindowForEvents(&root, gfx::Point(7, 7)).window);
-  EXPECT_EQ(nullptr,
-            FindDeepestVisibleWindowForEvents(&root, gfx::Point(4, 4)).window);
+  EXPECT_EQ(
+      &child,
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(7, 7)).window);
+  EXPECT_EQ(
+      nullptr,
+      FindDeepestVisibleWindowForLocation(&root, gfx::Point(4, 4)).window);
 }
 
 }  // namespace ws
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index c4b5446..fcc0256 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1403,23 +1403,6 @@
             ]
         }
     ],
-    "MarkNonSecureAs": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "ios",
-                "linux",
-                "mac",
-                "win"
-            ],
-            "experiments": [
-                {
-                    "name": "show-non-secure-passwords-cc-ui"
-                }
-            ]
-        }
-    ],
     "MaterialDesignDownloads": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests
index 0d4a85c..4a63a45 100644
--- a/third_party/WebKit/LayoutTests/SlowTests
+++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -374,7 +374,7 @@
 crbug.com/660468 [ Linux ] storage/indexeddb/observer-frame.html [ Slow ]
 crbug.com/660468 [ Linux ] storage/indexeddb/observer-workers.html [ Slow ]
 
-crbug.com/660492 [ Linux ] storage/indexeddb/structured-clone.html [ Slow ]
+crbug.com/660492 storage/indexeddb/structured-clone.html [ Slow ]
 
 # Foreign fetch tests make many requests, and create multiple browsing contexts,
 # which can be very slow.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 5b0f43d9..74b6daf 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -995,7 +995,6 @@
 crbug.com/521858 [ Win7 ] http/tests/security/media-element-audio-source-node-same-origin.html [ Failure Pass ]
 crbug.com/521858 [ Win7 ] virtual/mojo-loading/http/tests/security/media-element-audio-source-node-same-origin.html [ Failure Pass ]
 crbug.com/521853 [ Win ] http/tests/inspector/search/sources-search-scope.html [ Failure Pass ]
-crbug.com/521853 [ Win ] virtual/mojo-loading/http/tests/inspector/search/sources-search-scope.html [ Failure Pass ]
 crbug.com/652536 fast/events/mouse-cursor-change-after-image-load.html [ Failure Pass ]
 crbug.com/520188 [ Win ] http/tests/local/fileapi/file-last-modified-after-delete.html [ Failure Pass ]
 crbug.com/520188 [ Win ] virtual/mojo-loading/http/tests/local/fileapi/file-last-modified-after-delete.html [ Failure Pass ]
@@ -2676,12 +2675,19 @@
 
 # Producing incorrect results due to crbug.com/729352
 # TODO(ccameron): Re-enable and re-baseline when fixed.
-crbug.com/729352 images/color-profile-background-image-cross-fade.html [ Pass Failure Crash Timeout ]
-crbug.com/729352 images/color-profile-background-image-space.html [ Pass Failure Crash Timeout ]
-crbug.com/729352 images/color-profile-group.html [ Pass Failure Crash Timeout ]
-crbug.com/729352 images/color-profile-layer-filter.html [ Pass Failure Crash Timeout ]
-crbug.com/729352 images/color-profile-svg.html [ Pass Failure Crash Timeout ]
-crbug.com/729352 images/color-profile-svg-fill-text.html [ Pass Failure Crash Timeout ]
+crbug.com/729352 images/color-profile-background-image-cross-fade.html [ Pass Failure ]
+crbug.com/729352 images/color-profile-background-image-space.html [ Pass Failure ]
+crbug.com/729352 images/color-profile-group.html [ Pass Failure ]
+crbug.com/729352 images/color-profile-layer-filter.html [ Pass Failure ]
+crbug.com/729352 images/color-profile-svg.html [ Pass Failure ]
+crbug.com/729352 images/color-profile-svg-fill-text.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-background-image-space.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-group.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-layer-filter.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-svg.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-svg-fill-text.html [ Pass Failure ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-clip.html [ Pass Failure Timeout ]
+crbug.com/729352 virtual/gpu-rasterization/images/color-profile-layer.html [ Pass Failure Timeout ]
 
 # TODO(chrishall): this is a temporary mediation step as part of the P0 issue crbug.com/657646
 # this is not meant to be here for more than a few days (from 2016-11-03 SYD)
@@ -2844,7 +2850,7 @@
 
 crbug.com/676229 [ Linux ] plugins/mouse-click-plugin-clears-selection.html [ Failure Pass ]
 
-crbug.com/678346 [ Win7 Debug ] fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ]
+crbug.com/678346 [ Debug ] fast/dom/shadow/selections-in-shadow.html [ Pass Timeout ]
 crbug.com/678346 [ Win7 Debug ] storage/indexeddb/index-cursor.html [ Pass Timeout ]
 crbug.com/678346 [ Win7 Debug ] storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ]
 crbug.com/678346 [ Win7 Debug ] storage/indexeddb/structured-clone.html [ Pass Timeout ]
@@ -2989,15 +2995,14 @@
 crbug.com/725455 [ Linux ] nfc/watch.html [ Failure Pass Timeout ]
 
 # Sheriff failures 2017-05-29
-crbug.com/727014 [ Linux ] external/wpt/IndexedDB/large-nested-cloning.html [ Pass Timeout ]
 crbug.com/727252 [ Win7 ] external/wpt/media-source/mediasource-endofstream.html [ Pass Timeout ]
 
 # Compositor worker tests are flaky, crashing and timing out
-crbug.com/727991 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/visual-update.html [ Pass Failure Timeout Crash ]
-crbug.com/728036 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/compositor-proxy-supports.html [ Pass Failure Timeout Crash ]
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-main-to-worker.html [ Pass Failure Timeout Crash ]
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/basic-plumbing-worker-to-main.html [ Pass Failure Timeout Crash ]
 crbug.com/727505 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/request-animation-frame.html [ Pass Failure Timeout Crash ]
+crbug.com/727991 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/visual-update.html [ Pass Failure Timeout Crash ]
+crbug.com/728036 [ Linux Mac Win ] virtual/threaded/fast/compositorworker/compositor-proxy-supports.html [ Pass Failure Timeout Crash ]
 
 crbug.com/729075 [ Mac10.11 Retina ] css3/blending/background-blend-mode-gif-color-2.html [ Failure Pass ]
 
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 965ebfb1..b269698 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -71,7 +71,9 @@
   {
     "prefix": "gpu-rasterization",
     "base": "images",
-    "args": ["--force-gpu-rasterization"]
+    "args": ["--force-gpu-rasterization",
+             "--enable-color-correct-rendering",
+             "--force-color-profile=srgb"]
   },
   {
     "prefix": "stable",
@@ -454,12 +456,12 @@
   {
     "prefix": "mojo-localstorage",
     "base": "external/wpt/webstorage",
-    "args": ["--mojo-local-storage"]
+    "args": ["--disable-mojo-local-storage"]
   },
   {
     "prefix": "mojo-localstorage",
     "base": "storage/domstorage/localstorage",
-    "args": ["--mojo-local-storage"]
+    "args": ["--disable-mojo-local-storage"]
   },
   {
     "prefix": "print_browser",
diff --git a/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-basic.html b/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-basic.html
new file mode 100644
index 0000000..db0cf986
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-basic.html
@@ -0,0 +1,71 @@
+<!doctype html>
+<script src="../resources/run-after-layout-and-paint.js"></script>
+<!-- Tests various permutations of active suggestion underlines in LTR and RTL
+     text. -->
+<div dir="rtl" style="float: right;">
+    <p>RTL</p>
+    <div id="markRtlAll" dir="rtl">abcdef</div>
+    <div id="markRtlAllThick">abcdef</div>
+    <div id="markRtlBeginning">abcdef</div>
+    <div id="markRtlAllExceptFirstAndLast">abcdef</div>
+    <div id="markRtlEnd">abcdef</div>
+    <div id="markRtlAcrossNodes"><div>abcdef<span>ghijkl</span></div><div>mnopqr</div></div>
+</div>
+
+<div style="float: left;">
+    <p>LTR</p>
+    <div id="markAll">abcdef</div>
+    <div id="markAllThick">abcdef</div>
+    <div id="markAllDifferentColors">abcdef</div>
+    <div id="markBeginning">abcdef</div>
+    <div id="markAllExceptFirstAndLast">abcdef</div>
+    <div id="markEnd">abcdef</div>
+    <div id="markNothingZero">abcdef</div>
+    <div id="markNothingEnd">abcdef</div>
+    <div id="markAcrossNodes"><div>abcdef<span>ghijkl</span></div><div>mnopqr</div></div>
+</div>
+
+<script>
+function highlightRange(elem, start, end, underlineColor, thick, backgroundColor) {
+    var range = document.createRange();
+    var textNode = elem.firstChild;
+    range.setStart(textNode, start);
+    range.setEnd(textNode, end);
+    if (typeof internals !== 'undefined')
+        internals.addActiveSuggestionMarker(range, underlineColor, thick, backgroundColor);
+};
+
+function highlightRangeSimple(elem, start, end) {
+    highlightRange(elem, start, end, 'orange', 'thin', 'lightBlue');
+};
+
+function highlightAcrossNodes(startNode, start, endNode, end) {
+    var range = document.createRange();
+    range.setStart(startNode, start);
+    range.setEnd(endNode, end);
+    if (typeof internals !== 'undefined')
+        internals.addActiveSuggestionMarker(range, 'orange', 'thin', 'lightBlue');
+};
+
+onload = runAfterLayoutAndPaint(function() {
+    highlightRangeSimple(markAll, 0, 6);
+    highlightRange(markAllThick, 0, 6, 'orange', 'thick', 'lightBlue');
+    highlightRange(markAllDifferentColors, 0, 6, 'purple', 'thick', 'lightYellow');
+    highlightRangeSimple(markBeginning, 0, 3);
+    highlightRangeSimple(markAllExceptFirstAndLast, 1, 5);
+    highlightRangeSimple(markEnd, 3, 6);
+    highlightRangeSimple(markNothingZero, 0, 0);
+    highlightRangeSimple(markNothingEnd, 6, 6);
+
+    highlightRangeSimple(markRtlAll, 0, 6);
+    highlightRange(markRtlAllThick, 0, 6, 'orange', 'thick', 'lightBlue');
+    highlightRangeSimple(markRtlBeginning, 0, 3);
+    highlightRangeSimple(markRtlAllExceptFirstAndLast, 1, 5);
+    highlightRangeSimple(markRtlEnd, 3, 6);
+
+    highlightAcrossNodes(markAcrossNodes.childNodes[0].firstChild, 3,
+        markAcrossNodes.childNodes[1].firstChild, 3);
+    highlightAcrossNodes(markRtlAcrossNodes.childNodes[0].firstChild, 3,
+        markRtlAcrossNodes.childNodes[1].firstChild, 3);
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-split.html b/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-split.html
new file mode 100644
index 0000000..e863ccb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/active-suggestion-marker-split.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<script src="../resources/run-after-layout-and-paint.js"></script>
+<!-- Text is injected after page load into the center of the initial text.
+  This results in an InlineTextBox with start() > 0, which allows testing
+  to make sure composition underlines are still painted in the right place. -->
+<div id="markSplit">abc def</div>
+<div id="markSplitTruncated" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 8em;">abcdefghi jklmnopqr</div>
+<script>
+function injectText(node, offset) {
+    var textNode = node.firstChild;
+    var replacementNode = textNode.splitText(offset);
+    var newTextNode = document.createTextNode(' xxx ');
+    node.insertBefore(newTextNode, replacementNode);
+}
+
+function highlightRange(node) {
+    var range = document.createRange();
+    var textNode = node.childNodes[2];
+    range.setStart(textNode, 0);
+    range.setEnd(textNode, 4);
+    if (typeof internals !== 'undefined')
+        internals.addActiveSuggestionMarker(range, 'orange', 'thin', 'lightBlue');
+}
+
+onload = runAfterLayoutAndPaint(function() {
+    injectText(markSplit, 3);
+    // TODO(wkorman): This ITB has start=1, end=3, truncation=USHRT_MAX, len=3.
+    // Validate that the actual painting behavior is what's expected.
+    highlightRange(markSplit);
+
+    injectText(markSplitTruncated, 9);
+    // TODO(wkorman): This ITB has start=1, end=9, truncation=3, len=9. Validate
+    // that the actual painting behavior is what's expected.
+    highlightRange(markSplitTruncated);
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
index ba85bd8..eb9918c8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/console-test.js
@@ -93,7 +93,7 @@
 
 InspectorTest.dumpConsoleMessagesIntoArray = function(printOriginatingCommand, dumpClassNames, formatter)
 {
-    Common.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Verbose);
+    Console.ConsoleViewFilter.levelFilterSetting().set(Console.ConsoleViewFilter.allLevelsFilterValue());
     formatter = formatter || InspectorTest.prepareConsoleMessageText;
     var result = [];
     InspectorTest.disableConsoleViewport();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
index 52f778e..c9fdcaf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
@@ -281,7 +281,7 @@
 {
     var regex = text ? new RegExp(text, "i") : null;
     InspectorTest.addResult("Filtering styles by: " + text);
-    UI.panels.elements._stylesWidget.onFilterChanged(regex);
+    UI.panels.elements._stylesWidget._onFilterChanged(regex);
 }
 
 InspectorTest.dumpRenderedMatchedStyles = function()
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test-expected.txt
index 371444b..4b6ffe13 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test-expected.txt
@@ -10,8 +10,25 @@
 Tests that console can filter messages by source.
 
 
+Running: dumpLevels
+All levels
+{
+    error : true
+    info : true
+    verbose : true
+    warning : true
+}
+Default levels
+{
+    error : true
+    info : true
+    verbose : false
+    warning : true
+}
+
 Running: beforeFilter
 beforeFilter
+Level menu: Default levels
 >console-filter-level-test.html:5 sample info
 >console-filter-level-test.html:6 sample log
 >console-filter-level-test.html:7 sample warning
@@ -27,7 +44,8 @@
 >'Should be always visible'
 >"Should be always visible"
 
-Running: verbose
+Running: allLevels
+Level menu: All levels
 >console-filter-level-test.html:5 sample info
 >console-filter-level-test.html:6 sample log
 >console-filter-level-test.html:7 sample warning
@@ -44,7 +62,8 @@
 >'Should be always visible'
 >"Should be always visible"
 
-Running: info
+Running: defaultLevels
+Level menu: Default levels
 >console-filter-level-test.html:5 sample info
 >console-filter-level-test.html:6 sample log
 >console-filter-level-test.html:7 sample warning
@@ -60,7 +79,23 @@
 >'Should be always visible'
 >"Should be always visible"
 
-Running: warning
+Running: verbose
+Level menu: Verbose only
+>console-filter-level-test.html:8 sample debug
+>'Should be always visible'
+>"Should be always visible"
+
+Running: info
+Level menu: Info only
+>console-filter-level-test.html:5 sample info
+>console-filter-level-test.html:6 sample log
+>console-filter-level-test.html:11 abc info
+>console-filter-level-test.html:12 def info
+>'Should be always visible'
+>"Should be always visible"
+
+Running: warningsAndErrors
+Level menu: Custom levels
 >console-filter-level-test.html:7 sample warning
 onload @ console-filter-level-test.html:7
 >console-filter-level-test.html:9 sample error
@@ -72,27 +107,18 @@
 >'Should be always visible'
 >"Should be always visible"
 
-Running: error
->console-filter-level-test.html:9 sample error
-onload @ console-filter-level-test.html:9
->'Should be always visible'
->"Should be always visible"
-
 Running: abcMessagePlain
->console-filter-level-test.html:11 abc info
->console-filter-level-test.html:14 abc warn
-onload @ console-filter-level-test.html:14
+Level menu: Verbose only
 >'Should be always visible'
 >"Should be always visible"
 
 Running: abcMessageRegex
->console-filter-level-test.html:11 abc info
->console-filter-level-test.html:14 abc warn
-onload @ console-filter-level-test.html:14
+Level menu: Verbose only
 >'Should be always visible'
 >"Should be always visible"
 
 Running: abcMessageRegexWarning
+Level menu: Warnings only
 >console-filter-level-test.html:14 abc warn
 onload @ console-filter-level-test.html:14
 >'Should be always visible'
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test.html b/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test.html
index 4226eb51..9ba4be2e 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-filter-level-test.html
@@ -29,13 +29,23 @@
 {
     function dumpVisibleMessages()
     {
-        var messages = Console.ConsoleView.instance()._visibleViewMessages;
+        var menuText = Console.ConsoleView.instance()._filter._levelMenuButton.text();
+        InspectorTest.addResult("Level menu: " + menuText);
 
+        var messages = Console.ConsoleView.instance()._visibleViewMessages;
         for (var i = 0; i < messages.length; i++)
             InspectorTest.addResult(">" + messages[i].toMessageElement().deepTextContent());
     }
 
     var testSuite = [
+        function dumpLevels(next) {
+            InspectorTest.addResult('All levels');
+            InspectorTest.addObject(Console.ConsoleViewFilter.allLevelsFilterValue());
+            InspectorTest.addResult('Default levels');
+            InspectorTest.addObject(Console.ConsoleViewFilter.defaultLevelsFilterValue());
+            next();
+        },
+
         function beforeFilter(next)
         {
             InspectorTest.addResult(arguments.callee.name);
@@ -43,37 +53,44 @@
             next();
         },
 
+        function allLevels(next)
+        {
+            Console.ConsoleViewFilter.levelFilterSetting().set(Console.ConsoleViewFilter.allLevelsFilterValue());
+            dumpVisibleMessages();
+            next();
+        },
+
+        function defaultLevels(next)
+        {
+            Console.ConsoleViewFilter.levelFilterSetting().set(Console.ConsoleViewFilter.defaultLevelsFilterValue());
+            dumpVisibleMessages();
+            next();
+        },
+
         function verbose(next)
         {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Verbose);
+            Console.ConsoleViewFilter.levelFilterSetting().set({verbose: true});
             dumpVisibleMessages();
             next();
         },
         
         function info(next)
         {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Info);
+            Console.ConsoleViewFilter.levelFilterSetting().set({'info': true});
             dumpVisibleMessages();
             next();
         },
 
-        function warning(next)
+        function warningsAndErrors(next)
         {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Warning);
+            Console.ConsoleViewFilter.levelFilterSetting().set({'warning': true, 'error': true});
             dumpVisibleMessages();
             next();
         },
-              
-        function error(next)
-        {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Error);
-            dumpVisibleMessages();
-            next();
-        },
-       
+
         function abcMessagePlain(next)
         {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Verbose);
+            Console.ConsoleViewFilter.levelFilterSetting().set({verbose: true});
             Console.ConsoleView.instance()._filter._textFilterUI.setValue("abc");
             Console.ConsoleView.instance()._filter._textFilterChanged();
             dumpVisibleMessages();
@@ -90,7 +107,7 @@
 
         function abcMessageRegexWarning(next)
         {
-            Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Warning);
+            Console.ConsoleViewFilter.levelFilterSetting().set({'warning': true});
             dumpVisibleMessages();
             next();
         }
diff --git a/third_party/WebKit/LayoutTests/inspector/console/console-tests.html b/third_party/WebKit/LayoutTests/inspector/console/console-tests.html
index 41f307f..d37c2d62 100644
--- a/third_party/WebKit/LayoutTests/inspector/console/console-tests.html
+++ b/third_party/WebKit/LayoutTests/inspector/console/console-tests.html
@@ -42,7 +42,7 @@
 
 function test()
 {
-    Common.settings.settingForTest('messageLevelFilters2').set(ConsoleModel.ConsoleMessage.MessageLevel.Verbose);
+    Console.ConsoleViewFilter.levelFilterSetting().set(Console.ConsoleViewFilter.allLevelsFilterValue());
     InspectorTest.dumpConsoleMessagesWithClasses();
     InspectorTest.completeTest();
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..cd5f5e9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..f37edb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-basic-expected.txt
@@ -0,0 +1,72 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x260
+  LayoutBlockFlow {HTML} at (0,0) size 800x260
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (706,0) size 78x192
+        LayoutBlockFlow {P} at (0,16) size 78x20
+          LayoutText {#text} at (47,0) size 31x19
+            text run at (47,0) width 31: "RTL"
+        LayoutBlockFlow {DIV} at (0,52) size 78x20
+          LayoutText {#text} at (36,0) size 42x19
+            text run at (36,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,72) size 78x20
+          LayoutText {#text} at (36,0) size 42x19
+            text run at (36,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,92) size 78x20
+          LayoutText {#text} at (36,0) size 42x19
+            text run at (36,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,112) size 78x20
+          LayoutText {#text} at (36,0) size 42x19
+            text run at (36,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,132) size 78x20
+          LayoutText {#text} at (36,0) size 42x19
+            text run at (36,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,152) size 78x40
+          LayoutBlockFlow {DIV} at (0,0) size 78x20
+            LayoutText {#text} at (0,0) size 42x19
+              text run at (0,0) width 42: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 36x19
+              LayoutText {#text} at (42,0) size 36x19
+                text run at (42,0) width 36: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,20) size 78x20
+            LayoutText {#text} at (29,0) size 49x19
+              text run at (29,0) width 49: "mnopqr"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 78x252
+        LayoutBlockFlow {P} at (0,16) size 78x20
+          LayoutText {#text} at (0,0) size 30x19
+            text run at (0,0) width 30: "LTR"
+        LayoutBlockFlow {DIV} at (0,52) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,72) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,92) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,112) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,132) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,152) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,172) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,192) size 78x20
+          LayoutText {#text} at (0,0) size 42x19
+            text run at (0,0) width 42: "abcdef"
+        LayoutBlockFlow {DIV} at (0,212) size 78x40
+          LayoutBlockFlow {DIV} at (0,0) size 78x20
+            LayoutText {#text} at (0,0) size 42x19
+              text run at (0,0) width 42: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 36x19
+              LayoutText {#text} at (42,0) size 36x19
+                text run at (42,0) width 36: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,20) size 78x20
+            LayoutText {#text} at (0,0) size 49x19
+              text run at (0,0) width 49: "mnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.png b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.png
new file mode 100644
index 0000000..862e08f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..b19f1d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/editing/active-suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x56
+  LayoutBlockFlow {HTML} at (0,0) size 800x56
+    LayoutBlockFlow {BODY} at (8,8) size 784x40
+      LayoutBlockFlow {DIV} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 22x19
+          text run at (0,0) width 22: "abc"
+        LayoutText {#text} at (22,0) size 32x19
+          text run at (22,0) width 32: " xxx "
+        LayoutText {#text} at (54,0) size 20x19
+          text run at (54,0) width 20: "def"
+layer at (8,28) size 128x20 scrollWidth 159
+  LayoutBlockFlow {DIV} at (0,20) size 128x20
+    LayoutText {#text} at (0,0) size 62x19
+      text run at (0,0) width 62: "abcdefghi"
+    LayoutText {#text} at (62,0) size 32x19
+      text run at (62,0) width 32: " xxx "
+    LayoutText {#text} at (94,0) size 65x19
+      text run at (94,0) width 65: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-expected.png
new file mode 100644
index 0000000..d25115f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
new file mode 100644
index 0000000..8a079e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
index e4d4f8c..22dbbdf 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
index ace784a..17cda7d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
new file mode 100644
index 0000000..7407960
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
index 6f101d5..e523275 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
index f4365827..a91be93 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-clip-expected.png
new file mode 100644
index 0000000..ec168d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-filter-expected.png
index ac212269..476e395b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
index 975e5fd6..7cbd0e5c 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
index 2dbcf9a..704ba37 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
index 5dd87ff..814ab4a1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
index 68885d2..cb2b97af 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png
index eb1051c..669869dd 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
index b0bb606b..02f1d5f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
new file mode 100644
index 0000000..9398e0a4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
new file mode 100644
index 0000000..92469918
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
index 5f70429..49b5989 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
new file mode 100644
index 0000000..33cf925
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index 2207e444..0791b72 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png
index b2c39bb..c6d91224 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
new file mode 100644
index 0000000..c3cbfad4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 09bf797..a2ab773 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
index 99c6158..84432163 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-suite/test-expected.png
new file mode 100644
index 0000000..7eccc40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
index 99c6158..84432163 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
new file mode 100644
index 0000000..920523b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
new file mode 100644
index 0000000..ef294951
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
new file mode 100644
index 0000000..b896e672
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-layer-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-layer-expected.png
new file mode 100644
index 0000000..3440d7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-layer-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index d778e85..78fa092 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
index 14138ce3..1f00131 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-clip-expected.png
new file mode 100644
index 0000000..ec168d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/virtual/gpu-rasterization/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-clip-expected.png
new file mode 100644
index 0000000..ec168d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/virtual/gpu-rasterization/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..8f81fa7f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..8a45985
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-basic-expected.txt
@@ -0,0 +1,72 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x238
+  LayoutBlockFlow {HTML} at (0,0) size 800x238
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (704.02,0) size 79.98x176
+        LayoutBlockFlow {P} at (0,16) size 79.98x18
+          LayoutText {#text} at (50,0) size 30x18
+            text run at (50,0) width 30: "RTL"
+        LayoutBlockFlow {DIV} at (0,50) size 79.98x18
+          LayoutText {#text} at (37,0) size 43x18
+            text run at (37,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,68) size 79.98x18
+          LayoutText {#text} at (37,0) size 43x18
+            text run at (37,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,86) size 79.98x18
+          LayoutText {#text} at (37,0) size 43x18
+            text run at (37,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,104) size 79.98x18
+          LayoutText {#text} at (37,0) size 43x18
+            text run at (37,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,122) size 79.98x18
+          LayoutText {#text} at (37,0) size 43x18
+            text run at (37,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,140) size 79.98x36
+          LayoutBlockFlow {DIV} at (0,0) size 79.98x18
+            LayoutText {#text} at (0,0) size 43x18
+              text run at (0,0) width 43: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 38x18
+              LayoutText {#text} at (42,0) size 38x18
+                text run at (42,0) width 38: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,18) size 79.98x18
+            LayoutText {#text} at (30,0) size 50x18
+              text run at (30,0) width 50: "mnopqr"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 79.98x230
+        LayoutBlockFlow {P} at (0,16) size 79.98x18
+          LayoutText {#text} at (0,0) size 29x18
+            text run at (0,0) width 29: "LTR"
+        LayoutBlockFlow {DIV} at (0,50) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,68) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,86) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,104) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,122) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,140) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,158) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,176) size 79.98x18
+          LayoutText {#text} at (0,0) size 43x18
+            text run at (0,0) width 43: "abcdef"
+        LayoutBlockFlow {DIV} at (0,194) size 79.98x36
+          LayoutBlockFlow {DIV} at (0,0) size 79.98x18
+            LayoutText {#text} at (0,0) size 43x18
+              text run at (0,0) width 43: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 38x18
+              LayoutText {#text} at (42,0) size 38x18
+                text run at (42,0) width 38: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,18) size 79.98x18
+            LayoutText {#text} at (0,0) size 50x18
+              text run at (0,0) width 50: "mnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.png
similarity index 63%
rename from third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
rename to third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.png
index 90d0d43f..d3a34fb1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..d7eebef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/editing/active-suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x52
+  LayoutBlockFlow {HTML} at (0,0) size 800x52
+    LayoutBlockFlow {BODY} at (8,8) size 784x36
+      LayoutBlockFlow {DIV} at (0,0) size 784x18
+        LayoutText {#text} at (0,0) size 23x18
+          text run at (0,0) width 23: "abc"
+        LayoutText {#text} at (22,0) size 33x18
+          text run at (22,0) width 33: " xxx "
+        LayoutText {#text} at (54,0) size 21x18
+          text run at (54,0) width 21: "def"
+layer at (8,26) size 128x18 scrollWidth 162
+  LayoutBlockFlow {DIV} at (0,18) size 128x18
+    LayoutText {#text} at (0,0) size 64x18
+      text run at (0,0) width 64: "abcdefghi"
+    LayoutText {#text} at (63,0) size 33x18
+      text run at (63,0) width 33: " xxx "
+    LayoutText {#text} at (95,0) size 67x18
+      text run at (95,0) width 67: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
deleted file mode 100644
index b372065..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
deleted file mode 100644
index 693dca60..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-expected.png
index d069fe8..d25115f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
index b9eb5a7..8a079e3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
index a891dcaa..22dbbdf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
index b021e62d..17cda7d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
index 5b7aedd..7407960 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
index 2ec2e295..e523275 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-source-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-source-expected.png
index cc01ea8..006f1e0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-source-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-image-source-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
index 22402af..e916767 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png
index 58f7f2c..1fc9fe1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-drag-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
index d7a76be..5175807 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
index d45f6fdb..7cbd0e5c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
index 2258cdff..704ba37 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
index b8334e468..814ab4a1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
index 0084813..d0d1192 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png
index c599f7d7..2b25791f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
index 7cb47b3c..5d54f98 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
index 3ede6368..9398e0a4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-profile-match-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-profile-match-expected.png
index fd16cbd..1cf0831 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-profile-match-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-profile-match-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
index f9ee2404..92469918 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
index 84ef662..4395275 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
index 4b2e18c..33cf925 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index f771c24..2ebfc28 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt
deleted file mode 100644
index 236d02d..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-
-Color         Actual        Expected      dE
---------------------------------------------
-Dark Skin     95,62,49      115,80,64     31
-Light Skin    181,132,111   195,151,130   30
-Blue Sky      76,103,139    94,123,156    32
-Foliage       71,91,50      88,108,65     28
-Blue Flower   111,108,162   130,129,177   32
-Bluish Green  85,179,154    100,190,171   25
---------------------------------------------
-Orange        205,101,29    217,122,37    25
-Purplish Blue 56,69,149     72,91,165     32
-Moderate Red  178,62,79     194,84,98     33
-Purple        72,43,87      91,59,107     32
-Yellow Green  144,177,46    160,188,60    24
-Orange Yellow 223,147,32    230,163,42    20
---------------------------------------------
-Blue          35,40,135     46,60,153     29
-Green         58,134,54     71,150,69     25
-Red           159,26,43     177,44,56     29
-Yellow        234,191,24    238,200,27    10
-Magenta       171,58,129    187,82,148    35
-Cyan (*)      0,116,149     0,135,166     25
---------------------------------------------
-White         240,238,232   243,242,237   7
-Neutral 8     189,190,188   201,201,201   21
-Neutral 6.5   143,144,143   161,161,161   31
-Neutral 5     104,102,102   122,122,121   33
-Neutral 3.5   66,66,66      83,83,83      29
-Black         37,37,37      50,49,50      22
---------------------------------------------
-
-Result: total RMS color error: 27.52
- * Munsell Cyan is outside 255 sRGB gamut
-
-  
-
-
-
-
-
-
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
index f378248e8d..ba977700 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.txt
index 6b8c026e..61e3d1ad 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-munsell-srgb-to-srgb-expected.txt
@@ -1,36 +1,36 @@
 
 Color         Actual        Expected      dE
 --------------------------------------------
-Dark Skin     95,62,49      115,80,64     31
-Light Skin    181,133,111   195,151,130   30
-Blue Sky      76,103,138    94,123,156    32
-Foliage       71,90,50      88,108,65     29
-Blue Flower   111,108,161   130,129,177   33
-Bluish Green  85,178,155    100,190,171   25
+Dark Skin     115,80,64     115,80,64     0
+Light Skin    195,151,130   195,151,130   0
+Blue Sky      94,123,156    94,123,156    0
+Foliage       88,108,65     88,108,65     0
+Blue Flower   130,129,177   130,129,177   0
+Bluish Green  100,190,171   100,190,171   0
 --------------------------------------------
-Orange        206,102,29    217,122,37    24
-Purplish Blue 56,69,148     72,91,165     32
-Moderate Red  179,62,80     194,84,98     32
-Purple        72,42,88      91,59,107     32
-Yellow Green  144,178,47    160,188,60    23
-Orange Yellow 222,147,33    230,163,42    20
+Orange        217,122,37    217,122,37    0
+Purplish Blue 72,91,165     72,91,165     0
+Moderate Red  194,84,98     194,84,98     0
+Purple        91,59,107     91,59,107     0
+Yellow Green  160,188,60    160,188,60    0
+Orange Yellow 230,163,42    230,163,42    0
 --------------------------------------------
-Blue          35,40,135     46,60,153     29
-Green         58,135,53     71,150,69     25
-Red           159,26,43     177,44,56     29
-Yellow        233,190,24    238,200,27    12
-Magenta       171,58,130    187,82,148    34
-Cyan (*)      15,116,149    0,135,166     30
+Blue          46,60,153     46,60,153     0
+Green         71,150,69     71,150,69     0
+Red           177,44,56     177,44,56     0
+Yellow        238,200,27    238,200,27    0
+Magenta       187,82,148    187,82,148    0
+Cyan (*)      0,135,166     0,135,166     0
 --------------------------------------------
-White         240,239,233   243,242,237   6
-Neutral 8     189,189,189   201,201,201   21
-Neutral 6.5   144,144,144   161,161,161   29
-Neutral 5     103,103,102   122,122,121   33
-Neutral 3.5   65,65,65      83,83,83      31
-Black         38,37,38      50,49,50      21
+White         243,242,237   243,242,237   0
+Neutral 8     201,201,201   201,201,201   0
+Neutral 6.5   161,161,161   161,161,161   0
+Neutral 5     122,122,121   122,122,121   0
+Neutral 3.5   83,83,83      83,83,83      0
+Black         50,49,50      50,49,50      0
 --------------------------------------------
 
-Result: total RMS color error: 27.64
+Result: total RMS color error: 0.00
  * Munsell Cyan is outside 255 sRGB gamut
 
   
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png
index 4e3fd06ac..c6d91224 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
index 7456bcaa..c3cbfad4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 9124dfaa..61e7160 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/embed-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/embed-image-expected.png
index 19fdf4d..6caa236 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/embed-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/embed-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
index 765b44a..1dd81e3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/object-image-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/object-image-expected.png
index 19fdf4d..6caa236 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/object-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/object-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paint-subrect-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paint-subrect-expected.png
index 64b6ca2..1fca07f0 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paint-subrect-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/paint-subrect-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png
deleted file mode 100644
index 193267c8..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-suite/test-expected.png
index ae61580e..90dc9d56 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
index 765b44a..1dd81e3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png_per_row_alpha_decoding-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png_per_row_alpha_decoding-expected.png
index e9e5ba441..ae217b2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png_per_row_alpha_decoding-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/png_per_row_alpha_decoding-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
index 255c145..920523b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
index 92ffe60..ef294951 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
index 717906ca4..b896e672 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.png
new file mode 100644
index 0000000..f183f2b72
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.txt
new file mode 100644
index 0000000..d6a7b73
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-basic-expected.txt
@@ -0,0 +1,72 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x260
+  LayoutBlockFlow {HTML} at (0,0) size 800x260
+    LayoutBlockFlow {BODY} at (8,8) size 784x0
+      LayoutBlockFlow (floating) {DIV} at (711,0) size 73x192
+        LayoutBlockFlow {P} at (0,16) size 73x20
+          LayoutText {#text} at (45,0) size 28x19
+            text run at (45,0) width 28: "RTL"
+        LayoutBlockFlow {DIV} at (0,52) size 73x20
+          LayoutText {#text} at (32,0) size 41x19
+            text run at (32,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,72) size 73x20
+          LayoutText {#text} at (32,0) size 41x19
+            text run at (32,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,92) size 73x20
+          LayoutText {#text} at (32,0) size 41x19
+            text run at (32,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,112) size 73x20
+          LayoutText {#text} at (32,0) size 41x19
+            text run at (32,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,132) size 73x20
+          LayoutText {#text} at (32,0) size 41x19
+            text run at (32,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,152) size 73x40
+          LayoutBlockFlow {DIV} at (0,0) size 73x20
+            LayoutText {#text} at (0,0) size 41x19
+              text run at (0,0) width 41: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 32x19
+              LayoutText {#text} at (41,0) size 32x19
+                text run at (41,0) width 32: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,20) size 73x20
+            LayoutText {#text} at (26,0) size 47x19
+              text run at (26,0) width 47: "mnopqr"
+      LayoutBlockFlow (floating) {DIV} at (0,0) size 73x252
+        LayoutBlockFlow {P} at (0,16) size 73x20
+          LayoutText {#text} at (0,0) size 27x19
+            text run at (0,0) width 27: "LTR"
+        LayoutBlockFlow {DIV} at (0,52) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,72) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,92) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,112) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,132) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,152) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,172) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,192) size 73x20
+          LayoutText {#text} at (0,0) size 41x19
+            text run at (0,0) width 41: "abcdef"
+        LayoutBlockFlow {DIV} at (0,212) size 73x40
+          LayoutBlockFlow {DIV} at (0,0) size 73x20
+            LayoutText {#text} at (0,0) size 41x19
+              text run at (0,0) width 41: "abcdef"
+            LayoutInline {SPAN} at (0,0) size 32x19
+              LayoutText {#text} at (41,0) size 32x19
+                text run at (41,0) width 32: "ghijkl"
+          LayoutBlockFlow {DIV} at (0,20) size 73x20
+            LayoutText {#text} at (0,0) size 47x19
+              text run at (0,0) width 47: "mnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.png
similarity index 64%
rename from third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
rename to third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.png
index 23c1300..5f55a19 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.txt b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.txt
new file mode 100644
index 0000000..c6801ae
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/editing/active-suggestion-marker-split-expected.txt
@@ -0,0 +1,20 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x56
+  LayoutBlockFlow {HTML} at (0,0) size 800x56
+    LayoutBlockFlow {BODY} at (8,8) size 784x40
+      LayoutBlockFlow {DIV} at (0,0) size 784x20
+        LayoutText {#text} at (0,0) size 22x19
+          text run at (0,0) width 22: "abc"
+        LayoutText {#text} at (22,0) size 29x19
+          text run at (22,0) width 29: " xxx "
+        LayoutText {#text} at (51,0) size 19x19
+          text run at (51,0) width 19: "def"
+layer at (8,28) size 128x20 scrollWidth 149
+  LayoutBlockFlow {DIV} at (0,20) size 128x20
+    LayoutText {#text} at (0,0) size 58x19
+      text run at (0,0) width 58: "abcdefghi"
+    LayoutText {#text} at (58,0) size 29x19
+      text run at (58,0) width 29: " xxx "
+    LayoutText {#text} at (87,0) size 62x19
+      text run at (87,0) width 62: "jklmnopqr"
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
deleted file mode 100644
index 5286dbfb..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
deleted file mode 100644
index 8114e46..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-expected.png
index 21f9a15..2f3eb036 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
index 5032ce8..c6c93be 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-animate-rotate-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
index c98dad7..97a701c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-cover-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
index ac812b8..fe37b2c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-background-image-repeat-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
index ad4f227..a7f1bd14 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-fade-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
index c63227a..b513584 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
index 060937e0..36e70093 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-clip-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-clip-expected.png
index ff07c6a..4417abec 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-clip-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-clip-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-filter-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-filter-expected.png
index f8d1e272..e759e48 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-filter-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-filter-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
index 2cb8795..a4da71f3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
index 57d4053..13102cc 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
index 9f9f414..c42e54a3 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-pattern-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
index 7430ea1..a28c2e7 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-canvas-svg-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png
index 23f182ac..fb639c6f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
index 8025ba6..c2bb31b 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
index 3e4b818..dc7fa3c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-object-fit-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
index baa7551..4a44b02 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-pseudo-content-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
index 27b7092..bd4e989 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-shape-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
index 341dc128..d1e6b79 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-image-svg-resource-url-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
index 0850735..bb8ee48 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt
deleted file mode 100644
index 20ccc5c..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-munsell-adobe-to-srgb-expected.txt
+++ /dev/null
@@ -1,42 +0,0 @@
-
-Color         Actual        Expected      dE
---------------------------------------------
-Dark Skin     115,80,65     115,80,64     1
-Light Skin    194,150,130   195,151,130   1
-Blue Sky      94,123,156    94,123,156    0
-Foliage       89,108,65     88,108,65     1
-Blue Flower   130,129,177   130,129,177   0
-Bluish Green  100,190,170   100,190,171   1
---------------------------------------------
-Orange        216,122,37    217,122,37    1
-Purplish Blue 72,91,165     72,91,165     0
-Moderate Red  193,85,98     194,84,98     1
-Purple        91,60,107     91,59,107     1
-Yellow Green  160,187,60    160,188,60    1
-Orange Yellow 230,163,42    230,163,42    0
---------------------------------------------
-Blue          47,60,153     46,60,153     1
-Green         71,149,70     71,150,69     1
-Red           176,45,56     177,44,56     1
-Yellow        239,200,27    238,200,27    1
-Magenta       186,82,147    187,82,148    1
-Cyan (*)      0,135,165     0,135,166     1
---------------------------------------------
-White         243,242,236   243,242,237   1
-Neutral 8     201,201,200   201,201,201   1
-Neutral 6.5   160,161,160   161,161,161   1
-Neutral 5     123,122,121   122,122,121   1
-Neutral 3.5   84,84,84      83,83,83      2
-Black         50,50,50      50,49,50      1
---------------------------------------------
-
-Result: total RMS color error: 0.98
- * Munsell Cyan is outside 255 sRGB gamut
-
-  
-
-
-
-
-
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png
index 55dae2f..b1c82b5a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
index 0a8d5d2e..40007d9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/color-profile-svg-foreign-object-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
index 108cc2c..7c8e5da 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/cross-fade-background-size-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
index 5e1f74b..5dc6109f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png
deleted file mode 100644
index 68662902..0000000
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-color-profile-ignore-gamma-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-suite/test-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-suite/test-expected.png
index 2b557807..4187074 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-suite/test-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-suite/test-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
index 5e1f74b..5dc6109f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
index 829f86b..fcc69d2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossless-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
index c7c6b394..62e2e0d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-alpha-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
index 37a31d5..d49aec1af 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/gpu-rasterization/images/webp-color-profile-lossy-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
new file mode 100644
index 0000000..23ed1e4c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cHRM_color_spin-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
new file mode 100644
index 0000000..1d56780
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/color-jpeg-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-overflow-position-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-overflow-position-expected.png
index e49d2e89..07d1d8e 100644
--- a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-overflow-position-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-overflow-position-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-tiled-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-tiled-expected.png
index 18e3b7b..59a44ea1 100644
--- a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-tiled-expected.png
+++ b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/cross-fade-tiled-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
new file mode 100644
index 0000000..2d73757
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/gpu-rasterization/images/paletted-png-with-color-profile-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
index b939018..0c42777 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValueMappings.h
@@ -1100,38 +1100,6 @@
 }
 
 template <>
-inline CSSIdentifierValue::CSSIdentifierValue(TextUnderlinePosition e)
-    : CSSValue(kIdentifierClass) {
-  switch (e) {
-    case TextUnderlinePosition::kAuto:
-      value_id_ = CSSValueAuto;
-      break;
-    case TextUnderlinePosition::kUnder:
-      value_id_ = CSSValueUnder;
-      break;
-  }
-
-  // FIXME: Implement support for 'under left' and 'under right' values.
-}
-
-template <>
-inline TextUnderlinePosition CSSIdentifierValue::ConvertTo() const {
-  switch (value_id_) {
-    case CSSValueAuto:
-      return TextUnderlinePosition::kAuto;
-    case CSSValueUnder:
-      return TextUnderlinePosition::kUnder;
-    default:
-      break;
-  }
-
-  // FIXME: Implement support for 'under left' and 'under right' values.
-
-  NOTREACHED();
-  return TextUnderlinePosition::kAuto;
-}
-
-template <>
 inline TextDecorationSkip CSSIdentifierValue::ConvertTo() const {
   switch (value_id_) {
     case CSSValueObjects:
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.json5 b/third_party/WebKit/Source/core/css/CSSProperties.json5
index 38b07c9..7fd6171 100644
--- a/third_party/WebKit/Source/core/css/CSSProperties.json5
+++ b/third_party/WebKit/Source/core/css/CSSProperties.json5
@@ -2152,16 +2152,17 @@
       field_template: "keyword",
       keywords: ["capitalize", "uppercase", "lowercase", "none"],
     },
+    // FIXME: Implement support for 'under left' and 'under right' values.
     {
       name: "text-underline-position",
       api_class: true,
       api_methods: ["parseSingleValue"],
       inherited: true,
       runtime_flag: "CSS3TextDecorations",
-      field_template: "storage_only",
+      field_template: "keyword",
       type_name: "TextUnderlinePosition",
-      default_value: "TextUnderlinePosition::kAuto",
-      field_size: 1,
+      default_value: "auto",
+      keywords: ["auto", "under"],
       field_group: "rare-inherited",
     },
     {
diff --git a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5 b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
index 9d3fd3e..10258d5a 100644
--- a/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
+++ b/third_party/WebKit/Source/core/css/ComputedStyleExtraFields.json5
@@ -467,10 +467,9 @@
     {
       name: "SubtreeWillChangeContents",
       inherited: true,
-      field_template: "storage_only",
+      field_template: "primitive",
       type_name: "bool",
       default_value: "false",
-      field_size: 1,
       field_group: "rare-inherited",
     },
     {
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 71d423c..4e88854 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -1792,6 +1792,9 @@
   DCHECK(ShouldScheduleLayoutTreeUpdate());
   DCHECK(NeedsLayoutTreeUpdate());
 
+  // TODO(szager): Remove this CHECK after checking crash reports.
+  CHECK(lifecycle_.GetState() != DocumentLifecycle::kInPerformLayout);
+
   if (!View()->CanThrottleRendering())
     GetPage()->Animator().ScheduleVisualUpdate(GetFrame());
   lifecycle_.EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending);
@@ -2118,6 +2121,9 @@
 void Document::UpdateStyle() {
   DCHECK(!View()->ShouldThrottleRendering());
   TRACE_EVENT_BEGIN0("blink,blink_style", "Document::updateStyle");
+  RuntimeCallTimerScope scope(
+      RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()),
+      RuntimeCallStats::CounterId::kUpdateStyle);
   double start_time = MonotonicallyIncreasingTime();
 
   unsigned initial_element_count = GetStyleEngine().StyleForElementCount();
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
index 3b439e45..6430ebb 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -6,6 +6,7 @@
 
 #include "core/dom/MockScriptElementBase.h"
 #include "core/dom/ScriptLoader.h"
+#include "platform/bindings/RuntimeCallStats.h"
 #include "platform/heap/Handle.h"
 #include "platform/scheduler/renderer/web_view_scheduler.h"
 #include "platform/testing/TestingPlatformSupport.h"
@@ -44,8 +45,12 @@
     // loadingTaskRunner() to be initialized before creating ScriptRunner to
     // save it in constructor.
     script_runner_ = ScriptRunner::Create(document_.Get());
+    RuntimeCallStats::SetRuntimeCallStatsForTesting();
   }
-  void TearDown() override { script_runner_.Release(); }
+  void TearDown() override {
+    script_runner_.Release();
+    RuntimeCallStats::ClearRuntimeCallStatsForTesting();
+  }
 
  protected:
   Persistent<Document> document_;
diff --git a/third_party/WebKit/Source/core/editing/BUILD.gn b/third_party/WebKit/Source/core/editing/BUILD.gn
index 5bca983b..77592b6 100644
--- a/third_party/WebKit/Source/core/editing/BUILD.gn
+++ b/third_party/WebKit/Source/core/editing/BUILD.gn
@@ -193,6 +193,10 @@
     "iterators/TextIteratorTextState.h",
     "iterators/TextSearcherICU.cpp",
     "iterators/TextSearcherICU.h",
+    "markers/ActiveSuggestionMarker.cpp",
+    "markers/ActiveSuggestionMarker.h",
+    "markers/ActiveSuggestionMarkerListImpl.cpp",
+    "markers/ActiveSuggestionMarkerListImpl.h",
     "markers/CompositionMarker.cpp",
     "markers/CompositionMarker.h",
     "markers/CompositionMarkerListImpl.cpp",
@@ -323,6 +327,8 @@
     "iterators/SimplifiedBackwardsTextIteratorTest.cpp",
     "iterators/TextIteratorTest.cpp",
     "iterators/TextSearcherICUTest.cpp",
+    "markers/ActiveSuggestionMarkerListImplTest.cpp",
+    "markers/ActiveSuggestionMarkerTest.cpp",
     "markers/CompositionMarkerListImplTest.cpp",
     "markers/CompositionMarkerTest.cpp",
     "markers/DocumentMarkerControllerTest.cpp",
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.cpp b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.cpp
new file mode 100644
index 0000000..2847d92
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.cpp
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/ActiveSuggestionMarker.h"
+
+namespace blink {
+
+ActiveSuggestionMarker::ActiveSuggestionMarker(unsigned start_offset,
+                                               unsigned end_offset,
+                                               Color underline_color,
+                                               Thickness thickness,
+                                               Color background_color)
+    : StyleableMarker(start_offset,
+                      end_offset,
+                      underline_color,
+                      thickness,
+                      background_color) {}
+
+DocumentMarker::MarkerType ActiveSuggestionMarker::GetType() const {
+  return DocumentMarker::kActiveSuggestion;
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.h b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.h
new file mode 100644
index 0000000..54bcece
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarker.h
@@ -0,0 +1,38 @@
+// 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 ActiveSuggestionMarker_h
+#define ActiveSuggestionMarker_h
+
+#include "core/editing/markers/StyleableMarker.h"
+
+namespace blink {
+
+// A subclass of StyleableMarker used to represent ActiveSuggestion markers,
+// which are used to mark the region of text an open spellcheck or suggestion
+// menu pertains to.
+class CORE_EXPORT ActiveSuggestionMarker final : public StyleableMarker {
+ public:
+  ActiveSuggestionMarker(unsigned start_offset,
+                         unsigned end_offset,
+                         Color underline_color,
+                         Thickness,
+                         Color background_color);
+
+  // DocumentMarker implementations
+  MarkerType GetType() const final;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ActiveSuggestionMarker);
+};
+
+DEFINE_TYPE_CASTS(ActiveSuggestionMarker,
+                  DocumentMarker,
+                  marker,
+                  marker->GetType() == DocumentMarker::kActiveSuggestion,
+                  marker.GetType() == DocumentMarker::kActiveSuggestion);
+
+}  // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.cpp
new file mode 100644
index 0000000..600eeed
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.cpp
@@ -0,0 +1,57 @@
+// 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 "core/editing/markers/ActiveSuggestionMarkerListImpl.h"
+
+#include "core/editing/markers/DocumentMarkerListEditor.h"
+
+namespace blink {
+
+DocumentMarker::MarkerType ActiveSuggestionMarkerListImpl::MarkerType() const {
+  return DocumentMarker::kActiveSuggestion;
+}
+
+bool ActiveSuggestionMarkerListImpl::IsEmpty() const {
+  return markers_.IsEmpty();
+}
+
+void ActiveSuggestionMarkerListImpl::Add(DocumentMarker* marker) {
+  DocumentMarkerListEditor::AddMarkerWithoutMergingOverlapping(&markers_,
+                                                               marker);
+}
+
+void ActiveSuggestionMarkerListImpl::Clear() {
+  markers_.clear();
+}
+
+const HeapVector<Member<DocumentMarker>>&
+ActiveSuggestionMarkerListImpl::GetMarkers() const {
+  return markers_;
+}
+
+bool ActiveSuggestionMarkerListImpl::MoveMarkers(
+    int length,
+    DocumentMarkerList* dst_markers_) {
+  return DocumentMarkerListEditor::MoveMarkers(&markers_, length, dst_markers_);
+}
+
+bool ActiveSuggestionMarkerListImpl::RemoveMarkers(unsigned start_offset,
+                                                   int length) {
+  return DocumentMarkerListEditor::RemoveMarkers(&markers_, start_offset,
+                                                 length);
+}
+
+bool ActiveSuggestionMarkerListImpl::ShiftMarkers(unsigned offset,
+                                                  unsigned old_length,
+                                                  unsigned new_length) {
+  return DocumentMarkerListEditor::ShiftMarkersContentIndependent(
+      &markers_, offset, old_length, new_length);
+}
+
+DEFINE_TRACE(ActiveSuggestionMarkerListImpl) {
+  visitor->Trace(markers_);
+  DocumentMarkerList::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.h b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.h
new file mode 100644
index 0000000..c001823
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImpl.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 ActiveSuggestionMarkerListImpl_h
+#define ActiveSuggestionMarkerListImpl_h
+
+#include "core/editing/markers/DocumentMarkerList.h"
+
+namespace blink {
+
+// Implementation of DocumentMarkerList for ActiveSuggestion markers.
+// ActiveSuggestion markers are always inserted in order, aside from some
+// potential oddball cases (e.g. splitting the marker list into two nodes, then
+// undoing the split). This means we can keep the list in sorted order to do
+// some operations more efficiently, while still being able to do inserts in
+// O(1) time at the end of the list.
+class CORE_EXPORT ActiveSuggestionMarkerListImpl final
+    : public DocumentMarkerList {
+ public:
+  ActiveSuggestionMarkerListImpl() = default;
+
+  // DocumentMarkerList implementations
+  DocumentMarker::MarkerType MarkerType() const final;
+
+  bool IsEmpty() const final;
+
+  void Add(DocumentMarker*) final;
+  void Clear() final;
+
+  const HeapVector<Member<DocumentMarker>>& GetMarkers() const final;
+
+  bool MoveMarkers(int length, DocumentMarkerList* dst_list) final;
+  bool RemoveMarkers(unsigned start_offset, int length) final;
+  bool ShiftMarkers(unsigned offset,
+                    unsigned old_length,
+                    unsigned new_length) final;
+
+  DECLARE_VIRTUAL_TRACE();
+
+ private:
+  HeapVector<Member<DocumentMarker>> markers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ActiveSuggestionMarkerListImpl);
+};
+
+}  // namespace blink
+
+#endif  // ActiveSuggestionMarkerListImpl_h
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImplTest.cpp b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImplTest.cpp
new file mode 100644
index 0000000..e09c071
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerListImplTest.cpp
@@ -0,0 +1,43 @@
+// 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 "core/editing/markers/ActiveSuggestionMarkerListImpl.h"
+
+#include "core/editing/EditingTestBase.h"
+#include "core/editing/markers/ActiveSuggestionMarker.h"
+
+namespace blink {
+
+class ActiveSuggestionMarkerListImplTest : public EditingTestBase {
+ protected:
+  ActiveSuggestionMarkerListImplTest()
+      : marker_list_(new ActiveSuggestionMarkerListImpl()) {}
+
+  DocumentMarker* CreateMarker(unsigned start_offset, unsigned end_offset) {
+    return new ActiveSuggestionMarker(start_offset, end_offset, Color::kBlack,
+                                      StyleableMarker::Thickness::kThin,
+                                      Color::kBlack);
+  }
+
+  Persistent<ActiveSuggestionMarkerListImpl> marker_list_;
+};
+
+// ActiveSuggestionMarkerListImpl shouldn't merge markers with touching
+// endpoints
+TEST_F(ActiveSuggestionMarkerListImplTest, Add) {
+  EXPECT_EQ(0u, marker_list_->GetMarkers().size());
+
+  marker_list_->Add(CreateMarker(0, 1));
+  marker_list_->Add(CreateMarker(1, 2));
+
+  EXPECT_EQ(2u, marker_list_->GetMarkers().size());
+
+  EXPECT_EQ(0u, marker_list_->GetMarkers()[0]->StartOffset());
+  EXPECT_EQ(1u, marker_list_->GetMarkers()[0]->EndOffset());
+
+  EXPECT_EQ(1u, marker_list_->GetMarkers()[1]->StartOffset());
+  EXPECT_EQ(2u, marker_list_->GetMarkers()[1]->EndOffset());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerTest.cpp b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerTest.cpp
new file mode 100644
index 0000000..3b6f189
--- /dev/null
+++ b/third_party/WebKit/Source/core/editing/markers/ActiveSuggestionMarkerTest.cpp
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/editing/markers/ActiveSuggestionMarker.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+class ActiveSuggestionMarkerTest : public ::testing::Test {};
+
+TEST_F(ActiveSuggestionMarkerTest, MarkerType) {
+  DocumentMarker* marker = new ActiveSuggestionMarker(
+      0, 1, Color::kTransparent, StyleableMarker::Thickness::kThin,
+      Color::kTransparent);
+  EXPECT_EQ(DocumentMarker::kActiveSuggestion, marker->GetType());
+}
+
+TEST_F(ActiveSuggestionMarkerTest, IsStyleableMarker) {
+  DocumentMarker* marker = new ActiveSuggestionMarker(
+      0, 1, Color::kTransparent, StyleableMarker::Thickness::kThin,
+      Color::kTransparent);
+  EXPECT_TRUE(IsStyleableMarker(*marker));
+}
+
+TEST_F(ActiveSuggestionMarkerTest, ConstructorAndGetters) {
+  ActiveSuggestionMarker* marker = new ActiveSuggestionMarker(
+      0, 1, Color::kDarkGray, StyleableMarker::Thickness::kThin, Color::kGray);
+  EXPECT_EQ(Color::kDarkGray, marker->UnderlineColor());
+  EXPECT_FALSE(marker->IsThick());
+  EXPECT_EQ(Color::kGray, marker->BackgroundColor());
+
+  ActiveSuggestionMarker* thick_marker = new ActiveSuggestionMarker(
+      0, 1, Color::kDarkGray, StyleableMarker::Thickness::kThick, Color::kGray);
+  EXPECT_EQ(true, thick_marker->IsThick());
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
index 7440dae..ba638a4 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarker.h
@@ -43,6 +43,7 @@
     kGrammarMarkerIndex,
     kTextMatchMarkerIndex,
     kCompositionMarkerIndex,
+    kActiveSuggestionMarkerIndex,
     kMarkerTypeIndexesCount
   };
 
@@ -51,6 +52,7 @@
     kGrammar = 1 << kGrammarMarkerIndex,
     kTextMatch = 1 << kTextMatchMarkerIndex,
     kComposition = 1 << kCompositionMarkerIndex,
+    kActiveSuggestion = 1 << kActiveSuggestionMarkerIndex,
   };
 
   class MarkerTypesIterator
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
index 5295203b..a9309fa 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.cpp
@@ -34,6 +34,8 @@
 #include "core/dom/Text.h"
 #include "core/editing/VisibleUnits.h"
 #include "core/editing/iterators/TextIterator.h"
+#include "core/editing/markers/ActiveSuggestionMarker.h"
+#include "core/editing/markers/ActiveSuggestionMarkerListImpl.h"
 #include "core/editing/markers/CompositionMarker.h"
 #include "core/editing/markers/CompositionMarkerListImpl.h"
 #include "core/editing/markers/DocumentMarkerListEditor.h"
@@ -65,6 +67,8 @@
       return DocumentMarker::kTextMatchMarkerIndex;
     case DocumentMarker::kComposition:
       return DocumentMarker::kCompositionMarkerIndex;
+    case DocumentMarker::kActiveSuggestion:
+      return DocumentMarker::kActiveSuggestionMarkerIndex;
   }
 
   NOTREACHED();
@@ -73,6 +77,8 @@
 
 DocumentMarkerList* CreateListForType(DocumentMarker::MarkerType type) {
   switch (type) {
+    case DocumentMarker::kActiveSuggestion:
+      return new ActiveSuggestionMarkerListImpl();
     case DocumentMarker::kComposition:
       return new CompositionMarkerListImpl();
     case DocumentMarker::kSpelling:
@@ -163,6 +169,19 @@
   });
 }
 
+void DocumentMarkerController::AddActiveSuggestionMarker(
+    const EphemeralRange& range,
+    Color underline_color,
+    StyleableMarker::Thickness thickness,
+    Color background_color) {
+  DCHECK(!document_->NeedsLayoutTreeUpdate());
+  AddMarkerInternal(range, [underline_color, thickness, background_color](
+                               int start_offset, int end_offset) {
+    return new ActiveSuggestionMarker(start_offset, end_offset, underline_color,
+                                      thickness, background_color);
+  });
+}
+
 void DocumentMarkerController::PrepareForDestruction() {
   Clear();
 }
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
index 92e7532..64d9ebdb 100644
--- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
+++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerController.h
@@ -64,6 +64,10 @@
                             Color underline_color,
                             StyleableMarker::Thickness,
                             Color background_color);
+  void AddActiveSuggestionMarker(const EphemeralRange&,
+                                 Color underline_color,
+                                 StyleableMarker::Thickness,
+                                 Color background_color);
 
   void MoveMarkers(Node* src_node, int length, Node* dst_node);
 
diff --git a/third_party/WebKit/Source/core/editing/markers/StyleableMarker.cpp b/third_party/WebKit/Source/core/editing/markers/StyleableMarker.cpp
index 3ed789a..b80743e 100644
--- a/third_party/WebKit/Source/core/editing/markers/StyleableMarker.cpp
+++ b/third_party/WebKit/Source/core/editing/markers/StyleableMarker.cpp
@@ -30,7 +30,8 @@
 
 bool IsStyleableMarker(const DocumentMarker& marker) {
   DocumentMarker::MarkerType type = marker.GetType();
-  return type == DocumentMarker::kComposition;
+  return type == DocumentMarker::kComposition ||
+         type == DocumentMarker::kActiveSuggestion;
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 461460e..bd3893d6 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -1145,6 +1145,10 @@
 
   TRACE_EVENT0("blink,benchmark", "LocalFrameView::layout");
 
+  RuntimeCallTimerScope scope(
+      RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()),
+      RuntimeCallStats::CounterId::kUpdateLayout);
+
   if (auto_size_info_)
     auto_size_info_->AutoSizeIfNeeded();
 
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index 601fda49..176238c 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -641,9 +641,8 @@
         break;
       case DocumentMarker::kTextMatch:
       case DocumentMarker::kComposition:
+      case DocumentMarker::kActiveSuggestion:
         break;
-      default:
-        continue;
     }
 
     if (marker.EndOffset() <= inline_text_box_.Start()) {
@@ -676,13 +675,13 @@
               paint_info, box_origin, ToTextMatchMarker(marker), style, font);
         }
         break;
-      case DocumentMarker::kComposition: {
-        const CompositionMarker& composition_marker =
-            ToCompositionMarker(marker);
+      case DocumentMarker::kComposition:
+      case DocumentMarker::kActiveSuggestion: {
+        const StyleableMarker& styleable_marker = ToStyleableMarker(marker);
         CompositionUnderline underline(
-            composition_marker.StartOffset(), composition_marker.EndOffset(),
-            composition_marker.UnderlineColor(), composition_marker.IsThick(),
-            composition_marker.BackgroundColor());
+            styleable_marker.StartOffset(), styleable_marker.EndOffset(),
+            styleable_marker.UnderlineColor(), styleable_marker.IsThick(),
+            styleable_marker.BackgroundColor());
         if (marker_paint_phase == DocumentMarkerPaintPhase::kBackground)
           PaintSingleCompositionBackgroundRun(
               paint_info.context, box_origin, style, font,
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index f762bfd..4121c1b 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -75,6 +75,8 @@
 #include "core/paint/ObjectPaintInvalidator.h"
 #include "platform/LengthFunctions.h"
 #include "platform/RuntimeEnabledFeatures.h"
+#include "platform/bindings/RuntimeCallStats.h"
+#include "platform/bindings/V8PerIsolateData.h"
 #include "platform/geometry/FloatPoint3D.h"
 #include "platform/geometry/FloatRect.h"
 #include "platform/geometry/TransformState.h"
@@ -286,6 +288,9 @@
 void PaintLayer::UpdateLayerPositionsAfterLayout() {
   TRACE_EVENT0("blink,benchmark",
                "PaintLayer::updateLayerPositionsAfterLayout");
+  RuntimeCallTimerScope runtime_timer_scope(
+      RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()),
+      RuntimeCallStats::CounterId::kUpdateLayerPositionsAfterLayout);
 
   Clipper(PaintLayer::kDoNotUseGeometryMapper)
       .ClearClipRectsIncludingDescendants();
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index 467681b..6b139c0f 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -1480,17 +1480,6 @@
     SET_VAR(rare_non_inherited_data_, text_decoration_style_, v);
   }
 
-  // text-underline-position
-  static TextUnderlinePosition InitialTextUnderlinePosition() {
-    return TextUnderlinePosition::kAuto;
-  }
-  TextUnderlinePosition GetTextUnderlinePosition() const {
-    return TextUnderlinePositionInternal();
-  }
-  void SetTextUnderlinePosition(TextUnderlinePosition v) {
-    SetTextUnderlinePositionInternal(v);
-  }
-
   // text-decoration-skip
   static TextDecorationSkip InitialTextDecorationSkip() {
     return TextDecorationSkip::kObjects;
@@ -1547,9 +1536,6 @@
     return rare_non_inherited_data_->will_change_data_
         ->will_change_scroll_position_;
   }
-  bool SubtreeWillChangeContents() const {
-    return SubtreeWillChangeContentsInternal();
-  }
   void SetWillChangeProperties(const Vector<CSSPropertyID>& properties) {
     SET_NESTED_VAR(rare_non_inherited_data_, will_change_data_,
                    will_change_properties_, properties);
@@ -1562,9 +1548,6 @@
     SET_NESTED_VAR(rare_non_inherited_data_, will_change_data_,
                    will_change_scroll_position_, b);
   }
-  void SetSubtreeWillChangeContents(bool b) {
-    SetSubtreeWillChangeContentsInternal(b);
-  }
 
   // z-index
   int ZIndex() const { return ZIndexInternal(); }
diff --git a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
index 1adb46d..c0170a6 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyleConstants.h
@@ -236,12 +236,6 @@
   return a = a | b;
 }
 
-enum class TextUnderlinePosition {
-  // FIXME: Implement support for 'under left' and 'under right' values.
-  kAuto,
-  kUnder
-};
-
 enum ETransformStyle3D { kTransformStyle3DFlat, kTransformStyle3DPreserve3D };
 
 enum OffsetRotationType { kOffsetRotationAuto, kOffsetRotationFixed };
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 3987bdd..fdfc91a8 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -1070,11 +1070,17 @@
   return WTF::nullopt;
 }
 
-void Internals::addCompositionMarker(const Range* range,
-                                     const String& underline_color_value,
-                                     const String& thickness_value,
-                                     const String& background_color_value,
-                                     ExceptionState& exception_state) {
+namespace {
+
+void addStyleableMarkerHelper(
+    const Range* range,
+    const String& underline_color_value,
+    const String& thickness_value,
+    const String& background_color_value,
+    ExceptionState& exception_state,
+    std::function<
+        void(const EphemeralRange&, Color, StyleableMarker::Thickness, Color)>
+        create_marker) {
   DCHECK(range);
   range->OwnerDocument().UpdateStyleAndLayoutIgnorePendingStylesheets();
 
@@ -1093,12 +1099,49 @@
                  "Invalid underline color.") &&
       ParseColor(background_color_value, background_color, exception_state,
                  "Invalid background color.")) {
-    range->OwnerDocument().Markers().AddCompositionMarker(
-        EphemeralRange(range), underline_color, thickness.value(),
-        background_color);
+    create_marker(EphemeralRange(range), underline_color, thickness.value(),
+                  background_color);
   }
 }
 
+}  // namespace
+
+void Internals::addCompositionMarker(const Range* range,
+                                     const String& underline_color_value,
+                                     const String& thickness_value,
+                                     const String& background_color_value,
+                                     ExceptionState& exception_state) {
+  DocumentMarkerController& document_marker_controller =
+      range->OwnerDocument().Markers();
+  addStyleableMarkerHelper(
+      range, underline_color_value, thickness_value, background_color_value,
+      exception_state,
+      [&document_marker_controller](
+          const EphemeralRange& range, Color underline_color,
+          StyleableMarker::Thickness thickness, Color background_color) {
+        document_marker_controller.AddCompositionMarker(
+            range, underline_color, thickness, background_color);
+      });
+}
+
+void Internals::addActiveSuggestionMarker(const Range* range,
+                                          const String& underline_color_value,
+                                          const String& thickness_value,
+                                          const String& background_color_value,
+                                          ExceptionState& exception_state) {
+  DocumentMarkerController& document_marker_controller =
+      range->OwnerDocument().Markers();
+  addStyleableMarkerHelper(
+      range, underline_color_value, thickness_value, background_color_value,
+      exception_state,
+      [&document_marker_controller](
+          const EphemeralRange& range, Color underline_color,
+          StyleableMarker::Thickness thickness, Color background_color) {
+        document_marker_controller.AddActiveSuggestionMarker(
+            range, underline_color, thickness, background_color);
+      });
+}
+
 void Internals::setTextMatchMarkersActive(Node* node,
                                           unsigned start_offset,
                                           unsigned end_offset,
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 2e98fa2e..91772ee8 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -193,6 +193,11 @@
                             const String& thickness_value,
                             const String& background_color_value,
                             ExceptionState&);
+  void addActiveSuggestionMarker(const Range*,
+                                 const String& underline_color_value,
+                                 const String& thickness_value,
+                                 const String& background_color_value,
+                                 ExceptionState&);
   void setTextMatchMarkersActive(Node*,
                                  unsigned start_offset,
                                  unsigned end_offset,
diff --git a/third_party/WebKit/Source/core/testing/Internals.idl b/third_party/WebKit/Source/core/testing/Internals.idl
index cbe31e0..1446bf6 100644
--- a/third_party/WebKit/Source/core/testing/Internals.idl
+++ b/third_party/WebKit/Source/core/testing/Internals.idl
@@ -114,6 +114,7 @@
     [RaisesException] DOMString markerDescriptionForNode(Node node, DOMString markerType, unsigned long index);
     [RaisesException] void addTextMatchMarker(Range range, DOMString matchStatus);
     [RaisesException] void addCompositionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
+    [RaisesException] void addActiveSuggestionMarker(Range range, DOMString underlineColorValue, DOMString thicknessValue, DOMString backgroundColorValue);
     void setTextMatchMarkersActive(Node node, unsigned long startOffset, unsigned long endOffset, boolean active);
     void setMarkedTextMatchesAreHighlighted(Document document, boolean highlight);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
index 9b68900..3cc5a05 100644
--- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
+++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleView.js
@@ -71,7 +71,8 @@
     toolbar.appendToolbarItem(this._consoleContextSelector.toolbarItem());
     toolbar.appendSeparator();
     toolbar.appendToolbarItem(this._filter._textFilterUI);
-    toolbar.appendToolbarItem(this._filter._levelComboBox);
+    toolbar.appendToolbarItem(this._filter._levelMenuButton);
+    toolbar.appendToolbarItem(this._filter._levelMenuButtonArrow);
     toolbar.appendToolbarItem(this._progressToolbarItem);
     toolbar.appendSpacer();
     toolbar.appendToolbarItem(this._filterStatusText);
@@ -1007,8 +1008,8 @@
     this._filterChanged = filterChangedCallback;
 
     this._messageURLFiltersSetting = Common.settings.createSetting('messageURLFilters', {});
-    this._messageLevelFiltersSetting =
-        Common.settings.createSetting('messageLevelFilters2', ConsoleModel.ConsoleMessage.MessageLevel.Info);
+    this._messageLevelFiltersSetting = Console.ConsoleViewFilter.levelFilterSetting();
+
     this._hideNetworkMessagesSetting = Common.moduleSetting('hideNetworkMessages');
     this._filterByExecutionContextSetting = Common.moduleSetting('selectedContextFilterEnabled');
     this._filterByConsoleAPISetting = Common.moduleSetting('consoleAPIFilterEnabled');
@@ -1022,15 +1023,92 @@
     this._textFilterUI = new UI.ToolbarInput(Common.UIString('Filter'), 0.2, 1, true);
     this._textFilterUI.addEventListener(UI.ToolbarInput.Event.TextChanged, this._textFilterChanged, this);
 
-    var levels = [
-      {value: ConsoleModel.ConsoleMessage.MessageLevel.Verbose, label: Common.UIString('Verbose')},
-      {value: ConsoleModel.ConsoleMessage.MessageLevel.Info, label: Common.UIString('Info'), default: true},
-      {value: ConsoleModel.ConsoleMessage.MessageLevel.Warning, label: Common.UIString('Warnings')},
-      {value: ConsoleModel.ConsoleMessage.MessageLevel.Error, label: Common.UIString('Errors')}
-    ];
+    this._levelLabels = {};
+    this._levelLabels[ConsoleModel.ConsoleMessage.MessageLevel.Verbose] = Common.UIString('Verbose');
+    this._levelLabels[ConsoleModel.ConsoleMessage.MessageLevel.Info] = Common.UIString('Info');
+    this._levelLabels[ConsoleModel.ConsoleMessage.MessageLevel.Warning] = Common.UIString('Warnings');
+    this._levelLabels[ConsoleModel.ConsoleMessage.MessageLevel.Error] = Common.UIString('Errors');
 
-    this._levelComboBox =
-        new UI.ToolbarSettingComboBox(levels, this._messageLevelFiltersSetting, Common.UIString('Level'));
+    this._levelMenuButton = new UI.ToolbarText('');
+    this._levelMenuButtonArrow = new UI.ToolbarItem(UI.Icon.create('smallicon-triangle-down'));
+    this._levelMenuButton.element.addEventListener('click', this._showLevelContextMenu.bind(this));
+    this._levelMenuButtonArrow.element.addEventListener('click', this._showLevelContextMenu.bind(this));
+
+    this._updateLevelMenuButtonText();
+    this._messageLevelFiltersSetting.addChangeListener(this._updateLevelMenuButtonText.bind(this));
+  }
+
+  /**
+   * @return {!Common.Setting}
+   */
+  static levelFilterSetting() {
+    return Common.settings.createSetting('messageLevelFilters', Console.ConsoleViewFilter.defaultLevelsFilterValue());
+  }
+
+  /**
+   * @return {!Object<string, boolean>}
+   */
+  static allLevelsFilterValue() {
+    var result = {};
+    for (var name of Object.values(ConsoleModel.ConsoleMessage.MessageLevel))
+      result[name] = true;
+    return result;
+  }
+
+  /**
+   * @return {!Object<string, boolean>}
+   */
+  static defaultLevelsFilterValue() {
+    var result = Console.ConsoleViewFilter.allLevelsFilterValue();
+    result[ConsoleModel.ConsoleMessage.MessageLevel.Verbose] = false;
+    return result;
+  }
+
+  _updateLevelMenuButtonText() {
+    var isAll = true;
+    var isDefault = true;
+    var allValue = Console.ConsoleViewFilter.allLevelsFilterValue();
+    var defaultValue = Console.ConsoleViewFilter.defaultLevelsFilterValue();
+
+    var text = null;
+    var levels = this._messageLevelFiltersSetting.get();
+    for (var name of Object.values(ConsoleModel.ConsoleMessage.MessageLevel)) {
+      isAll = isAll && levels[name] === allValue[name];
+      isDefault = isDefault && levels[name] === defaultValue[name];
+      if (levels[name])
+        text = text ? Common.UIString('Custom levels') : Common.UIString('%s only', this._levelLabels[name]);
+    }
+    if (isAll)
+      text = Common.UIString('All levels');
+    else if (isDefault)
+      text = Common.UIString('Default levels');
+    else
+      text = text || Common.UIString('Hide all');
+    this._levelMenuButton.setText(text);
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  _showLevelContextMenu(event) {
+    var setting = this._messageLevelFiltersSetting;
+    var levels = setting.get();
+
+    var contextMenu = new UI.ContextMenu(event, true);
+    contextMenu.appendItem(
+        Common.UIString('Default'), () => setting.set(Console.ConsoleViewFilter.defaultLevelsFilterValue()));
+    contextMenu.appendSeparator();
+    for (var level in this._levelLabels)
+      contextMenu.appendCheckboxItem(this._levelLabels[level], toggleShowLevel.bind(null, level), levels[level]);
+    contextMenu.show();
+
+    /**
+     * @param {string} level
+     */
+    function toggleShowLevel(level) {
+      levels[level] = !levels[level];
+      setting.set(levels);
+    }
   }
 
   _textFilterChanged() {
@@ -1104,9 +1182,8 @@
     if (message.url && this._messageURLFiltersSetting.get()[message.url])
       return false;
 
-    var filterOrdinal = ConsoleModel.ConsoleMessage.MessageLevel.ordinal(
-        /** @type {!ConsoleModel.ConsoleMessage.MessageLevel} */ (this._messageLevelFiltersSetting.get()));
-    if (message.level && ConsoleModel.ConsoleMessage.MessageLevel.ordinal(message.level) < filterOrdinal)
+    var levels = this._messageLevelFiltersSetting.get();
+    if (!levels[message.level])
       return false;
 
     if (this._filterRegex) {
@@ -1126,7 +1203,7 @@
 
   reset() {
     this._messageURLFiltersSetting.set({});
-    this._messageLevelFiltersSetting.set(ConsoleModel.ConsoleMessage.MessageLevel.Info);
+    this._messageLevelFiltersSetting.set(Console.ConsoleViewFilter.defaultLevelsFilterValue());
     this._filterByExecutionContextSetting.set(false);
     this._filterByConsoleAPISetting.set(false);
     this._hideNetworkMessagesSetting.set(false);
diff --git a/third_party/WebKit/Source/devtools/front_end/console_model/ConsoleModel.js b/third_party/WebKit/Source/devtools/front_end/console_model/ConsoleModel.js
index 3831e39..bf9eab73 100644
--- a/third_party/WebKit/Source/devtools/front_end/console_model/ConsoleModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/console_model/ConsoleModel.js
@@ -649,20 +649,6 @@
   Error: 'error'
 };
 
-/**
- * @param {!ConsoleModel.ConsoleMessage.MessageLevel} level
- * @return {number}
- */
-ConsoleModel.ConsoleMessage.MessageLevel.ordinal = function(level) {
-  if (level === ConsoleModel.ConsoleMessage.MessageLevel.Verbose)
-    return 0;
-  if (level === ConsoleModel.ConsoleMessage.MessageLevel.Info)
-    return 1;
-  if (level === ConsoleModel.ConsoleMessage.MessageLevel.Warning)
-    return 2;
-  return 3;
-};
-
 ConsoleModel.ConsoleModel._events = Symbol('ConsoleModel.ConsoleModel.events');
 
 /**
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 dfdab46..d5afb49a 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -68,21 +68,10 @@
     this._breadcrumbs.show(crumbsContainer);
     this._breadcrumbs.addEventListener(Elements.ElementsBreadcrumbs.Events.NodeSelected, this._crumbNodeSelected, this);
 
-    /** @type {?UI.Widget} */
-    this._currentToolbarPane = null;
-    /** @type {?UI.Widget} */
-    this._animatedToolbarPane = null;
-    /** @type {?UI.Widget} */
-    this._pendingWidget = null;
-    /** @type {?UI.ToolbarToggle} */
-    this._pendingWidgetToggle = null;
-
     this._stylesWidget = new Elements.StylesSidebarPane();
     this._computedStyleWidget = new Elements.ComputedStyleWidget();
     this._metricsWidget = new Elements.MetricsSidebarPane();
 
-    this._stylesSidebarToolbar = this._createStylesSidebarToolbar();
-
     Common.moduleSetting('sidebarPosition').addChangeListener(this._updateSidebarPosition.bind(this));
     this._updateSidebarPosition();
 
@@ -118,26 +107,6 @@
   }
 
   /**
-   * @return {!Element}
-   */
-  _createStylesSidebarToolbar() {
-    var container = createElementWithClass('div', 'styles-sidebar-pane-toolbar-container');
-    var hbox = container.createChild('div', 'hbox styles-sidebar-pane-toolbar');
-    var filterContainerElement = hbox.createChild('div', 'styles-sidebar-pane-filter-box');
-    var filterInput = Elements.StylesSidebarPane.createPropertyFilterElement(
-        Common.UIString('Filter'), hbox, this._stylesWidget.onFilterChanged.bind(this._stylesWidget));
-    UI.ARIAUtils.setAccessibleName(filterInput, Common.UIString('Filter Styles'));
-    filterContainerElement.appendChild(filterInput);
-    var toolbar = new UI.Toolbar('styles-pane-toolbar', hbox);
-    toolbar.makeToggledGray();
-    toolbar.appendLocationItems('styles-sidebarpane-toolbar');
-    var toolbarPaneContainer = container.createChild('div', 'styles-sidebar-toolbar-pane-container');
-    this._toolbarPaneElement = createElementWithClass('div', 'styles-sidebar-toolbar-pane');
-    toolbarPaneContainer.appendChild(this._toolbarPaneElement);
-    return container;
-  }
-
-  /**
    * @override
    * @param {string} locationName
    * @return {?UI.ViewLocation}
@@ -151,67 +120,8 @@
    * @param {?UI.ToolbarToggle} toggle
    */
   showToolbarPane(widget, toggle) {
-    if (this._pendingWidgetToggle)
-      this._pendingWidgetToggle.setToggled(false);
-    this._pendingWidgetToggle = toggle;
-
-    if (this._animatedToolbarPane)
-      this._pendingWidget = widget;
-    else
-      this._startToolbarPaneAnimation(widget);
-
-    if (widget && toggle)
-      toggle.setToggled(true);
-  }
-
-  /**
-   * @param {?UI.Widget} widget
-   */
-  _startToolbarPaneAnimation(widget) {
-    if (widget === this._currentToolbarPane)
-      return;
-
-    if (widget && this._currentToolbarPane) {
-      this._currentToolbarPane.detach();
-      widget.show(this._toolbarPaneElement);
-      this._currentToolbarPane = widget;
-      this._currentToolbarPane.focus();
-      return;
-    }
-
-    this._animatedToolbarPane = widget;
-
-    if (this._currentToolbarPane)
-      this._toolbarPaneElement.style.animationName = 'styles-element-state-pane-slideout';
-    else if (widget)
-      this._toolbarPaneElement.style.animationName = 'styles-element-state-pane-slidein';
-
-    if (widget)
-      widget.show(this._toolbarPaneElement);
-
-    var listener = onAnimationEnd.bind(this);
-    this._toolbarPaneElement.addEventListener('animationend', listener, false);
-
-    /**
-     * @this {Elements.ElementsPanel}
-     */
-    function onAnimationEnd() {
-      this._toolbarPaneElement.style.removeProperty('animation-name');
-      this._toolbarPaneElement.removeEventListener('animationend', listener, false);
-
-      if (this._currentToolbarPane)
-        this._currentToolbarPane.detach();
-
-      this._currentToolbarPane = this._animatedToolbarPane;
-      if (this._currentToolbarPane)
-        this._currentToolbarPane.focus();
-      this._animatedToolbarPane = null;
-
-      if (this._pendingWidget) {
-        this._startToolbarPaneAnimation(this._pendingWidget);
-        this._pendingWidget = null;
-      }
-    }
+    // TODO(luoe): remove this function once its providers have an alternative way to reveal their views.
+    this._stylesWidget.showToolbarPane(widget, toggle);
   }
 
   /**
@@ -840,11 +750,8 @@
     this._splitWidget.setVertical(this._splitMode === Elements.ElementsPanel._splitMode.Vertical);
     this.showToolbarPane(null /* widget */, null /* toggle */);
 
-    var matchedStylesContainer = new UI.VBox();
-    matchedStylesContainer.element.appendChild(this._stylesSidebarToolbar);
     var matchedStylePanesWrapper = new UI.VBox();
     matchedStylePanesWrapper.element.classList.add('style-panes-wrapper');
-    matchedStylePanesWrapper.show(matchedStylesContainer.element);
     this._stylesWidget.show(matchedStylePanesWrapper.element);
 
     var computedStylePanesWrapper = new UI.VBox();
@@ -893,12 +800,12 @@
 
       var splitWidget = new UI.SplitWidget(true, true, 'stylesPaneSplitViewState', 215);
       splitWidget.show(stylesView.element);
-      splitWidget.setMainWidget(matchedStylesContainer);
+      splitWidget.setMainWidget(matchedStylePanesWrapper);
       splitWidget.setSidebarWidget(computedStylePanesWrapper);
     } else {
       // Styles and computed are in separate tabs.
       stylesView.element.classList.add('flex-auto', 'metrics-and-styles');
-      matchedStylesContainer.show(stylesView.element);
+      matchedStylePanesWrapper.show(stylesView.element);
 
       var computedView = new UI.SimpleView(Common.UIString('Computed'));
       computedView.element.classList.add('composite', 'fill', 'metrics-and-computed');
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index b6757d5..85b15020 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -35,6 +35,15 @@
     Common.moduleSetting('colorFormat').addChangeListener(this.update.bind(this));
     Common.moduleSetting('textEditorIndent').addChangeListener(this.update.bind(this));
 
+    /** @type {?UI.Widget} */
+    this._currentToolbarPane = null;
+    /** @type {?UI.Widget} */
+    this._animatedToolbarPane = null;
+    /** @type {?UI.Widget} */
+    this._pendingWidget = null;
+    /** @type {?UI.ToolbarToggle} */
+    this._pendingWidgetToggle = null;
+    this._toolbarPaneElement = this._createStylesSidebarToolbar();
     this._sectionsContainer = this.element.createChild('div');
     this._swatchPopoverHelper = new InlineEditor.SwatchPopoverHelper();
     this._linkifier = new Components.Linkifier(Elements.StylesSidebarPane._maxLinkLength, /* useLinkDecorator */ true);
@@ -222,7 +231,7 @@
   /**
    * @param {?RegExp} regex
    */
-  onFilterChanged(regex) {
+  _onFilterChanged(regex) {
     this._filterRegex = regex;
     this._updateFilter();
   }
@@ -513,6 +522,94 @@
   _clipboardCopy(event) {
     Host.userMetrics.actionTaken(Host.UserMetrics.Action.StyleRuleCopied);
   }
+
+  /**
+   * @return {!Element}
+   */
+  _createStylesSidebarToolbar() {
+    var container = this.element.createChild('div', 'styles-sidebar-pane-toolbar-container');
+    var hbox = container.createChild('div', 'hbox styles-sidebar-pane-toolbar');
+    var filterContainerElement = hbox.createChild('div', 'styles-sidebar-pane-filter-box');
+    var filterInput = Elements.StylesSidebarPane.createPropertyFilterElement(
+        Common.UIString('Filter'), hbox, this._onFilterChanged.bind(this));
+    UI.ARIAUtils.setAccessibleName(filterInput, Common.UIString('Filter Styles'));
+    filterContainerElement.appendChild(filterInput);
+    var toolbar = new UI.Toolbar('styles-pane-toolbar', hbox);
+    toolbar.makeToggledGray();
+    toolbar.appendLocationItems('styles-sidebarpane-toolbar');
+    var toolbarPaneContainer = container.createChild('div', 'styles-sidebar-toolbar-pane-container');
+    var toolbarPaneContent = toolbarPaneContainer.createChild('div', 'styles-sidebar-toolbar-pane');
+
+    return toolbarPaneContent;
+  }
+
+  /**
+   * @param {?UI.Widget} widget
+   * @param {?UI.ToolbarToggle} toggle
+   */
+  showToolbarPane(widget, toggle) {
+    if (this._pendingWidgetToggle)
+      this._pendingWidgetToggle.setToggled(false);
+    this._pendingWidgetToggle = toggle;
+
+    if (this._animatedToolbarPane)
+      this._pendingWidget = widget;
+    else
+      this._startToolbarPaneAnimation(widget);
+
+    if (widget && toggle)
+      toggle.setToggled(true);
+  }
+
+  /**
+   * @param {?UI.Widget} widget
+   */
+  _startToolbarPaneAnimation(widget) {
+    if (widget === this._currentToolbarPane)
+      return;
+
+    if (widget && this._currentToolbarPane) {
+      this._currentToolbarPane.detach();
+      widget.show(this._toolbarPaneElement);
+      this._currentToolbarPane = widget;
+      this._currentToolbarPane.focus();
+      return;
+    }
+
+    this._animatedToolbarPane = widget;
+
+    if (this._currentToolbarPane)
+      this._toolbarPaneElement.style.animationName = 'styles-element-state-pane-slideout';
+    else if (widget)
+      this._toolbarPaneElement.style.animationName = 'styles-element-state-pane-slidein';
+
+    if (widget)
+      widget.show(this._toolbarPaneElement);
+
+    var listener = onAnimationEnd.bind(this);
+    this._toolbarPaneElement.addEventListener('animationend', listener, false);
+
+    /**
+     * @this {!Elements.StylesSidebarPane}
+     */
+    function onAnimationEnd() {
+      this._toolbarPaneElement.style.removeProperty('animation-name');
+      this._toolbarPaneElement.removeEventListener('animationend', listener, false);
+
+      if (this._currentToolbarPane)
+        this._currentToolbarPane.detach();
+
+      this._currentToolbarPane = this._animatedToolbarPane;
+      if (this._currentToolbarPane)
+        this._currentToolbarPane.focus();
+      this._animatedToolbarPane = null;
+
+      if (this._pendingWidget) {
+        this._startToolbarPaneAnimation(this._pendingWidget);
+        this._pendingWidget = null;
+      }
+    }
+  }
 };
 
 Elements.StylesSidebarPane._maxLinkLength = 30;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
index 73c50f4..84a7679 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DOMDebuggerModel.js
@@ -37,11 +37,9 @@
     if (!remoteObject.objectId)
       return [];
 
-    var payloads = await this._agent.getEventListeners(
-        /** @type {string} */ (remoteObject.objectId), undefined, undefined,
-        (error, payloads) => error ? [] : payloads);
+    var payloads = await this._agent.getEventListeners(/** @type {string} */ (remoteObject.objectId));
     var eventListeners = [];
-    for (var payload of payloads) {
+    for (var payload of payloads || []) {
       var location = this._runtimeModel.debuggerModel().createRawLocationByScriptId(
           payload.scriptId, payload.lineNumber, payload.columnNumber);
       if (!location)
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index 37cc0e2f..c14bb43 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -460,6 +460,13 @@
   }
 
   /**
+   * @return {string}
+   */
+  text() {
+    return this.element.textContent;
+  }
+
+  /**
    * @param {string} text
    */
   setText(text) {
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
index f943fa7..418361ba 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -46,10 +46,6 @@
 
 ref_types = {}
 
-NON_PROMISIFIED_DOMAINS = frozenset([
-    "DOMDebugger",
-])
-
 
 def full_qualified_type_id(domain_name, type_id):
     if type_id.find(".") == -1:
@@ -121,7 +117,6 @@
 
     for domain in domains:
         domain_name = domain["domain"]
-        is_promisified = domain_name not in NON_PROMISIFIED_DOMAINS
 
         output_file.write("Protocol.%s = {};\n" % domain_name)
         output_file.write("\n\n/**\n * @constructor\n*/\n")
@@ -158,20 +153,14 @@
                         else:
                             returns.append("%s" % out_param_type)
 
-                if is_promisified:
-                    if has_return_value and len(command["returns"]) > 0:
-                        out_param_type = param_type(domain_name, command["returns"][0])
-                        if re.match(r"^[!?]", out_param_type[:1]):
-                            out_param_type = out_param_type[1:]
-                        out_param_type = "?%s" % out_param_type
-                    else:
-                        out_param_type = "undefined"
-                    output_file.write(" * @return {!Promise<%s>}\n" % out_param_type)
+                if has_return_value and len(command["returns"]) > 0:
+                    out_param_type = param_type(domain_name, command["returns"][0])
+                    if re.match(r"^[!?]", out_param_type[:1]):
+                        out_param_type = out_param_type[1:]
+                    out_param_type = "?%s" % out_param_type
                 else:
-                    output_file.write(" * @param {function(%s):T=} opt_callback\n" % ", ".join(returns))
-                    output_file.write(" * @return {!Promise<T>}\n")
-                    output_file.write(" * @template T\n")
-                    params.append("opt_callback")
+                    out_param_type = "undefined"
+                output_file.write(" * @return {!Promise<%s>}\n" % out_param_type)
 
                 output_file.write(" */\n")
                 output_file.write("Protocol.%sAgent.prototype.%s = function(%s) {};\n" %
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index 8ad521c..72ad9945 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -1414,6 +1414,7 @@
       case DocumentMarker::kSpelling:
       case DocumentMarker::kGrammar:
       case DocumentMarker::kTextMatch:
+      case DocumentMarker::kActiveSuggestion:
         marker_types.push_back(marker->GetType());
         marker_ranges.push_back(
             AXRange(marker->StartOffset(), marker->EndOffset()));
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
index eb8fdd5..d07c65b 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.cpp
@@ -11,6 +11,10 @@
 
 namespace blink {
 
+namespace {
+RuntimeCallStats* g_runtime_call_stats_for_testing = nullptr;
+}
+
 void RuntimeCallTimer::Start(RuntimeCallCounter* counter,
                              RuntimeCallTimer* parent) {
   DCHECK(!IsRunning());
@@ -46,9 +50,21 @@
 
 // static
 RuntimeCallStats* RuntimeCallStats::From(v8::Isolate* isolate) {
+  if (g_runtime_call_stats_for_testing)
+    return g_runtime_call_stats_for_testing;
   return V8PerIsolateData::From(isolate)->GetRuntimeCallStats();
 }
 
+void RuntimeCallStats::Enter(RuntimeCallTimer* timer, CounterId id) {
+  timer->Start(GetCounter(id), current_timer_);
+  current_timer_ = timer;
+}
+
+void RuntimeCallStats::Leave(RuntimeCallTimer* timer) {
+  DCHECK_EQ(timer, current_timer_);
+  current_timer_ = timer->Stop();
+}
+
 void RuntimeCallStats::Reset() {
   for (int i = 0; i < number_of_counters_; i++) {
     counters_[i].Reset();
@@ -58,14 +74,28 @@
 String RuntimeCallStats::ToString() const {
   StringBuilder builder;
   builder.Append("Runtime Call Stats for Blink \n");
-  builder.Append("Name                              Count     Time (ms)\n\n");
+  builder.Append(
+      "Name                                               Count     Time "
+      "(ms)\n\n");
   for (int i = 0; i < number_of_counters_; i++) {
     const RuntimeCallCounter* counter = &counters_[i];
-    builder.Append(String::Format("%-32s  %8" PRIu64 "  %9.3f\n",
+    builder.Append(String::Format("%-50s  %8" PRIu64 "  %9.3f\n",
                                   counter->GetName(), counter->GetCount(),
                                   counter->GetTime().InMillisecondsF()));
   }
   return builder.ToString();
 }
 
+// static
+void RuntimeCallStats::SetRuntimeCallStatsForTesting() {
+  DEFINE_STATIC_LOCAL(RuntimeCallStatsForTesting, s_rcs_for_testing, ());
+  g_runtime_call_stats_for_testing =
+      static_cast<RuntimeCallStats*>(&s_rcs_for_testing);
+}
+
+// static
+void RuntimeCallStats::ClearRuntimeCallStatsForTesting() {
+  g_runtime_call_stats_for_testing = nullptr;
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
index 546ddea..5d27c4b 100644
--- a/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
+++ b/third_party/WebKit/Source/platform/bindings/RuntimeCallStats.h
@@ -98,8 +98,15 @@
   static RuntimeCallStats* From(v8::Isolate*);
 
 // Counters
-#define FOR_EACH_COUNTER(V) \
-  V(TestCounter1)           \
+#define FOR_EACH_COUNTER(V)          \
+  V(UpdateStyle)                     \
+  V(UpdateLayout)                    \
+  V(CollectGarbage)                  \
+  V(PerformIdleLazySweep)            \
+  V(UpdateLayerPositionsAfterLayout) \
+  V(PaintContents)                   \
+  V(ProcessStyleSheet)               \
+  V(TestCounter1)                    \
   V(TestCounter2)
 
   enum class CounterId : uint16_t {
@@ -111,18 +118,12 @@
 
   // Enters a new recording scope by pausing the currently running timer that
   // was started by the current instance, and starting <timer>.
-  void Enter(RuntimeCallTimer* timer, CounterId id) {
-    timer->Start(GetCounter(id), current_timer_);
-    current_timer_ = timer;
-  }
+  virtual void Enter(RuntimeCallTimer*, CounterId);
 
   // Exits the current recording scope, by stopping <timer> (and updating the
   // counter associated with <timer>) and resuming the timer that was paused
   // before entering the current scope.
-  void Leave(RuntimeCallTimer* timer) {
-    DCHECK_EQ(timer, current_timer_);
-    current_timer_ = timer->Stop();
-  }
+  virtual void Leave(RuntimeCallTimer*);
 
   // Reset all the counters.
   void Reset();
@@ -133,6 +134,10 @@
 
   String ToString() const;
 
+  // Use these two functions to stub out RuntimeCallStats in tests.
+  static void SetRuntimeCallStatsForTesting();
+  static void ClearRuntimeCallStatsForTesting();
+
  private:
   RuntimeCallTimer* current_timer_ = nullptr;
   RuntimeCallCounter counters_[static_cast<int>(CounterId::kNumberOfCounters)];
@@ -143,8 +148,6 @@
 // A utility class that creates a RuntimeCallTimer and uses it with
 // RuntimeCallStats to measure execution time of a C++ scope.
 class PLATFORM_EXPORT RuntimeCallTimerScope {
-  STATIC_ONLY(RuntimeCallTimerScope);
-
  public:
   RuntimeCallTimerScope(RuntimeCallStats* stats,
                         RuntimeCallStats::CounterId counter)
@@ -158,6 +161,12 @@
   RuntimeCallTimer timer_;
 };
 
+// Used to stub out RuntimeCallStats for testing.
+class RuntimeCallStatsForTesting : public RuntimeCallStats {
+  void Enter(RuntimeCallTimer*, RuntimeCallStats::CounterId) override {}
+  void Leave(RuntimeCallTimer*) override {}
+};
+
 }  // namespace blink
 
 #endif  // RuntimeCallStats_h
diff --git a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
index 05702a7..684ec562 100644
--- a/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ContentLayerDelegate.cpp
@@ -25,6 +25,8 @@
 
 #include "platform/graphics/ContentLayerDelegate.h"
 
+#include "platform/bindings/RuntimeCallStats.h"
+#include "platform/bindings/V8PerIsolateData.h"
 #include "platform/geometry/IntRect.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/GraphicsLayer.h"
@@ -55,6 +57,9 @@
     WebDisplayItemList* web_display_item_list,
     WebContentLayerClient::PaintingControlSetting painting_control) {
   TRACE_EVENT0("blink,benchmark", "ContentLayerDelegate::paintContents");
+  RuntimeCallTimerScope runtime_timer_scope(
+      RuntimeCallStats::From(V8PerIsolateData::MainThreadIsolate()),
+      RuntimeCallStats::CounterId::kPaintContents);
 
   PaintController& paint_controller = graphics_layer_->GetPaintController();
   paint_controller.SetDisplayItemConstructionIsDisabled(
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 4ea6db5..58dc75b9 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -36,6 +36,7 @@
 #include "platform/Histogram.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/ScriptForbiddenScope.h"
+#include "platform/bindings/RuntimeCallStats.h"
 #include "platform/heap/BlinkGCMemoryDumpProvider.h"
 #include "platform/heap/CallbackStack.h"
 #include "platform/heap/Handle.h"
@@ -617,6 +618,10 @@
   if (SweepForbidden())
     return;
 
+  RuntimeCallTimerScope runtime_scope(
+      RuntimeCallStats::From(GetIsolate()),
+      RuntimeCallStats::CounterId::kPerformIdleLazySweep);
+
   TRACE_EVENT1("blink_gc,devtools.timeline",
                "ThreadState::performIdleLazySweep", "idleDeltaInSeconds",
                deadline_seconds - MonotonicallyIncreasingTime());
@@ -1437,6 +1442,12 @@
   CHECK(!IsGCForbidden());
   CompleteSweep();
 
+  Optional<RuntimeCallTimerScope> timer_scope;
+  if (v8::Isolate* isolate = GetIsolate()) {
+    timer_scope.emplace(RuntimeCallStats::From(isolate),
+                        RuntimeCallStats::CounterId::kCollectGarbage);
+  }
+
   GCForbiddenScope gc_forbidden_scope(this);
 
   {
diff --git a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
index c5da7373..16646c3f 100644
--- a/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
+++ b/third_party/WebKit/Source/web/AssertMatchingEnums.cpp
@@ -395,6 +395,8 @@
 STATIC_ASSERT_ENUM(kWebAXMarkerTypeSpelling, DocumentMarker::kSpelling);
 STATIC_ASSERT_ENUM(kWebAXMarkerTypeGrammar, DocumentMarker::kGrammar);
 STATIC_ASSERT_ENUM(kWebAXMarkerTypeTextMatch, DocumentMarker::kTextMatch);
+STATIC_ASSERT_ENUM(kWebAXMarkerTypeActiveSuggestion,
+                   DocumentMarker::kActiveSuggestion);
 
 STATIC_ASSERT_ENUM(kWebAXTextStyleNone, kTextStyleNone);
 STATIC_ASSERT_ENUM(kWebAXTextStyleBold, kTextStyleBold);
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index 0cc781d4..81e3d64 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -216,16 +216,6 @@
   // in all subframes, both remote and local.
 }
 
-WebDataSource* WebRemoteFrameImpl::ProvisionalDataSource() const {
-  NOTREACHED();
-  return nullptr;
-}
-
-WebDataSource* WebRemoteFrameImpl::DataSource() const {
-  NOTREACHED();
-  return nullptr;
-}
-
 void WebRemoteFrameImpl::EnableViewSourceMode(bool enable) {
   NOTREACHED();
 }
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
index a2e40498..7836d34 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.h
@@ -72,8 +72,6 @@
                              WebFrameLoadType) override;
   void LoadRequest(const WebURLRequest&) override;
   void StopLoading() override;
-  WebDataSource* ProvisionalDataSource() const override;
-  WebDataSource* DataSource() const override;
   void EnableViewSourceMode(bool enable) override;
   bool IsViewSourceModeEnabled() const override;
   void SetReferrerForRequest(WebURLRequest&, const WebURL& referrer) override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index e718f63..05388c4 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -96,7 +96,6 @@
 #include "core/paint/PaintLayer.h"
 #include "core/timing/DOMWindowPerformance.h"
 #include "core/timing/Performance.h"
-#include "modules/accessibility/AXObjectCacheImpl.h"
 #include "modules/compositorworker/AnimationWorkletProxyClientImpl.h"
 #include "modules/compositorworker/CompositorWorkerProxyClientImpl.h"
 #include "modules/credentialmanager/CredentialManagerClient.h"
@@ -145,7 +144,6 @@
 #include "public/platform/WebTextInputInfo.h"
 #include "public/platform/WebURLRequest.h"
 #include "public/platform/WebVector.h"
-#include "public/web/WebAXObject.h"
 #include "public/web/WebActiveWheelFlingParameters.h"
 #include "public/web/WebAutofillClient.h"
 #include "public/web/WebConsoleMessage.h"
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
index c8713e6d..e0419bfb 100644
--- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4348,7 +4348,7 @@
       web_view_helper.WebView()->MainFrame());
 
   WebDataSource* data_source =
-      web_view_helper.WebView()->MainFrame()->DataSource();
+      web_view_helper.WebView()->MainFrameImpl()->DataSource();
   ASSERT_TRUE(data_source);
   EXPECT_EQ(ToKURL(base_url_ + "fixed_layout.html"),
             KURL(data_source->GetRequest().Url()));
@@ -4362,7 +4362,7 @@
   web_view_helper.InitializeAndLoad(first_url, true);
 
   WebDataSource* data_source =
-      web_view_helper.WebView()->MainFrame()->DataSource();
+      web_view_helper.WebView()->MainFrameImpl()->DataSource();
   ASSERT_TRUE(data_source);
   data_source->AppendRedirect(ToKURL(second_url));
 
@@ -4387,8 +4387,8 @@
   WebFrame* iframe =
       web_view_helper.WebView()->MainFrameImpl()->FindFrameByName(
           WebString::FromUTF8("ifr"));
-  ASSERT_TRUE(iframe);
-  WebDataSource* iframe_data_source = iframe->DataSource();
+  ASSERT_TRUE(iframe && iframe->IsWebLocalFrame());
+  WebDataSource* iframe_data_source = iframe->ToWebLocalFrame()->DataSource();
   ASSERT_TRUE(iframe_data_source);
   WebVector<WebURL> redirects;
   iframe_data_source->RedirectChain(redirects);
@@ -7342,7 +7342,7 @@
   FrameTestHelpers::WebViewHelper web_view_helper;
   web_view_helper.InitializeAndLoad(base_url_ + "fragment_middle_click.html",
                                     true);
-  WebFrame* frame = web_view_helper.WebView()->MainFrame();
+  WebLocalFrame* frame = web_view_helper.WebView()->MainFrameImpl();
   const FrameLoader& main_frame_loader =
       web_view_helper.WebView()->MainFrameImpl()->GetFrame()->Loader();
   Persistent<HistoryItem> first_item =
@@ -7401,7 +7401,7 @@
   RegisterMockedHttpURLLoad("reload_post.html");
   FrameTestHelpers::WebViewHelper web_view_helper;
   web_view_helper.InitializeAndLoad(base_url_ + "reload_post.html", true);
-  WebFrame* frame = web_view_helper.WebView()->MainFrame();
+  WebLocalFrame* frame = web_view_helper.WebView()->MainFrameImpl();
 
   FrameTestHelpers::LoadFrame(web_view_helper.WebView()->MainFrame(),
                               "javascript:document.forms[0].submit()");
@@ -7424,7 +7424,7 @@
   FrameTestHelpers::WebViewHelper web_view_helper;
   web_view_helper.InitializeAndLoad(base_url_ + "fragment_middle_click.html",
                                     true);
-  WebFrame* frame = web_view_helper.WebView()->MainFrame();
+  WebLocalFrame* frame = web_view_helper.WebView()->MainFrameImpl();
   const FrameLoader& main_frame_loader =
       web_view_helper.WebView()->MainFrameImpl()->GetFrame()->Loader();
   Persistent<HistoryItem> first_item =
@@ -8729,7 +8729,7 @@
   RegisterMockedHttpURLLoad("foo.html");
   FrameTestHelpers::WebViewHelper web_view_helper;
   web_view_helper.InitializeAndLoad(base_url_ + "foo.html", true);
-  WebFrame* frame = web_view_helper.WebView()->MainFrame();
+  WebLocalFrame* frame = web_view_helper.WebView()->MainFrameImpl();
   FrameTestHelpers::ReloadFrameBypassingCache(frame);
   EXPECT_EQ(WebCachePolicy::kBypassingCache,
             frame->DataSource()->GetRequest().GetCachePolicy());
diff --git a/third_party/WebKit/public/web/WebAXEnums.h b/third_party/WebKit/public/web/WebAXEnums.h
index 23d5cf7..1f97e0a 100644
--- a/third_party/WebKit/public/web/WebAXEnums.h
+++ b/third_party/WebKit/public/web/WebAXEnums.h
@@ -304,7 +304,9 @@
 enum WebAXMarkerType {
   kWebAXMarkerTypeSpelling = 1 << 0,
   kWebAXMarkerTypeGrammar = 1 << 1,
-  kWebAXMarkerTypeTextMatch = 1 << 2
+  kWebAXMarkerTypeTextMatch = 1 << 2,
+  // Skip DocumentMarker::MarkerType::Composition
+  kWebAXMarkerTypeActiveSuggestion = 1 << 4,
 };
 
 // Used for exposing text attributes.
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h
index 6349f1f..e141023 100644
--- a/third_party/WebKit/public/web/WebFrame.h
+++ b/third_party/WebKit/public/web/WebFrame.h
@@ -57,7 +57,6 @@
 class WebAssociatedURLLoader;
 struct WebAssociatedURLLoaderOptions;
 class WebDOMEvent;
-class WebDataSource;
 class WebDocument;
 class WebElement;
 class WebLocalFrame;
@@ -307,12 +306,6 @@
   // Stops any pending loads on the frame and its children.
   virtual void StopLoading() = 0;
 
-  // Returns the data source that is currently loading.  May be null.
-  virtual WebDataSource* ProvisionalDataSource() const = 0;
-
-  // Returns the data source that is currently loaded.
-  virtual WebDataSource* DataSource() const = 0;
-
   // View-source rendering mode.  Set this before loading an URL to cause
   // it to be rendered in view-source mode.
   virtual void EnableViewSourceMode(bool) = 0;
diff --git a/third_party/WebKit/public/web/WebLocalFrame.h b/third_party/WebKit/public/web/WebLocalFrame.h
index affbd2e9..7581208 100644
--- a/third_party/WebKit/public/web/WebLocalFrame.h
+++ b/third_party/WebKit/public/web/WebLocalFrame.h
@@ -26,6 +26,7 @@
 class WebAutofillClient;
 class WebContentSettingsClient;
 class WebData;
+class WebDataSource;
 class WebDevToolsAgent;
 class WebDevToolsAgentClient;
 class WebDoubleSize;
@@ -178,6 +179,12 @@
                         WebHistoryLoadType = kWebHistoryDifferentDocumentLoad,
                         bool is_client_redirect = false) = 0;
 
+  // Returns the data source that is currently loading.  May be null.
+  virtual WebDataSource* ProvisionalDataSource() const = 0;
+
+  // Returns the data source that is currently loaded.
+  virtual WebDataSource* DataSource() const = 0;
+
   enum FallbackContentResult {
     // An error page should be shown instead of fallback.
     NoFallbackContent,
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 01603248..5411a46 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -61554,6 +61554,23 @@
   </summary>
 </histogram>
 
+<histogram name="ResourceScheduler.PeakDelayableRequestsInFlight"
+    units="requests">
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Records the highest number of delayable requests that were in-flight when
+    the given request with higher priority was in-flight.
+  </summary>
+</histogram>
+
+<histogram name="ResourceScheduler.RequestsCount" units="requests count">
+  <owner>tbansal@chromium.org</owner>
+  <summary>
+    Records the count of number of requests in-flight. Recorded when a request
+    is started by the resource scheduler.
+  </summary>
+</histogram>
+
 <histogram name="ResourceScheduler.RequestTimeDeferred.Active">
   <obsolete>
     Deprecated 1/2016
@@ -93485,6 +93502,29 @@
       name="ResourceScheduler.ClientLoadedTime.Other.SwitchedToActive"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="ResourceSchedulerPeakDelayableRequestsInFlight">
+  <suffix name="LayoutBlocking"
+      label="Records the highest number of delayable requests that were
+             in-flight at the same time when a layout blocking request was
+             in-flight. Recorded every time a layout blocking request
+             finishes."/>
+  <suffix name="NonDelayable"
+      label="Records the highest number of delayable requests that were
+             in-flight at the same time when a non-delayable request was
+             in-flight. Recorded every time a non-delayable request finishes."/>
+  <affected-histogram name="ResourceScheduler.PeakDelayableRequestsInFlight"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="ResourceSchedulerRequestsCount">
+  <suffix name="All" label="All requests in-flight were counted."/>
+  <suffix name="Delayable" label="Delayable requests in-flight were counted."/>
+  <suffix name="NonDelayable"
+      label="Non-delayable requests in-flight were counted."/>
+  <suffix name="TotalLayoutBlocking"
+      label="Layout blocking requests in-flight were counted."/>
+  <affected-histogram name="ResourceScheduler.RequestsCount"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="ResourceType" separator=".">
   <suffix name="MainResource"/>
   <suffix name="Image"/>
diff --git a/tools/perf/page_sets/blank_page.py b/tools/perf/page_sets/blank_page.py
index 1858cfa..7ffff30a 100644
--- a/tools/perf/page_sets/blank_page.py
+++ b/tools/perf/page_sets/blank_page.py
@@ -7,8 +7,8 @@
 
 
 class BlankPage(page_module.Page):
-  def __init__(self, url, page_set):
-    super(BlankPage, self).__init__(url, page_set=page_set)
+  def __init__(self, url, page_set, name):
+    super(BlankPage, self).__init__(url, page_set=page_set, name=name)
 
   def RunPageInteractions(self, action_runner):
     # Request a RAF and wait for it to be processed to ensure that the metric
@@ -27,8 +27,9 @@
   """A single blank page."""
 
   def __init__(self):
-    super(BlankPageSet, self).__init__()
-    self.AddStory(BlankPage('file://blank_page/blank_page.html', self))
+    super(BlankPageSet, self).__init__(verify_names=True)
+    self.AddStory(BlankPage('file://blank_page/blank_page.html',
+                            self, 'blank_page.html'))
 
 
 class BlankPageTBM(page_module.Page):
diff --git a/tools/perf/page_sets/blank_page_with_extension_profile.py b/tools/perf/page_sets/blank_page_with_extension_profile.py
index b4c5b594..a20afee 100644
--- a/tools/perf/page_sets/blank_page_with_extension_profile.py
+++ b/tools/perf/page_sets/blank_page_with_extension_profile.py
@@ -10,17 +10,19 @@
 class BlankPageWithExtensionProfile(page_module.Page):
   """A single blank page loaded with a profile with many extensions."""
 
-  def __init__(self, url, page_set):
+  def __init__(self, url, page_set, name):
     super(BlankPageWithExtensionProfile, self).__init__(
         url=url, page_set=page_set,
         shared_page_state_class=extension_profile_shared_state.
-                                ExtensionProfileSharedState)
+                                ExtensionProfileSharedState,
+        name=name)
 
 
 class BlankPageSetWithExtensionProfile(story.StorySet):
   """PageSet tied to BlankPageWithExtensionProfile."""
 
   def __init__(self):
-    super(BlankPageSetWithExtensionProfile, self).__init__()
+    super(BlankPageSetWithExtensionProfile, self).__init__(verify_names=True)
     self.AddStory(BlankPageWithExtensionProfile(
-        'file://blank_page/blank_page.html', self))
+        'file://blank_page/blank_page.html', self,
+        'blank_page.html'))
diff --git a/tools/perf/page_sets/blank_page_with_large_profile.py b/tools/perf/page_sets/blank_page_with_large_profile.py
index 07d348e..9d268d5 100644
--- a/tools/perf/page_sets/blank_page_with_large_profile.py
+++ b/tools/perf/page_sets/blank_page_with_large_profile.py
@@ -7,17 +7,19 @@
 
 
 class BlankPageWithLargeProfile(page_module.Page):
-  def __init__(self, url, page_set):
+  def __init__(self, url, page_set, name):
     super(BlankPageWithLargeProfile, self).__init__(
         url=url, page_set=page_set,
         shared_page_state_class=pregenerated_large_profile_shared_state.
-        PregeneratedLargeProfileSharedState)
+        PregeneratedLargeProfileSharedState,
+        name=name)
 
 
 class BlankPageSetWithLargeProfile(story.StorySet):
   """A single blank page loaded with a large profile."""
 
   def __init__(self):
-    super(BlankPageSetWithLargeProfile, self).__init__()
+    super(BlankPageSetWithLargeProfile, self).__init__(verify_names=True)
     self.AddStory(BlankPageWithLargeProfile(
-        'file://blank_page/blank_page.html', self))
+        'file://blank_page/blank_page.html', self,
+        'blank_page.html'))
diff --git a/tools/perf/page_sets/chrome_signin.py b/tools/perf/page_sets/chrome_signin.py
index b7eabb2e..db695ff 100644
--- a/tools/perf/page_sets/chrome_signin.py
+++ b/tools/perf/page_sets/chrome_signin.py
@@ -12,12 +12,14 @@
   """A page that signs in a user to Chrome."""
 
   def __init__(self, page_set):
+    url = 'chrome://signin-internals'
     super(ChromeSigninPage, self).__init__(
-        url='chrome://signin-internals',
+        url=url,
         page_set=page_set,
         credentials_path='data/chrome_signin_credentials.json',
         credentials_bucket=story.INTERNAL_BUCKET,
-        shared_page_state_class=shared_page_state.SharedDesktopPageState)
+        shared_page_state_class=shared_page_state.SharedDesktopPageState,
+        name=url)
 
   def RunPageInteractions(self, action_runner):
     # Use page.credentials_path because it is automatically translated into a
@@ -31,5 +33,6 @@
   def __init__(self):
     super(ChromeSigninPageSet, self).__init__(
         archive_data_file='data/chrome_signin_archive.json',
-        cloud_storage_bucket=story.INTERNAL_BUCKET)
+        cloud_storage_bucket=story.INTERNAL_BUCKET,
+        verify_names=True)
     self.AddStory(ChromeSigninPage(self))
diff --git a/tools/perf/page_sets/startup_pages.py b/tools/perf/page_sets/startup_pages.py
index 59322bc0bb..0b6327d 100644
--- a/tools/perf/page_sets/startup_pages.py
+++ b/tools/perf/page_sets/startup_pages.py
@@ -23,7 +23,8 @@
   def __init__(self, url, page_set):
     super(StartedPage, self).__init__(
         url=url, page_set=page_set, startup_url=url,
-        shared_page_state_class=BrowserStartupSharedState)
+        shared_page_state_class=BrowserStartupSharedState,
+        name=url)
     self.archive_data_file = 'data/startup_pages.json'
 
   def RunNavigateSteps(self, action_runner):
@@ -47,7 +48,8 @@
   def __init__(self):
     super(StartupPagesPageSet, self).__init__(
         archive_data_file='data/startup_pages.json',
-        cloud_storage_bucket=story.PARTNER_BUCKET)
+        cloud_storage_bucket=story.PARTNER_BUCKET,
+        verify_names=True)
 
     # Typical page.
     self.AddStory(StartedPage('about:blank', self))
diff --git a/tools/perf/page_sets/webrtc_cases.py b/tools/perf/page_sets/webrtc_cases.py
index 94d3c4b..9a554a1 100644
--- a/tools/perf/page_sets/webrtc_cases.py
+++ b/tools/perf/page_sets/webrtc_cases.py
@@ -153,3 +153,7 @@
     self.DisableStory('audio_call_isac/1600_10s',
                       [story.expectations.ALL],
                       'crbug.com/468732')
+
+    self.DisableStory('30s_datachannel_transfer',
+                      [story.expectations.ALL_DESKTOP],
+                      'crbug.com/726811')
diff --git a/ui/accessibility/ax_enums.idl b/ui/accessibility/ax_enums.idl
index 013fb7e..3eb77fd 100644
--- a/ui/accessibility/ax_enums.idl
+++ b/ui/accessibility/ax_enums.idl
@@ -533,6 +533,8 @@
     word_ends
   };
 
+  // TODO(dmazzoni, nektar): make this list not grow exponentially as new
+  // MarkerTypes are added
   enum AXMarkerType {
     // Assignments are ignored by the parser, but are kept here for clarity.
     spelling = 1,
@@ -541,7 +543,17 @@
     text_match = 4,
     spelling_text_match = 5,
     grammar_text_match = 6,
-    spelling_grammar_text_match = 7
+    spelling_grammar_text_match = 7,
+    // DocumentMarker::MarkerType::Composition = 8 is ignored for accessibility
+    // purposes
+    active_suggestion = 16,
+    spelling_active_suggestion = 17,
+    grammar_active_suggestion = 18,
+    spelling_grammar_active_suggestion = 19,
+    text_match_active_suggestion = 20,
+    spelling_text_match_active_suggestion = 21,
+    grammar_text_match_active_suggestion = 22,
+    spelling_grammar_text_match_active_suggestion = 23
   };
 
   enum AXTextDirection {
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 2cb0504..eea07f3 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -926,6 +926,8 @@
             types_str += "grammar&";
           if (type & AX_MARKER_TYPE_TEXT_MATCH)
             types_str += "text_match&";
+          if (type & AX_MARKER_TYPE_ACTIVE_SUGGESTION)
+            types_str += "active_suggestion&";
 
           if (!types_str.empty())
             types_str = types_str.substr(0, types_str.size() - 1);
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index e0b23166f..325e13f 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -233,15 +233,17 @@
           base::MakeUnique<cc::DelayBasedTimeSource>(
               compositor->task_runner().get())));
   std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
-      compositor->task_runner().get(),
+      begin_frame_source.get(), compositor->task_runner().get(),
       display_output_surface->capabilities().max_frames_pending));
 
   data->display = base::MakeUnique<cc::Display>(
       &shared_bitmap_manager_, &gpu_memory_buffer_manager_, renderer_settings_,
-      compositor->frame_sink_id(), begin_frame_source.get(),
-      std::move(display_output_surface), std::move(scheduler),
+      compositor->frame_sink_id(), std::move(display_output_surface),
+      std::move(scheduler),
       base::MakeUnique<cc::TextureMailboxDeleter>(
           compositor->task_runner().get()));
+  GetSurfaceManager()->RegisterBeginFrameSource(begin_frame_source.get(),
+                                                compositor->frame_sink_id());
   // Note that we are careful not to destroy a prior |data->begin_frame_source|
   // until we have reset |data->display|.
   data->begin_frame_source = std::move(begin_frame_source);
@@ -286,6 +288,8 @@
   if (it == per_compositor_data_.end())
     return;
   PerCompositorData* data = it->second.get();
+  GetSurfaceManager()->UnregisterBeginFrameSource(
+      data->begin_frame_source.get());
   DCHECK(data);
 #if !defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
   if (data->surface_handle)