diff --git a/DEPS b/DEPS
index 9aa8ddf..28054b1 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'fc4ee229a653d0e9d71f828e513c9d458c1eab57',
+  'skia_revision': '8abb9f45379823f417371d3e99f42629fbccd579',
   # 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': '1115d8724ce832a77e1a85e0ba3fbee527ea7eb0',
+  'v8_revision': 'a47a2b11cb904b87c10c50ad2ff54668042d62ee',
   # 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': '21dd189fe50d297dd1224c06319e166c1ac6bae2',
+  'pdfium_revision': '3a4ebcc7c490eba0c22892ab04d1730c350fd0c0',
   # 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': 'ebf00ecf2e8397f7774dcd90c73f40fcba8097d5',
+  'catapult_revision': 'af47a939971b50a8f4c7b2e234ec7069ca196841',
   # 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' + '@' + '5e57726d6fe2833c957b5a33cd0aed19d67a4fa9',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '72eda82d069da578af04e5c4e8e411ae006b6a18',
 
   'src/third_party/webdriver/pylib':
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index 5c9301b5..734516a 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -64,10 +64,7 @@
                            public display::DisplayObserver,
                            public aura::WindowObserver {
  public:
-  DisplayManagerTest()
-      : removed_count_(0U),
-        root_window_destroyed_(false),
-        changed_metrics_(0U) {}
+  DisplayManagerTest() {}
   ~DisplayManagerTest() override {}
 
   void SetUp() override {
@@ -86,14 +83,15 @@
   uint32_t changed_metrics() const { return changed_metrics_; }
 
   string GetCountSummary() const {
-    return StringPrintf("%" PRIuS " %" PRIuS " %" PRIuS, changed_.size(),
-                        added_.size(), removed_count_);
+    return StringPrintf("%" PRIuS " %" PRIuS " %" PRIuS " %" PRIuS " %" PRIuS,
+                        changed_.size(), added_.size(), removed_count_,
+                        will_process_count_, did_process_count_);
   }
 
   void reset() {
     changed_.clear();
     added_.clear();
-    removed_count_ = 0U;
+    removed_count_ = will_process_count_ = did_process_count_ = 0U;
     changed_metrics_ = 0U;
     root_window_destroyed_ = false;
   }
@@ -118,6 +116,8 @@
   }
 
   // aura::DisplayObserver overrides:
+  void OnWillProcessDisplayChanges() override { ++will_process_count_; }
+  void OnDidProcessDisplayChanges() override { ++did_process_count_; }
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override {
     changed_.push_back(display);
@@ -139,9 +139,11 @@
  private:
   vector<display::Display> changed_;
   vector<display::Display> added_;
-  size_t removed_count_;
-  bool root_window_destroyed_;
-  uint32_t changed_metrics_;
+  size_t removed_count_ = 0u;
+  size_t will_process_count_ = 0u;
+  size_t did_process_count_ = 0u;
+  bool root_window_destroyed_ = false;
+  uint32_t changed_metrics_ = 0u;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayManagerTest);
 };
@@ -155,7 +157,7 @@
   EXPECT_EQ("0,0 500x500",
             display_manager()->GetDisplayAt(0).bounds().ToString());
 
-  EXPECT_EQ("2 1 0", GetCountSummary());
+  EXPECT_EQ("2 1 0 1 1", GetCountSummary());
   EXPECT_EQ(display_manager()->GetDisplayAt(1).id(), changed()[0].id());
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(), changed()[1].id());
   EXPECT_EQ(display_manager()->GetDisplayAt(1).id(), added()[0].id());
@@ -169,12 +171,12 @@
 
   // Delete secondary.
   UpdateDisplay("100+0-500x500");
-  EXPECT_EQ("0 0 1", GetCountSummary());
+  EXPECT_EQ("0 0 1 1 1", GetCountSummary());
   reset();
 
   // Change primary.
   UpdateDisplay("1+1-1000x600");
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(), changed()[0].id());
   EXPECT_EQ("0,0 1000x600", changed()[0].bounds().ToString());
   reset();
@@ -182,7 +184,7 @@
   // Add secondary.
   UpdateDisplay("1+1-1000x600,1002+0-600x400");
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("1 1 0", GetCountSummary());
+  EXPECT_EQ("1 1 0 1 1", GetCountSummary());
   EXPECT_EQ(display_manager()->GetDisplayAt(1).id(), changed()[0].id());
   EXPECT_EQ(display_manager()->GetDisplayAt(1).id(), added()[0].id());
   // Secondary display is on right.
@@ -194,7 +196,7 @@
   // Secondary removed, primary changed.
   UpdateDisplay("1+1-800x300");
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("1 0 1", GetCountSummary());
+  EXPECT_EQ("1 0 1 1 1", GetCountSummary());
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(), changed()[0].id());
   EXPECT_EQ("0,0 800x300", changed()[0].bounds().ToString());
   reset();
@@ -203,7 +205,9 @@
   const vector<display::ManagedDisplayInfo> empty;
   display_manager()->OnNativeDisplaysChanged(empty);
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("0 0 0", GetCountSummary());
+  // Going to 0 displays doesn't actually change the list and is effectively
+  // ignored.
+  EXPECT_EQ("0 0 0 0 0", GetCountSummary());
   EXPECT_FALSE(root_window_destroyed());
   // Display configuration stays the same
   EXPECT_EQ("0,0 800x300",
@@ -213,7 +217,7 @@
   // Connect to display again
   UpdateDisplay("100+100-500x400");
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
   EXPECT_FALSE(root_window_destroyed());
   EXPECT_EQ("0,0 500x400", changed()[0].bounds().ToString());
   EXPECT_EQ("100,100 500x400",
@@ -240,7 +244,7 @@
 
   // Changing primary will update secondary as well.
   UpdateDisplay("0+0-800x600,1000+1000-600x400");
-  EXPECT_EQ("2 0 0", GetCountSummary());
+  EXPECT_EQ("2 0 0 1 1", GetCountSummary());
   reset();
   EXPECT_EQ("0,0 800x600",
             display_manager()->GetDisplayAt(0).bounds().ToString());
@@ -263,17 +267,17 @@
   display_manager()->AddRemoveDisplay();
   // Update primary and add seconary.
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("1 1 0", GetCountSummary());
+  EXPECT_EQ("1 1 0 1 1", GetCountSummary());
   reset();
 
   display_manager()->AddRemoveDisplay();
   EXPECT_EQ(1U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("0 0 1", GetCountSummary());
+  EXPECT_EQ("0 0 1 1 1", GetCountSummary());
   reset();
 
   display_manager()->AddRemoveDisplay();
   EXPECT_EQ(2U, display_manager()->GetNumDisplays());
-  EXPECT_EQ("1 1 0", GetCountSummary());
+  EXPECT_EQ("1 1 0 1 1", GetCountSummary());
 }
 
 // Tests support for 3 displays.
@@ -292,7 +296,7 @@
   EXPECT_EQ("960,0 400x300",
             display_manager()->GetDisplayAt(2).bounds().ToString());
 
-  EXPECT_EQ("3 2 0", GetCountSummary());
+  EXPECT_EQ("3 2 0 1 1", GetCountSummary());
   EXPECT_EQ(display_manager()->GetDisplayAt(1).id(), changed()[0].id());
   EXPECT_EQ(display_manager()->GetDisplayAt(2).id(), changed()[1].id());
   EXPECT_EQ(display_manager()->GetDisplayAt(0).id(), changed()[2].id());
@@ -1199,11 +1203,11 @@
   EXPECT_EQ(1, host->compositor()->device_scale_factor());
   EXPECT_EQ("1000x600",
             Shell::GetPrimaryRootWindow()->bounds().size().ToString());
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
 
   UpdateDisplay("1000x600*2");
   EXPECT_EQ(2, host->compositor()->device_scale_factor());
-  EXPECT_EQ("2 0 0", GetCountSummary());
+  EXPECT_EQ("2 0 0 2 2", GetCountSummary());
   EXPECT_EQ("500x300",
             Shell::GetPrimaryRootWindow()->bounds().size().ToString());
 }
@@ -1596,7 +1600,7 @@
   EXPECT_EQ("400x300", GetDisplayInfoAt(1).size_in_pixel().ToString());
   reset();
   UpdateDisplay("100x200/b,300x400");
-  EXPECT_EQ("2 0 0", GetCountSummary());
+  EXPECT_EQ("2 0 0 1 1", GetCountSummary());
   reset();
 
   EXPECT_EQ("1,1 100x200", GetDisplayInfoAt(0).bounds_in_native().ToString());
@@ -1607,30 +1611,31 @@
 
   // Just Rotating display will change the bounds on both display.
   UpdateDisplay("100x200/l,300x400");
-  EXPECT_EQ("2 0 0", GetCountSummary());
+  EXPECT_EQ("2 0 0 1 1", GetCountSummary());
   reset();
 
-  // Updating to the same configuration should report no changes.
+  // Updating to the same configuration should report no changes. A will/did
+  // change is still sent.
   UpdateDisplay("100x200/l,300x400");
-  EXPECT_EQ("0 0 0", GetCountSummary());
+  EXPECT_EQ("0 0 0 1 1", GetCountSummary());
   reset();
 
   // Rotating 180 degrees should report one change.
   UpdateDisplay("100x200/r,300x400");
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
   reset();
 
   UpdateDisplay("200x200");
-  EXPECT_EQ("1 0 1", GetCountSummary());
+  EXPECT_EQ("1 0 1 1 1", GetCountSummary());
   reset();
 
   // Rotating 180 degrees should report one change.
   UpdateDisplay("200x200/u");
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
   reset();
 
   UpdateDisplay("200x200/l");
-  EXPECT_EQ("1 0 0", GetCountSummary());
+  EXPECT_EQ("1 0 0 1 1", GetCountSummary());
 
   // Having the internal display deactivated should restore user rotation. Newly
   // set rotations should be applied.
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index e5d787ef..2605bd4 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -606,14 +606,15 @@
     // unified and non unified, but I'm keeping them separated to minimize
     // the risk in M44. I'll consolidate this in M45.
     DCHECK(window_tree_hosts_.empty());
-    primary_display_id = display.id();
-    window_tree_hosts_[display.id()] = primary_tree_host_for_replace_;
-    GetRootWindowSettings(GetWindow(primary_tree_host_for_replace_))
-        ->display_id = display.id();
+    AshWindowTreeHost* ash_host = primary_tree_host_for_replace_;
     primary_tree_host_for_replace_ = nullptr;
+    primary_display_id = display.id();
+    window_tree_hosts_[display.id()] = ash_host;
+    GetRootWindowSettings(GetWindow(ash_host))->display_id = display.id();
+    for (auto& observer : observers_)
+      observer.OnWindowTreeHostReusedForDisplay(ash_host, display);
     const display::ManagedDisplayInfo& display_info =
         GetDisplayManager()->GetDisplayInfo(display.id());
-    AshWindowTreeHost* ash_host = window_tree_hosts_[display.id()];
     ash_host->AsWindowTreeHost()->SetBoundsInPixels(
         display_info.bounds_in_native());
     SetDisplayPropertiesOnHost(ash_host, display);
diff --git a/ash/display/window_tree_host_manager.h b/ash/display/window_tree_host_manager.h
index 545ae6e..50e930c9 100644
--- a/ash/display/window_tree_host_manager.h
+++ b/ash/display/window_tree_host_manager.h
@@ -68,6 +68,13 @@
     // Invoked in WindowTreeHostManager::Shutdown().
     virtual void OnWindowTreeHostManagerShutdown() {}
 
+    // Invoked when an existing AshWindowTreeHost is reused for a new display.
+    // This happens when all displays are removed, and then a new display is
+    // added.
+    virtual void OnWindowTreeHostReusedForDisplay(
+        AshWindowTreeHost* window_tree_host,
+        const display::Display& display) {}
+
    protected:
     virtual ~Observer() {}
   };
diff --git a/ash/laser/laser_segment_utils.cc b/ash/laser/laser_segment_utils.cc
index 189f51b..52d85d7 100644
--- a/ash/laser/laser_segment_utils.cc
+++ b/ash/laser/laser_segment_utils.cc
@@ -4,6 +4,7 @@
 
 #include "ash/laser/laser_segment_utils.h"
 
+#include <cmath>
 #include <limits>
 
 #include "base/logging.h"
@@ -67,8 +68,8 @@
                             gfx::PointF* second_projection) {
   // If the slope is NaN, the y-intercept should be NaN too. The line is thus
   // vertical and projections will be projected straight up/down from |point|.
-  if (isnan(line_slope)) {
-    DCHECK(isnan(line_y_intercept));
+  if (std::isnan(line_slope)) {
+    DCHECK(std::isnan(line_y_intercept));
 
     *first_projection =
         gfx::PointF(point.x(), point.y() + round(projection_distance));
diff --git a/ash/mus/DEPS b/ash/mus/DEPS
index b39c35c..7d88d9a0 100644
--- a/ash/mus/DEPS
+++ b/ash/mus/DEPS
@@ -20,6 +20,10 @@
     "+mash/quick_launch/public",
   ],
 
+  "display_synchronizer.cc": [
+    "+ash/host/ash_window_tree_host.h",
+  ],
+
   "non_client_frame_controller_unittest.cc": [
     # These tests inspect the DrawQuads in the CompositorFrame generated by the
     # compositor. So this needs to explicitly depend on cc.
diff --git a/ash/mus/display_synchronizer.cc b/ash/mus/display_synchronizer.cc
index ca00f7c..8aa12a5 100644
--- a/ash/mus/display_synchronizer.cc
+++ b/ash/mus/display_synchronizer.cc
@@ -4,8 +4,11 @@
 
 #include "ash/mus/display_synchronizer.h"
 
+#include "ash/host/ash_window_tree_host.h"
 #include "ash/shell.h"
+#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
 #include "ui/aura/mus/window_manager_delegate.h"
+#include "ui/aura/mus/window_tree_host_mus.h"
 #include "ui/display/manager/display_manager.h"
 #include "ui/display/manager/managed_display_info.h"
 
@@ -25,6 +28,9 @@
 }
 
 void DisplaySynchronizer::SendDisplayConfigurationToServer() {
+  if (processing_display_changes_)
+    return;
+
   display::DisplayManager* display_manager = Shell::Get()->display_manager();
   const size_t display_count = display_manager->GetNumDisplays();
   if (display_count == 0)
@@ -58,6 +64,38 @@
   SendDisplayConfigurationToServer();
 }
 
+void DisplaySynchronizer::OnWindowTreeHostReusedForDisplay(
+    AshWindowTreeHost* window_tree_host,
+    const display::Display& display) {
+  aura::WindowTreeHostMus* window_tree_host_mus =
+      static_cast<aura::WindowTreeHostMus*>(
+          window_tree_host->AsWindowTreeHost());
+  if (window_tree_host_mus->display_id() == display.id())
+    return;
+  const display::ManagedDisplayInfo& display_info =
+      Shell::Get()->display_manager()->GetDisplayInfo(display.id());
+  ui::mojom::WmViewportMetricsPtr viewport_metrics =
+      ui::mojom::WmViewportMetrics::New();
+  viewport_metrics->bounds_in_pixels = display_info.bounds_in_native();
+  viewport_metrics->device_scale_factor = display.device_scale_factor();
+  viewport_metrics->ui_scale_factor = display_info.configured_ui_scale();
+  window_manager_client_->AddDisplayReusingWindowTreeHost(
+      static_cast<aura::WindowTreeHostMus*>(
+          window_tree_host->AsWindowTreeHost()),
+      display, std::move(viewport_metrics));
+}
+
+void DisplaySynchronizer::OnWillProcessDisplayChanges() {
+  DCHECK(!processing_display_changes_);
+  processing_display_changes_ = true;
+}
+
+void DisplaySynchronizer::OnDidProcessDisplayChanges() {
+  DCHECK(processing_display_changes_);
+  processing_display_changes_ = false;
+  SendDisplayConfigurationToServer();
+}
+
 void DisplaySynchronizer::OnDisplayMetricsChanged(
     const display::Display& display,
     uint32_t changed_metrics) {
diff --git a/ash/mus/display_synchronizer.h b/ash/mus/display_synchronizer.h
index 3428cc5..b38a286 100644
--- a/ash/mus/display_synchronizer.h
+++ b/ash/mus/display_synchronizer.h
@@ -31,8 +31,13 @@
   // WindowTreeHostManager::Observer:
   void OnDisplaysInitialized() override;
   void OnDisplayConfigurationChanged() override;
+  void OnWindowTreeHostReusedForDisplay(
+      AshWindowTreeHost* window_tree_host,
+      const display::Display& display) override;
 
   // display::DisplayObserver:
+  void OnWillProcessDisplayChanges() override;
+  void OnDidProcessDisplayChanges() override;
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
@@ -40,6 +45,16 @@
 
   bool sent_initial_config_ = false;
 
+  // Set to true when OnWillProcessDisplayChanges() is called and false in
+  // OnDidProcessDisplayChanges(). DisplayManager calls out while the list of
+  // displays contains both newly added displays and displays that have been
+  // removed. This means if we attempt to access the list of displays during
+  // this time we may get the wrong state (SendDisplayConfigurationToServer()
+  // would send a bogus display to the window server). By only processing the
+  // change after DisplayManager has updated its internal state we ensure we
+  // don't send a bad config.
+  bool processing_display_changes_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(DisplaySynchronizer);
 };
 
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 9e5568b..961f0dd 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -82,6 +82,8 @@
     "palette_tray_icon_magnify.icon",
     "palette_tray_icon_metalayer.1x.icon",
     "palette_tray_icon_metalayer.icon",
+    "shelf_back.1x.icon",
+    "shelf_back.icon",
     "shelf_keyboard.1x.icon",
     "shelf_keyboard.icon",
     "shelf_logout.1x.icon",
diff --git a/ash/resources/vector_icons/shelf_back.1x.icon b/ash/resources/vector_icons/shelf_back.1x.icon
new file mode 100644
index 0000000..0eb4554
--- /dev/null
+++ b/ash/resources/vector_icons/shelf_back.1x.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 16,
+MOVE_TO, 0, 0,
+R_H_LINE_TO, 16,
+R_V_LINE_TO, 16,
+H_LINE_TO, 0,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 5.2f, 7,
+H_LINE_TO, 15,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5.2f,
+R_LINE_TO, 4.8f, 4.8f,
+LINE_TO, 8.9f, 15,
+LINE_TO, 2, 8,
+R_LINE_TO, 6.9f, -7,
+LINE_TO, 10, 2.2f,
+LINE_TO, 5.2f, 7,
+CLOSE,
+END
diff --git a/ash/resources/vector_icons/shelf_back.icon b/ash/resources/vector_icons/shelf_back.icon
new file mode 100644
index 0000000..c8ca33f
--- /dev/null
+++ b/ash/resources/vector_icons/shelf_back.icon
@@ -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.
+
+CANVAS_DIMENSIONS, 32,
+MOVE_TO, 0, 0,
+R_H_LINE_TO, 32,
+R_V_LINE_TO, 32,
+H_LINE_TO, 0,
+CLOSE,
+NEW_PATH,
+PATH_COLOR_ARGB, 0xFF, 0xFF, 0xFF, 0xFF,
+MOVE_TO, 8.56f, 17.99f,
+R_LINE_TO, 9.65f, 9.98f,
+LINE_TO, 16.18f, 30,
+LINE_TO, 3, 16.49f,
+LINE_TO, 16.18f, 3,
+R_LINE_TO, 2.03f, 2,
+R_LINE_TO, -9.86f, 9.99f,
+H_LINE_TO, 29,
+R_V_LINE_TO, 3,
+CLOSE,
+END
diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc
index 82948a84..fdc86e4 100644
--- a/ash/shelf/app_list_button.cc
+++ b/ash/shelf/app_list_button.cc
@@ -17,20 +17,24 @@
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/tray_popup_utils.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/timer/timer.h"
 #include "chromeos/chromeos_switches.h"
+#include "third_party/skia/include/core/SkPath.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/app_list/presenter/app_list.h"
+#include "ui/aura/window_tree_host.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer_animation_element.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/layer_animation_sequence.h"
 #include "ui/compositor/paint_context.h"
 #include "ui/compositor/paint_recorder.h"
+#include "ui/events/event_sink.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/canvas_image_source.h"
 #include "ui/gfx/image/image_skia.h"
@@ -44,7 +48,35 @@
 
 namespace ash {
 namespace {
+
 constexpr int kVoiceInteractionAnimationDelayMs = 200;
+
+// Generate and send a VKEY_BROWSER_BACK key event when the back button portion
+// is clicked or tapped.
+void GenerateAndSendBackEvent(const ui::LocatedEvent& original_event) {
+  ui::EventType event_type;
+  switch (original_event.type()) {
+    case ui::ET_MOUSE_PRESSED:
+    case ui::ET_GESTURE_TAP_DOWN:
+      event_type = ui::ET_KEY_PRESSED;
+      break;
+    case ui::ET_MOUSE_RELEASED:
+    case ui::ET_GESTURE_TAP:
+      event_type = ui::ET_KEY_RELEASED;
+      break;
+    default:
+      return;
+  }
+
+  ui::KeyEvent key_event(event_type, ui::VKEY_BROWSER_BACK, ui::EF_NONE);
+  aura::Window* target = static_cast<aura::Window*>(original_event.target());
+  aura::Window* target_root = target->GetRootWindow()
+                                  ? target->GetRootWindow()
+                                  : Shell::Get()->GetPrimaryRootWindow();
+  ignore_result(
+      target_root->GetHost()->event_sink()->OnEventFromSource(&key_event));
+}
+
 }  // namespace
 
 constexpr uint8_t kVoiceInteractionRunningAlpha = 255;     // 100% alpha
@@ -106,6 +138,28 @@
 }
 
 void AppListButton::OnGestureEvent(ui::GestureEvent* event) {
+  last_event_is_back_event_ = IsBackEvent(event->location());
+  // Handle gesture events that are on the back button.
+  if (last_event_is_back_event_) {
+    switch (event->type()) {
+      case ui::ET_GESTURE_TAP:
+        AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, event);
+        GenerateAndSendBackEvent(*event);
+        break;
+      case ui::ET_GESTURE_TAP_CANCEL:
+        AnimateInkDrop(views::InkDropState::HIDDEN, event);
+        break;
+      case ui::ET_GESTURE_TAP_DOWN:
+        AnimateInkDrop(views::InkDropState::ACTION_PENDING, event);
+        GenerateAndSendBackEvent(*event);
+        break;
+      default:
+        break;
+    }
+    return;
+  }
+
+  // Handle gesture events that are on the app list circle.
   switch (event->type()) {
     case ui::ET_GESTURE_SCROLL_BEGIN:
       AnimateInkDrop(views::InkDropState::HIDDEN, event);
@@ -172,14 +226,26 @@
 }
 
 bool AppListButton::OnMousePressed(const ui::MouseEvent& event) {
-  ImageButton::OnMousePressed(event);
-  shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event);
+  last_event_is_back_event_ = IsBackEvent(event.location());
+  if (last_event_is_back_event_) {
+    AnimateInkDrop(views::InkDropState::ACTION_PENDING, &event);
+    GenerateAndSendBackEvent(*event.AsLocatedEvent());
+  } else {
+    ImageButton::OnMousePressed(event);
+    shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event);
+  }
   return true;
 }
 
 void AppListButton::OnMouseReleased(const ui::MouseEvent& event) {
-  ImageButton::OnMouseReleased(event);
-  shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false);
+  last_event_is_back_event_ = IsBackEvent(event.location());
+  if (last_event_is_back_event_) {
+    AnimateInkDrop(views::InkDropState::ACTION_TRIGGERED, &event);
+    GenerateAndSendBackEvent(*event.AsLocatedEvent());
+  } else {
+    ImageButton::OnMouseReleased(event);
+    shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false);
+  }
 }
 
 void AppListButton::OnMouseCaptureLost() {
@@ -200,7 +266,8 @@
 
 std::unique_ptr<views::InkDropRipple> AppListButton::CreateInkDropRipple()
     const {
-  gfx::Point center = GetCenterPoint();
+  gfx::Point center = last_event_is_back_event_ ? GetBackButtonCenterPoint()
+                                                : GetAppListButtonCenterPoint();
   gfx::Rect bounds(center.x() - kAppListButtonRadius,
                    center.y() - kAppListButtonRadius, 2 * kAppListButtonRadius,
                    2 * kAppListButtonRadius);
@@ -232,22 +299,81 @@
 }
 
 std::unique_ptr<views::InkDropMask> AppListButton::CreateInkDropMask() const {
-  return base::MakeUnique<views::CircleInkDropMask>(size(), GetCenterPoint(),
-                                                    kAppListButtonRadius);
+  return base::MakeUnique<views::CircleInkDropMask>(
+      size(),
+      last_event_is_back_event_ ? GetBackButtonCenterPoint()
+                                : GetAppListButtonCenterPoint(),
+      kAppListButtonRadius);
 }
 
 void AppListButton::PaintButtonContents(gfx::Canvas* canvas) {
-  gfx::PointF circle_center(GetCenterPoint());
+  const bool is_maximize_mode = Shell::Get()
+                                    ->maximize_mode_controller()
+                                    ->IsMaximizeModeWindowManagerEnabled();
+  gfx::PointF circle_center(GetAppListButtonCenterPoint());
 
   // Paint the circular background.
   cc::PaintFlags bg_flags;
   bg_flags.setColor(background_color_);
   bg_flags.setAntiAlias(true);
   bg_flags.setStyle(cc::PaintFlags::kFill_Style);
-  canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags);
 
-  // Paint a white ring as the foreground. The ceil/dsf math assures that the
-  // ring draws sharply and is centered at all scale factors.
+  if (is_maximize_mode) {
+    // Draw the maximize mode app list background. It will look something like
+    // [1] when the shelf is horizontal and [2] when the shelf is vertical,
+    // where 1. is the back button and 2. is the app launcher circle.
+    //                                      _____
+    // [1]   _______________         [2]   /  1. \
+    //      /               \             |       |
+    //      | 1.         2. |             |   2.  |
+    //      \_______________/              \_____/
+
+    // Calculate the rectangular bounds of the path. The primary axis will be
+    // the distance between the back button and app circle centers and the
+    // secondary axis will be 2 * |kAppListButtonRadius|. The origin will be
+    // situated such that the back button center and app circle center are
+    // located equal distance from the sides parallel to the primary axis. See
+    // diagrams below; (1) is the back button and (2) is the app circle.
+    //
+    //    ___________         ____(1)____
+    //    |         |         |         |
+    //   (1)       (2)        |         |
+    //    |_________|         |         |
+    //                        |___(2)___|
+    gfx::PointF back_center(GetBackButtonCenterPoint());
+    gfx::RectF background_bounds(
+        shelf_->PrimaryAxisValue(back_center.x(),
+                                 back_center.x() - kAppListButtonRadius),
+        shelf_->PrimaryAxisValue(back_center.y() - kAppListButtonRadius,
+                                 back_center.y()),
+        shelf_->PrimaryAxisValue(circle_center.x() - back_center.x(),
+                                 2 * kAppListButtonRadius),
+        shelf_->PrimaryAxisValue(2 * kAppListButtonRadius,
+                                 circle_center.y() - back_center.y()));
+
+    // Create the path by drawing two circles, one around the back button and
+    // one around the app list circle. Join them with the rectangle calculated
+    // previously.
+    SkPath path;
+    path.addCircle(circle_center.x(), circle_center.y(), kAppListButtonRadius);
+    path.addCircle(back_center.x(), back_center.y(), kAppListButtonRadius);
+    path.addRect(background_bounds.x(), background_bounds.y(),
+                 background_bounds.right(), background_bounds.bottom());
+    canvas->DrawPath(path, bg_flags);
+
+    // Draw the back button icon.
+    // TODO(sammiequon): Check if the back button should be flipped in RTL.
+    gfx::ImageSkia back_button =
+        CreateVectorIcon(kShelfBackIcon, SK_ColorTRANSPARENT);
+    canvas->DrawImageInt(back_button, back_center.x() - back_button.width() / 2,
+                         back_center.y() - back_button.height() / 2);
+  } else {
+    canvas->DrawCircle(circle_center, kAppListButtonRadius, bg_flags);
+  }
+
+  // Paint a white ring as the foreground for the app list circle. The ceil/dsf
+  // math assures that the ring draws sharply and is centered at all scale
+  // factors.
   float ring_outer_radius_dp = 7.f;
   float ring_thickness_dp = 1.5f;
   if (chromeos::switches::IsVoiceInteractionEnabled()) {
@@ -286,26 +412,55 @@
   }
 }
 
-gfx::Point AppListButton::GetCenterPoint() const {
+gfx::Point AppListButton::GetAppListButtonCenterPoint() const {
   // For a bottom-aligned shelf, the button bounds could have a larger height
-  // than width (in the case of touch-dragging the shelf updwards) or a larger
+  // than width (in the case of touch-dragging the shelf upwards) or a larger
   // width than height (in the case of a shelf hide/show animation), so adjust
   // the y-position of the circle's center to ensure correct layout. Similarly
-  // adjust the x-position for a left- or right-aligned shelf.
+  // adjust the x-position for a left- or right-aligned shelf. In maximized
+  // mode, the button will increase it's primary axis size to accomodate the
+  // back button arrow in addition to the app list button circle.
   const int x_mid = width() / 2.f;
   const int y_mid = height() / 2.f;
+  const bool is_maximize_mode = Shell::Get()
+                                    ->maximize_mode_controller()
+                                    ->IsMaximizeModeWindowManagerEnabled();
+
   ShelfAlignment alignment = shelf_->alignment();
   if (alignment == SHELF_ALIGNMENT_BOTTOM ||
       alignment == SHELF_ALIGNMENT_BOTTOM_LOCKED) {
+    if (is_maximize_mode) {
+      return gfx::Point(width() - kShelfButtonSize / 2.f,
+                        kShelfButtonSize / 2.f);
+    }
     return gfx::Point(x_mid, x_mid);
   } else if (alignment == SHELF_ALIGNMENT_RIGHT) {
+    if (is_maximize_mode) {
+      return gfx::Point(kShelfButtonSize / 2.f,
+                        height() - kShelfButtonSize / 2.f);
+    }
     return gfx::Point(y_mid, y_mid);
   } else {
     DCHECK_EQ(alignment, SHELF_ALIGNMENT_LEFT);
+    if (is_maximize_mode) {
+      return gfx::Point(width() - kShelfButtonSize / 2.f,
+                        height() - kShelfButtonSize / 2.f);
+    }
     return gfx::Point(width() - y_mid, y_mid);
   }
 }
 
+gfx::Point AppListButton::GetBackButtonCenterPoint() const {
+  DCHECK(Shell::Get()
+             ->maximize_mode_controller()
+             ->IsMaximizeModeWindowManagerEnabled());
+
+  if (shelf_->alignment() == SHELF_ALIGNMENT_LEFT)
+    return gfx::Point(width() - kShelfButtonSize / 2.f, kShelfButtonSize / 2.f);
+
+  return gfx::Point(kShelfButtonSize / 2.f, kShelfButtonSize / 2.f);
+}
+
 void AppListButton::OnAppListVisibilityChanged(bool shown,
                                                aura::Window* root_window) {
   if (shelf_ != Shelf::ForWindow(root_window))
@@ -322,4 +477,15 @@
   SchedulePaint();
 }
 
+bool AppListButton::IsBackEvent(const gfx::Point& location) {
+  if (!Shell::Get()
+           ->maximize_mode_controller()
+           ->IsMaximizeModeWindowManagerEnabled()) {
+    return false;
+  }
+
+  return (location - GetBackButtonCenterPoint()).LengthSquared() <
+         (location - GetAppListButtonCenterPoint()).LengthSquared();
+}
+
 }  // namespace ash
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h
index 6ad53960..67a644b 100644
--- a/ash/shelf/app_list_button.h
+++ b/ash/shelf/app_list_button.h
@@ -40,15 +40,18 @@
   // Updates background and schedules a paint.
   void UpdateShelfItemBackground(SkColor color);
 
-  // views::ImageButton overrides:
+  // views::ImageButton:
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  // Get the center point of the app list button used to draw its background and
-  // ink drops.
-  gfx::Point GetCenterPoint() const;
+  // Get the center point of the app list button circle used to draw its
+  // background and ink drops.
+  gfx::Point GetAppListButtonCenterPoint() const;
+  // Get the center point of the app list button back arrow. Returns an empty
+  // gfx::Point if the back arrow is not shown.
+  gfx::Point GetBackButtonCenterPoint() const;
 
  protected:
-  // views::ImageButton overrides:
+  // views::ImageButton:
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnMouseReleased(const ui::MouseEvent& event) override;
   void OnMouseCaptureLost() override;
@@ -62,11 +65,16 @@
   void PaintButtonContents(gfx::Canvas* canvas) override;
 
  private:
-  // ShellObserver overrides:
+  // ShellObserver:
   void OnAppListVisibilityChanged(bool shown,
                                   aura::Window* root_window) override;
   void OnVoiceInteractionStatusChanged(bool running) override;
 
+  // Helper function to determine whether and event at |location| should be
+  // handled by the back button or the app list circle. Returns false if we are
+  // not in maximized mode (there is no back button).
+  bool IsBackEvent(const gfx::Point& location);
+
   // True if the app list is currently showing for this display.
   // This is useful because other IsApplistVisible functions aren't per-display.
   bool is_showing_app_list_;
@@ -83,6 +91,10 @@
 
   bool voice_interaction_running_ = false;
 
+  // Flag that gets set each time we receive a mouse or gesture event. It is
+  // then used to render the ink drop in the right location.
+  bool last_event_is_back_event_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(AppListButton);
 };
 
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index acbef66d..e9d4938b 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -28,6 +28,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/shell_port.h"
 #include "ash/strings/grit/ash_strings.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/root_window_finder.h"
 #include "base/auto_reset.h"
 #include "base/memory/ptr_util.h"
@@ -755,15 +756,31 @@
 
   int w = shelf_->PrimaryAxisValue(kShelfButtonSize, width());
   int h = shelf_->PrimaryAxisValue(height(), kShelfButtonSize);
+
+  const bool is_maximize_mode = Shell::Get()->maximize_mode_controller()
+                                    ? Shell::Get()
+                                          ->maximize_mode_controller()
+                                          ->IsMaximizeModeWindowManagerEnabled()
+                                    : false;
+
   for (int i = 0; i < view_model_->view_size(); ++i) {
     if (i < first_visible_index_) {
       view_model_->set_ideal_bounds(i, gfx::Rect(x, y, 0, 0));
       continue;
     }
 
-    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, w, h));
-    x = shelf_->PrimaryAxisValue(x + w + kShelfButtonSpacing, x);
-    y = shelf_->PrimaryAxisValue(y, y + h + kShelfButtonSpacing);
+    int width = w;
+    int height = h;
+    // If this is the app list button and we are in maximize/tablet mode, make
+    // space for the back button (which is part of the app list button).
+    if (i == 0 && is_maximize_mode) {
+      width = shelf_->PrimaryAxisValue(2 * w + kShelfButtonSpacing, w);
+      height = shelf_->PrimaryAxisValue(h, 2 * h + kShelfButtonSpacing);
+    }
+
+    view_model_->set_ideal_bounds(i, gfx::Rect(x, y, width, height));
+    x = shelf_->PrimaryAxisValue(x + width + kShelfButtonSpacing, x);
+    y = shelf_->PrimaryAxisValue(y, y + height + kShelfButtonSpacing);
   }
 
   if (is_overflow_mode()) {
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index c18c2140..e18ab969 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -35,6 +35,7 @@
 #include "ash/test/test_shell_delegate.h"
 #include "ash/test/wallpaper_controller_test_api.h"
 #include "ash/wallpaper/wallpaper_controller.h"
+#include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "base/i18n/rtl.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -2568,6 +2569,129 @@
 
 namespace {
 
+// Test fixture to run app list button ink drop tests for both mouse and touch
+// events.
+class AppListButtonInkDropTest
+    : public ShelfViewInkDropTest,
+      public testing::WithParamInterface<ui::EventPointerType> {
+ public:
+  AppListButtonInkDropTest() : pointer_type_(GetParam()) {}
+
+  ~AppListButtonInkDropTest() override {}
+
+  void MovePointerTo(const gfx::Point& point) {
+    if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE)
+      GetEventGenerator().MoveMouseTo(point);
+    else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH)
+      GetEventGenerator().MoveTouch(point);
+  }
+
+  void PressPointer() {
+    if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE)
+      GetEventGenerator().PressLeftButton();
+    else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH)
+      GetEventGenerator().PressTouch();
+  }
+
+  void ReleasePointer() {
+    if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_MOUSE)
+      GetEventGenerator().ReleaseLeftButton();
+    else if (pointer_type_ == ui::EventPointerType::POINTER_TYPE_TOUCH)
+      GetEventGenerator().ReleaseTouch();
+  }
+
+ private:
+  ui::EventPointerType pointer_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(AppListButtonInkDropTest);
+};
+
+const ui::EventPointerType kPointerTypes[] = {
+    ui::EventPointerType::POINTER_TYPE_MOUSE,
+    ui::EventPointerType::POINTER_TYPE_TOUCH};
+
+}  // namespace
+
+// Tests that clicking/tapping on the app list button in maximized mode (when
+// it has two functionalities), transitions the ink drop state correctly.
+TEST_P(AppListButtonInkDropTest, AppListButtonInMaximizedMode) {
+  // TODO: investigate failure in mash, http://crbug.com/695751.
+  if (Shell::GetAshConfig() == Config::MASH)
+    return;
+
+  InitAppListButtonInkDrop();
+
+  // Verify the app list button bounds change when we enter maximized mode.
+  const gfx::Rect old_bounds = app_list_button_->GetBoundsInScreen();
+  Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
+      true);
+  gfx::Rect new_bounds = app_list_button_->GetBoundsInScreen();
+  EXPECT_EQ(new_bounds.height(), old_bounds.height());
+  EXPECT_GT(new_bounds.width(), old_bounds.width());
+
+  gfx::Point point_on_circle = app_list_button_->GetAppListButtonCenterPoint();
+  views::View::ConvertPointToScreen(app_list_button_, &point_on_circle);
+  gfx::Point point_on_back_button =
+      app_list_button_->GetBackButtonCenterPoint();
+  views::View::ConvertPointToScreen(app_list_button_, &point_on_back_button);
+
+  // Verify the ink drop state transitions as expected when we press and
+  // release on the app list circle part of the app list button. Taps on the
+  // app list circle, which shows the app list, should end up in the activated
+  // state.
+  MovePointerTo(point_on_circle);
+  PressPointer();
+  EXPECT_EQ(views::InkDropState::ACTION_PENDING,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTION_PENDING));
+  ReleasePointer();
+
+  // Trigger a mock button notification that the app list was shown.
+  app_list_button_->OnAppListShown();
+  FinishAppListVisibilityChange();
+  EXPECT_EQ(views::InkDropState::ACTIVATED,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTIVATED));
+
+  // Trigger a mock button notification that the app list was dismissed.
+  app_list_button_->OnAppListDismissed();
+  FinishAppListVisibilityChange();
+  EXPECT_EQ(views::InkDropState::HIDDEN,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::DEACTIVATED));
+
+  // Verify the ink drop state transitions as expected when we tap on the back
+  // button part of the app list button.
+  MovePointerTo(point_on_back_button);
+  PressPointer();
+  EXPECT_EQ(views::InkDropState::ACTION_PENDING,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTION_PENDING));
+  ReleasePointer();
+  EXPECT_EQ(views::InkDropState::HIDDEN,
+            app_list_button_ink_drop_->GetTargetInkDropState());
+  EXPECT_THAT(app_list_button_ink_drop_->GetAndResetRequestedStates(),
+              ElementsAre(views::InkDropState::ACTION_TRIGGERED));
+
+  // Verify when we leave maximized mode, the bounds should return to be the
+  // same as they were before we entered maximized mode.
+  Shell::Get()->maximize_mode_controller()->EnableMaximizeModeWindowManager(
+      false);
+  new_bounds = app_list_button_->GetBoundsInScreen();
+  EXPECT_EQ(new_bounds, old_bounds);
+}
+
+INSTANTIATE_TEST_CASE_P(
+    /* prefix intentionally left blank due to only one parameterization */,
+    AppListButtonInkDropTest,
+    ::testing::ValuesIn(kPointerTypes));
+
+namespace {
+
 // An empty menu model for shell context menu just to have a menu.
 class TestShellMenuModel : public ui::SimpleMenuModel,
                            public ui::SimpleMenuModel::Delegate {
diff --git a/ash/shelf/voice_interaction_overlay.cc b/ash/shelf/voice_interaction_overlay.cc
index e50c738..a9b87711 100644
--- a/ash/shelf/voice_interaction_overlay.cc
+++ b/ash/shelf/voice_interaction_overlay.cc
@@ -193,7 +193,7 @@
       kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip;
   gfx::Transform transform;
 
-  const gfx::Point center = host_view_->GetCenterPoint();
+  const gfx::Point center = host_view_->GetAppListButtonCenterPoint();
   transform.Translate(center.x() - kRippleCircleStartRadiusDip,
                       center.y() - kRippleCircleStartRadiusDip);
   transform.Scale(scale_factor, scale_factor);
@@ -311,7 +311,7 @@
 void VoiceInteractionOverlay::BurstAnimation() {
   is_bursting_ = true;
 
-  gfx::Point center = host_view_->GetCenterPoint();
+  gfx::Point center = host_view_->GetAppListButtonCenterPoint();
 
   // Setup ripple animations.
   {
@@ -364,7 +364,7 @@
       kRippleCircleStartRadiusDip / kRippleCircleInitRadiusDip;
   gfx::Transform transform;
 
-  const gfx::Point center = host_view_->GetCenterPoint();
+  const gfx::Point center = host_view_->GetAppListButtonCenterPoint();
   transform.Translate(center.x() - kRippleCircleStartRadiusDip,
                       center.y() - kRippleCircleStartRadiusDip);
   transform.Scale(scale_factor, scale_factor);
diff --git a/base/numerics/clamped_math.h b/base/numerics/clamped_math.h
index 799043a..620bfd8 100644
--- a/base/numerics/clamped_math.h
+++ b/base/numerics/clamped_math.h
@@ -176,6 +176,11 @@
         value_);
   }
 
+  // This method extracts the raw integer value without saturating it to the
+  // destination type as the conversion operator does. This is useful when
+  // e.g. assigning to an auto type or passing as a deduced template parameter.
+  constexpr T RawValue() const { return value_; }
+
  private:
   T value_;
 
diff --git a/base/numerics/saturated_arithmetic.h b/base/numerics/saturated_arithmetic.h
index 74fbba80..504fcd8f 100644
--- a/base/numerics/saturated_arithmetic.h
+++ b/base/numerics/saturated_arithmetic.h
@@ -22,46 +22,6 @@
 
 namespace base {
 
-ALWAYS_INLINE int32_t SaturatedAddition(int32_t a, int32_t b) {
-  uint32_t ua = a;
-  uint32_t ub = b;
-  uint32_t result = ua + ub;
-
-  // Can only overflow if the signed bit of the two values match. If the
-  // signed bit of the result and one of the values differ it overflowed.
-  // The branch compiles to a CMOVNS instruction on x86.
-  if (~(ua ^ ub) & (result ^ ua) & (1 << 31))
-    return std::numeric_limits<int>::max() + (ua >> 31);
-
-  return result;
-}
-
-ALWAYS_INLINE int32_t SaturatedSubtraction(int32_t a, int32_t b) {
-  uint32_t ua = a;
-  uint32_t ub = b;
-  uint32_t result = ua - ub;
-
-  // Can only overflow if the signed bit of the two input values differ. If
-  // the signed bit of the result and the first value differ it overflowed.
-  // The branch compiles to a CMOVNS instruction on x86.
-  if ((ua ^ ub) & (result ^ ua) & (1 << 31))
-    return std::numeric_limits<int>::max() + (ua >> 31);
-
-  return result;
-}
-
-ALWAYS_INLINE int32_t SaturatedNegative(int32_t a) {
-  if (UNLIKELY(a == std::numeric_limits<int>::min()))
-    return std::numeric_limits<int>::max();
-  return -a;
-}
-
-ALWAYS_INLINE int32_t SaturatedAbsolute(int32_t a) {
-  if (a >= 0)
-    return a;
-  return SaturatedNegative(a);
-}
-
 ALWAYS_INLINE int GetMaxSaturatedSetResultForTesting(int fractional_shift) {
   // For C version the set function maxes out to max int, this differs from
   // the ARM asm version, see saturated_arithmetic_arm.h for the equivalent asm
diff --git a/base/numerics/saturated_arithmetic_arm.h b/base/numerics/saturated_arithmetic_arm.h
index 732f5f2..21701aa 100644
--- a/base/numerics/saturated_arithmetic_arm.h
+++ b/base/numerics/saturated_arithmetic_arm.h
@@ -9,36 +9,6 @@
 
 namespace base {
 
-inline int32_t SaturatedAddition(int32_t a, int32_t b) {
-  int32_t result;
-
-  asm("qadd %[output],%[first],%[second]"
-      : [output] "=r"(result)
-      : [first] "r"(a), [second] "r"(b));
-
-  return result;
-}
-
-inline int32_t SaturatedSubtraction(int32_t a, int32_t b) {
-  int32_t result;
-
-  asm("qsub %[output],%[first],%[second]"
-      : [output] "=r"(result)
-      : [first] "r"(a), [second] "r"(b));
-
-  return result;
-}
-
-inline int32_t SaturatedNegative(int32_t a) {
-  return SaturatedSubtraction(0, a);
-}
-
-inline int32_t SaturatedAbsolute(int32_t a) {
-  if (a >= 0)
-    return a;
-  return SaturatedNegative(a);
-}
-
 inline int GetMaxSaturatedSetResultForTesting(int fractional_shift) {
   // For ARM Asm version the set function maxes out to the biggest
   // possible integer part with the fractional part zero'd out.
diff --git a/base/numerics/saturated_arithmetic_unittest.cc b/base/numerics/saturated_arithmetic_unittest.cc
index 498f5b7..aa323c2 100644
--- a/base/numerics/saturated_arithmetic_unittest.cc
+++ b/base/numerics/saturated_arithmetic_unittest.cc
@@ -12,78 +12,6 @@
 
 namespace base {
 
-TEST(SaturatedArithmeticTest, Addition) {
-  int int_max = std::numeric_limits<int>::max();
-  int int_min = std::numeric_limits<int>::min();
-
-  EXPECT_EQ(0, SaturatedAddition(0, 0));
-  EXPECT_EQ(1, SaturatedAddition(0, 1));
-  EXPECT_EQ(100, SaturatedAddition(0, 100));
-  EXPECT_EQ(150, SaturatedAddition(100, 50));
-
-  EXPECT_EQ(-1, SaturatedAddition(0, -1));
-  EXPECT_EQ(0, SaturatedAddition(1, -1));
-  EXPECT_EQ(50, SaturatedAddition(100, -50));
-  EXPECT_EQ(-50, SaturatedAddition(50, -100));
-
-  EXPECT_EQ(int_max - 1, SaturatedAddition(int_max - 1, 0));
-  EXPECT_EQ(int_max, SaturatedAddition(int_max - 1, 1));
-  EXPECT_EQ(int_max, SaturatedAddition(int_max - 1, 2));
-  EXPECT_EQ(int_max - 1, SaturatedAddition(0, int_max - 1));
-  EXPECT_EQ(int_max, SaturatedAddition(1, int_max - 1));
-  EXPECT_EQ(int_max, SaturatedAddition(2, int_max - 1));
-  EXPECT_EQ(int_max, SaturatedAddition(int_max - 1, int_max - 1));
-  EXPECT_EQ(int_max, SaturatedAddition(int_max, int_max));
-
-  EXPECT_EQ(int_min, SaturatedAddition(int_min, 0));
-  EXPECT_EQ(int_min + 1, SaturatedAddition(int_min + 1, 0));
-  EXPECT_EQ(int_min + 2, SaturatedAddition(int_min + 1, 1));
-  EXPECT_EQ(int_min + 3, SaturatedAddition(int_min + 1, 2));
-  EXPECT_EQ(int_min, SaturatedAddition(int_min + 1, -1));
-  EXPECT_EQ(int_min, SaturatedAddition(int_min + 1, -2));
-  EXPECT_EQ(int_min + 1, SaturatedAddition(0, int_min + 1));
-  EXPECT_EQ(int_min, SaturatedAddition(-1, int_min + 1));
-  EXPECT_EQ(int_min, SaturatedAddition(-2, int_min + 1));
-
-  EXPECT_EQ(int_max / 2 + 10000, SaturatedAddition(int_max / 2, 10000));
-  EXPECT_EQ(int_max, SaturatedAddition(int_max / 2 + 1, int_max / 2 + 1));
-  EXPECT_EQ(-1, SaturatedAddition(int_min, int_max));
-}
-
-TEST(SaturatedArithmeticTest, Subtraction) {
-  int int_max = std::numeric_limits<int>::max();
-  int int_min = std::numeric_limits<int>::min();
-
-  EXPECT_EQ(0, SaturatedSubtraction(0, 0));
-  EXPECT_EQ(-1, SaturatedSubtraction(0, 1));
-  EXPECT_EQ(-100, SaturatedSubtraction(0, 100));
-  EXPECT_EQ(50, SaturatedSubtraction(100, 50));
-
-  EXPECT_EQ(1, SaturatedSubtraction(0, -1));
-  EXPECT_EQ(2, SaturatedSubtraction(1, -1));
-  EXPECT_EQ(150, SaturatedSubtraction(100, -50));
-  EXPECT_EQ(150, SaturatedSubtraction(50, -100));
-
-  EXPECT_EQ(int_max, SaturatedSubtraction(int_max, 0));
-  EXPECT_EQ(int_max - 1, SaturatedSubtraction(int_max, 1));
-  EXPECT_EQ(int_max - 1, SaturatedSubtraction(int_max - 1, 0));
-  EXPECT_EQ(int_max, SaturatedSubtraction(int_max - 1, -1));
-  EXPECT_EQ(int_max, SaturatedSubtraction(int_max - 1, -2));
-  EXPECT_EQ(-int_max + 1, SaturatedSubtraction(0, int_max - 1));
-  EXPECT_EQ(-int_max, SaturatedSubtraction(-1, int_max - 1));
-  EXPECT_EQ(-int_max - 1, SaturatedSubtraction(-2, int_max - 1));
-  EXPECT_EQ(-int_max - 1, SaturatedSubtraction(-3, int_max - 1));
-
-  EXPECT_EQ(int_min, SaturatedSubtraction(int_min, 0));
-  EXPECT_EQ(int_min + 1, SaturatedSubtraction(int_min + 1, 0));
-  EXPECT_EQ(int_min, SaturatedSubtraction(int_min + 1, 1));
-  EXPECT_EQ(int_min, SaturatedSubtraction(int_min + 1, 2));
-
-  EXPECT_EQ(0, SaturatedSubtraction(int_min, int_min));
-  EXPECT_EQ(0, SaturatedSubtraction(int_max, int_max));
-  EXPECT_EQ(int_max, SaturatedSubtraction(int_max, int_min));
-}
-
 TEST(SaturatedArithmeticTest, SetSigned) {
   int int_max = std::numeric_limits<int>::max();
   int int_min = std::numeric_limits<int>::min();
diff --git a/base/trace_event/heap_profiler_event_writer.cc b/base/trace_event/heap_profiler_event_writer.cc
index 23fe761f..c09a1e2 100644
--- a/base/trace_event/heap_profiler_event_writer.cc
+++ b/base/trace_event/heap_profiler_event_writer.cc
@@ -17,6 +17,7 @@
 #include "base/trace_event/heap_profiler_string_deduplicator.h"
 #include "base/trace_event/heap_profiler_type_name_deduplicator.h"
 #include "base/trace_event/sharded_allocation_register.h"
+#include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 
 namespace base {
@@ -44,6 +45,7 @@
 std::unique_ptr<TracedValue> SerializeHeapDump(
     const ShardedAllocationRegister& allocation_register,
     HeapProfilerSerializationState* serialization_state) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"), "SerializeHeapDump");
   // Aggregate allocations by {backtrace_id, type_id} key.
   using MetricsMap = std::unordered_map<AggregationKey, AllocationMetrics,
                                         AggregationKey::Hasher>;
@@ -67,9 +69,13 @@
         metrics.size += allocation.size;
         metrics.count += 1;
       };
-  allocation_register.VisitAllocations(base::BindRepeating(
-      visit_allocation, base::Unretained(serialization_state),
-      base::Unretained(&metrics_by_key)));
+  {
+    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+                 "SerializeHeapDump.VisitAllocations");
+    allocation_register.VisitAllocations(base::BindRepeating(
+        visit_allocation, base::Unretained(serialization_state),
+        base::Unretained(&metrics_by_key)));
+  }
 
   auto traced_value = MakeUnique<TracedValue>();
 
@@ -101,6 +107,8 @@
 std::unique_ptr<TracedValue> SerializeHeapProfileEventData(
     const SerializedHeapDumpsMap& heap_dumps,
     HeapProfilerSerializationState* serialization_state) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+               "SerializeHeapProfileEventData");
   auto traced_value = MakeUnique<TracedValue>();
 
   // See brief description of the format in the header file.
diff --git a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
index 5e314984..a7dac9c5 100644
--- a/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
+++ b/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/heap_profiler_string_deduplicator.h"
 #include "base/trace_event/memory_usage_estimator.h"
+#include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "base/trace_event/trace_event_memory_overhead.h"
 
@@ -80,6 +81,8 @@
 }
 
 void StackFrameDeduplicator::SerializeIncrementally(TracedValue* traced_value) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+               "StackFrameDeduplicator::SerializeIncrementally");
   std::string stringify_buffer;
 
   for (; last_exported_index_ < frames_.size(); ++last_exported_index_) {
diff --git a/base/trace_event/heap_profiler_string_deduplicator.cc b/base/trace_event/heap_profiler_string_deduplicator.cc
index bf035a1..5938e30 100644
--- a/base/trace_event/heap_profiler_string_deduplicator.cc
+++ b/base/trace_event/heap_profiler_string_deduplicator.cc
@@ -38,6 +38,8 @@
 }
 
 void StringDeduplicator::SerializeIncrementally(TracedValue* traced_value) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+               "StringDeduplicator::SerializeIncrementally");
   for (; last_serialized_index_ != strings_.size(); ++last_serialized_index_) {
     traced_value->BeginDictionary();
     traced_value->SetInteger("id", last_serialized_index_);
diff --git a/base/trace_event/heap_profiler_type_name_deduplicator.cc b/base/trace_event/heap_profiler_type_name_deduplicator.cc
index 0f01165..8224b5a9 100644
--- a/base/trace_event/heap_profiler_type_name_deduplicator.cc
+++ b/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -87,6 +87,8 @@
 }
 
 void TypeNameDeduplicator::SerializeIncrementally(TracedValue* traced_value) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory-infra"),
+               "TypeNameDeduplicator::SerializeIncrementally");
   for (const auto* name_and_id : new_type_ids_) {
     traced_value->BeginDictionary();
 
diff --git a/cc/base/rtree.h b/cc/base/rtree.h
index a29a7b8..4a48643 100644
--- a/cc/base/rtree.h
+++ b/cc/base/rtree.h
@@ -13,7 +13,7 @@
 #include <vector>
 
 #include "base/logging.h"
-#include "base/numerics/saturated_arithmetic.h"
+#include "base/numerics/clamped_math.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace cc {
@@ -258,8 +258,8 @@
         ++node->num_children;
         ++current_branch;
       }
-      branch.bounds.SetRect(x, y, base::SaturatedSubtraction(right, x),
-                            base::SaturatedSubtraction(bottom, y));
+      branch.bounds.SetRect(x, y, base::ClampSub(right, x),
+                            base::ClampSub(bottom, y));
 
       DCHECK_LT(new_branch_index, current_branch);
       (*branches)[new_branch_index] = std::move(branch);
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index ba065ea..c91c95a 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -144,6 +144,7 @@
   IPC_STRUCT_TRAITS_MEMBER(mailbox_holder)
   IPC_STRUCT_TRAITS_MEMBER(read_lock_fences_enabled)
   IPC_STRUCT_TRAITS_MEMBER(is_software)
+  IPC_STRUCT_TRAITS_MEMBER(shared_bitmap_sequence_number)
   IPC_STRUCT_TRAITS_MEMBER(is_overlay_candidate)
   IPC_STRUCT_TRAITS_MEMBER(color_space)
 #if defined(OS_ANDROID)
diff --git a/cc/ipc/shared_bitmap_allocation_notifier.mojom b/cc/ipc/shared_bitmap_allocation_notifier.mojom
index 1648625..a10eff2 100644
--- a/cc/ipc/shared_bitmap_allocation_notifier.mojom
+++ b/cc/ipc/shared_bitmap_allocation_notifier.mojom
@@ -8,10 +8,6 @@
 
 // This interface is used when allocating shared bitmaps to be shared with a
 // display compositor.
-// This interface needs to be associated with the channel used to submit
-// CompositorFrames, to prevent running into message ordering issues (the
-// display compositor trying to access shared memory before the registration
-// message below made it to the display compositor).
 interface SharedBitmapAllocationNotifier {
   // Informs the display compositor that the child allocated a shared bitmap.
   DidAllocateSharedBitmap(handle<shared_buffer> buffer, gpu.mojom.Mailbox id);
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 5bffa458..59fc43b 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -1135,6 +1135,7 @@
   const uint32_t texture_target = 1337;
   const bool read_lock_fences_enabled = true;
   const bool is_software = false;
+  const uint32_t shared_bitmap_sequence_number = 123456;
   const bool is_overlay_candidate = true;
 
   gpu::MailboxHolder mailbox_holder;
@@ -1151,6 +1152,7 @@
   input.mailbox_holder = mailbox_holder;
   input.read_lock_fences_enabled = read_lock_fences_enabled;
   input.is_software = is_software;
+  input.shared_bitmap_sequence_number = shared_bitmap_sequence_number;
   input.is_overlay_candidate = is_overlay_candidate;
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
   TransferableResource output;
@@ -1165,6 +1167,8 @@
             output.mailbox_holder.texture_target);
   EXPECT_EQ(read_lock_fences_enabled, output.read_lock_fences_enabled);
   EXPECT_EQ(is_software, output.is_software);
+  EXPECT_EQ(shared_bitmap_sequence_number,
+            output.shared_bitmap_sequence_number);
   EXPECT_EQ(is_overlay_candidate, output.is_overlay_candidate);
 }
 
diff --git a/cc/ipc/transferable_resource.mojom b/cc/ipc/transferable_resource.mojom
index ea20a63..81696f6 100644
--- a/cc/ipc/transferable_resource.mojom
+++ b/cc/ipc/transferable_resource.mojom
@@ -23,12 +23,13 @@
 struct TransferableResource {
   uint32 id;
   ResourceFormat format;
-  gfx.mojom.BufferFormat buffer_format;  
+  gfx.mojom.BufferFormat buffer_format;
   uint32 filter;
   gfx.mojom.Size size;
   gpu.mojom.MailboxHolder mailbox_holder;
   bool read_lock_fences_enabled;
   bool is_software;
+  uint32 shared_bitmap_sequence_number;
   bool is_overlay_candidate;
   bool is_backed_by_surface_texture;
   bool wants_promotion_hint;
diff --git a/cc/ipc/transferable_resource_struct_traits.cc b/cc/ipc/transferable_resource_struct_traits.cc
index 60aedc8..d53c823 100644
--- a/cc/ipc/transferable_resource_struct_traits.cc
+++ b/cc/ipc/transferable_resource_struct_traits.cc
@@ -25,6 +25,7 @@
   out->filter = data.filter();
   out->read_lock_fences_enabled = data.read_lock_fences_enabled();
   out->is_software = data.is_software();
+  out->shared_bitmap_sequence_number = data.shared_bitmap_sequence_number();
   out->is_overlay_candidate = data.is_overlay_candidate();
 #if defined(OS_ANDROID)
   out->is_backed_by_surface_texture = data.is_backed_by_surface_texture();
diff --git a/cc/ipc/transferable_resource_struct_traits.h b/cc/ipc/transferable_resource_struct_traits.h
index e9964c6..526a7e1 100644
--- a/cc/ipc/transferable_resource_struct_traits.h
+++ b/cc/ipc/transferable_resource_struct_traits.h
@@ -50,6 +50,11 @@
     return resource.is_software;
   }
 
+  static uint32_t shared_bitmap_sequence_number(
+      const cc::TransferableResource& resource) {
+    return resource.shared_bitmap_sequence_number;
+  }
+
   static bool is_overlay_candidate(const cc::TransferableResource& resource) {
     return resource.is_overlay_candidate;
   }
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 23a8640d..6c0383e 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1729,6 +1729,12 @@
   if (source->type == RESOURCE_TYPE_BITMAP) {
     resource->mailbox_holder.mailbox = source->shared_bitmap_id;
     resource->is_software = true;
+    if (source->shared_bitmap) {
+      resource->shared_bitmap_sequence_number =
+          source->shared_bitmap->sequence_number();
+    } else {
+      resource->shared_bitmap_sequence_number = 0;
+    }
   } else {
     DCHECK(source->mailbox().IsValid());
     DCHECK(source->mailbox().IsTexture());
diff --git a/cc/resources/transferable_resource.cc b/cc/resources/transferable_resource.cc
index d64a0670..d305971 100644
--- a/cc/resources/transferable_resource.cc
+++ b/cc/resources/transferable_resource.cc
@@ -14,6 +14,7 @@
       filter(0),
       read_lock_fences_enabled(false),
       is_software(false),
+      shared_bitmap_sequence_number(0),
 #if defined(OS_ANDROID)
       is_backed_by_surface_texture(false),
       wants_promotion_hint(false),
diff --git a/cc/resources/transferable_resource.h b/cc/resources/transferable_resource.h
index a4e497c..7fcd0d8 100644
--- a/cc/resources/transferable_resource.h
+++ b/cc/resources/transferable_resource.h
@@ -38,6 +38,7 @@
   gpu::MailboxHolder mailbox_holder;
   bool read_lock_fences_enabled;
   bool is_software;
+  uint32_t shared_bitmap_sequence_number;
 #if defined(OS_ANDROID)
   bool is_backed_by_surface_texture;
   bool wants_promotion_hint;
diff --git a/cc/test/test_shared_bitmap_manager.cc b/cc/test/test_shared_bitmap_manager.cc
index 900aaaa..bc30dd5d 100644
--- a/cc/test/test_shared_bitmap_manager.cc
+++ b/cc/test/test_shared_bitmap_manager.cc
@@ -17,7 +17,9 @@
  public:
   OwnedSharedBitmap(std::unique_ptr<base::SharedMemory> shared_memory,
                     const viz::SharedBitmapId& id)
-      : viz::SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
+      : viz::SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()),
+                          id,
+                          0 /* sequence_number */),
         shared_memory_(std::move(shared_memory)) {}
 
   ~OwnedSharedBitmap() override {}
@@ -34,7 +36,7 @@
 class UnownedSharedBitmap : public viz::SharedBitmap {
  public:
   UnownedSharedBitmap(uint8_t* pixels, const viz::SharedBitmapId& id)
-      : viz::SharedBitmap(pixels, id) {}
+      : viz::SharedBitmap(pixels, id, 0 /* sequence_number */) {}
 
   // viz::SharedBitmap:
   base::SharedMemoryHandle GetSharedMemoryHandle() const override {
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 9b433783..29e26b1 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -409,7 +409,7 @@
         </activity>
         <activity android:name="org.chromium.chrome.browser.firstrun.LightweightFirstRunActivity"
             android:theme="@style/SimpleDialog"
-            android:launchMode="singleTop"
+            android:launchMode="singleInstance"
             android:autoRemoveFromRecents="true"
             android:windowSoftInputMode="stateHidden|adjustPan"
             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize">
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index c68b61e..1d275ba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -34,7 +34,10 @@
     private static final String DISABLE_SEARCH_TERM_RESOLUTION = "disable_search_term_resolution";
     private static final String WAIT_AFTER_TAP_DELAY_MS = "wait_after_tap_delay_ms";
 
-    // Translation.  All these members are private, except for usage by testing.
+    // ------------
+    // Translation.
+    // ------------
+    // All these members are private, except for usage by testing.
     // Master switch, needed to disable all translate code for Contextual Search in case of an
     // emergency.
     @VisibleForTesting
@@ -44,6 +47,9 @@
     static final String ENABLE_ENGLISH_TARGET_TRANSLATION =
             "enable_english_target_translation";
 
+    // ---------------------------------------------
+    // Features for suppression or machine learning.
+    // ---------------------------------------------
     // TODO(donnd): remove all supporting code once short-lived data collection is done.
     private static final String SCREEN_TOP_SUPPRESSION_DPS = "screen_top_suppression_dps";
     private static final String ENABLE_BAR_OVERLAP_COLLECTION = "enable_bar_overlap_collection";
@@ -54,20 +60,25 @@
             "enable_not_long_word_suppression";
     @VisibleForTesting
     static final String NOT_AN_ENTITY_SUPPRESSION_ENABLED = "enable_not_an_entity_suppression";
+    // The threshold for tap suppression based on duration.
+    private static final String TAP_DURATION_THRESHOLD_MS = "tap_duration_threshold_ms";
 
     private static final String MINIMUM_SELECTION_LENGTH = "minimum_selection_length";
 
+    // -----------------
+    // Disable switches.
+    // -----------------
     // Safety switch for disabling online-detection.  Also used to disable detection when running
     // tests.
     @VisibleForTesting
     static final String ONLINE_DETECTION_DISABLED = "disable_online_detection";
-
     private static final String DISABLE_AMP_AS_SEPARATE_TAB = "disable_amp_as_separate_tab";
-
-    // Machine Learning
+    // Disable logging for Machine Learning
     private static final String DISABLE_RANKER_LOGGING = "disable_ranker_logging";
 
-    // Privacy-related flags
+    // ----------------------
+    // Privacy-related flags.
+    // ----------------------
     private static final String DISABLE_SEND_HOME_COUNTRY = "disable_send_home_country";
     private static final String DISABLE_PAGE_CONTENT_NOTIFICATION =
             "disable_page_content_notification";
@@ -98,6 +109,7 @@
     private static Boolean sContextualSearchUrlActionsEnabled;
     private static Boolean sIsRankerLoggingDisabled;
     private static Integer sWaitAfterTapDelayMs;
+    private static Integer sTapDurationThresholdMs;
 
     /**
      * Don't instantiate.
@@ -375,6 +387,18 @@
         return sWaitAfterTapDelayMs.intValue();
     }
 
+    /**
+     * Gets a threshold for the duration of a tap gesture for categorization as brief or lengthy.
+     * @return The maximum amount of time in milliseconds for a tap gesture that's still considered
+     *         a very brief duration tap.
+     */
+    static int getTapDurationThresholdMs() {
+        if (sTapDurationThresholdMs == null) {
+            sTapDurationThresholdMs = getIntParamValueOrDefault(TAP_DURATION_THRESHOLD_MS, 0);
+        }
+        return sTapDurationThresholdMs.intValue();
+    }
+
     // ---------------------------
     // Feature-controlled Switches
     // ---------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java
index 8fe0f7e..db4ad34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java
@@ -4,8 +4,6 @@
 
 package org.chromium.chrome.browser.contextualsearch;
 
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchRankerLogger.Feature;
-
 import java.net.URL;
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
index 6060aea..eabeb55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -46,6 +46,8 @@
     // Max selection length must be limited or the entire request URL can go past the 2K limit.
     private static final int MAX_SELECTION_LENGTH = 100;
 
+    private static final int INVALID_DURATION = -1;
+
     private final ChromeActivity mActivity;
     private final ContextualSearchSelectionHandler mHandler;
     private final float mPxToDp;
@@ -71,6 +73,9 @@
     // When the last tap gesture happened.
     private long mTapTimeNanoseconds;
 
+    // The duration of the last tap gesture in milliseconds, or 0 if not set.
+    private int mTapDurationMs = INVALID_DURATION;
+
     private class ContextualSearchGestureStateListener extends GestureStateListener {
         @Override
         public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {
@@ -89,13 +94,9 @@
             mLastScrollTimeNs = System.nanoTime();
         }
 
-        // TODO(donnd): Remove this once we get notification of the selection changing
-        // after a tap-select gets a subsequent tap nearby.  Currently there's no
-        // notification in this case.
-        // See crbug.com/444114.
         @Override
-        public void onSingleTap(boolean consumed) {
-            // TODO(donnd): remove completely!
+        public void onTouchDown() {
+            mTapTimeNanoseconds = System.nanoTime();
         }
     }
 
@@ -292,6 +293,7 @@
         mLastTapState = null;
         mLastScrollTimeNs = 0;
         mTapTimeNanoseconds = 0;
+        mTapDurationMs = INVALID_DURATION;
         mDidExpandSelection = false;
     }
 
@@ -322,9 +324,11 @@
         mWasTapGestureDetected = false;
         // TODO(donnd): refactor to avoid needing a new handler API method as suggested by Pedro.
         if (mSelectionType != SelectionType.LONG_PRESS) {
+            assert mTapTimeNanoseconds != 0 : "mTapTimeNanoseconds not set!";
+            mTapDurationMs = (int) ((System.nanoTime() - mTapTimeNanoseconds)
+                    / ContextualSearchHeuristic.NANOSECONDS_IN_A_MILLISECOND);
             mWasTapGestureDetected = true;
             mSelectionType = SelectionType.TAP;
-            mTapTimeNanoseconds = System.nanoTime();
             mX = x;
             mY = y;
             mHandler.handleValidTap();
@@ -353,8 +357,9 @@
         ChromePreferenceManager prefs = ChromePreferenceManager.getInstance();
         int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount()
                 - prefs.getContextualSearchTapQuickAnswerCount();
-        TapSuppressionHeuristics tapHeuristics = new TapSuppressionHeuristics(
-                this, mLastTapState, x, y, adjustedTapsSinceOpen, contextualSearchContext);
+        assert mTapDurationMs != INVALID_DURATION : "mTapDurationMs not set!";
+        TapSuppressionHeuristics tapHeuristics = new TapSuppressionHeuristics(this, mLastTapState,
+                x, y, adjustedTapsSinceOpen, contextualSearchContext, mTapDurationMs);
         // TODO(donnd): Move to be called when the panel closes to work with states that change.
         tapHeuristics.logConditionState();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index a49e129..5206970 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -803,6 +803,44 @@
     }
 
     /**
+     * Logs whether results were seen based on the duration of the Tap, for both short and long
+     * durations.
+     * @param wasSearchContentViewSeen If the panel was opened.
+     * @param isTapShort Whether this tap was "short" in duration.
+     */
+    public static void logTapDurationSeen(boolean wasSearchContentViewSeen, boolean isTapShort) {
+        if (isTapShort) {
+            RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapShortDurationSeen",
+                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
+                    RESULTS_SEEN_BOUNDARY);
+        } else {
+            RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapLongDurationSeen",
+                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
+                    RESULTS_SEEN_BOUNDARY);
+        }
+    }
+
+    /**
+     * Logs the duration of a Tap in ms into custom histograms to profile the duration of seen
+     * and not seen taps.
+     * @param wasPanelSeen Whether the panel was seen.
+     * @param durationMs The duration of the tap gesture.
+     */
+    public static void logTapDuration(boolean wasPanelSeen, int durationMs) {
+        int min = 1;
+        int max = 1000;
+        int numBuckets = 100;
+
+        if (wasPanelSeen) {
+            RecordHistogram.recordCustomCountHistogram(
+                    "Search.ContextualSearchTapDurationSeen", durationMs, min, max, numBuckets);
+        } else {
+            RecordHistogram.recordCustomCountHistogram(
+                    "Search.ContextualSearchTapDurationNotSeen", durationMs, min, max, numBuckets);
+        }
+    }
+
+    /**
      * Log whether results were seen due to a Tap on a short word.
      * @param wasSearchContentViewSeen If the panel was opened.
      * @param isTapOnShortWord Whether this tap was on a "short" word.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapDurationSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapDurationSuppression.java
new file mode 100644
index 0000000..3d71153
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapDurationSuppression.java
@@ -0,0 +1,58 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.contextualsearch;
+
+/**
+ * Provides a signal for the duration of a Tap being either brief or lengthy.
+ * This signal could be used for suppression of taps below some threshold, so we aggregate-log too.
+ * We log CTR to UMA for Taps shorter and longer than the threshold.
+ */
+class TapDurationSuppression extends ContextualSearchHeuristic {
+    private static final int DEFAULT_TAP_DURATION_THRESHOLD_MS = 70;
+
+    private final int mTapDurationMs;
+    private final int mTapDurationThresholdMs;
+    private final boolean mIsTapDurationConditionSatisfied;
+
+    /**
+     * Constructs a heuristic to categorize the Tap based on duration as either short or long.
+     * @param tapDurationMs The duration of the tap in milliseconds.
+     */
+    TapDurationSuppression(int tapDurationMs) {
+        mTapDurationMs = tapDurationMs;
+        mTapDurationThresholdMs = ContextualSearchFieldTrial.getTapDurationThresholdMs();
+        int tapDurationThreshold = mTapDurationThresholdMs != 0 ? mTapDurationThresholdMs
+                                                                : DEFAULT_TAP_DURATION_THRESHOLD_MS;
+        mIsTapDurationConditionSatisfied = tapDurationMs < tapDurationThreshold;
+    }
+
+    @Override
+    protected boolean isConditionSatisfiedAndEnabled() {
+        return mIsTapDurationConditionSatisfied && mTapDurationThresholdMs != 0;
+    }
+
+    @Override
+    protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {
+        if (wasActivatedByTap) {
+            ContextualSearchUma.logTapDurationSeen(
+                    wasSearchContentViewSeen, mIsTapDurationConditionSatisfied);
+
+            // TODO(donnd): remove when logging to Ranker is done!
+            ContextualSearchUma.logTapDuration(wasSearchContentViewSeen, mTapDurationMs);
+        }
+    }
+
+    // TODO(donnd): Log the actual tap duration to Ranker once we have privacy-approval!
+
+    @Override
+    protected boolean shouldAggregateLogForTapSuppression() {
+        return true;
+    }
+
+    @Override
+    protected boolean isConditionSatisfiedForAggregateLogging() {
+        return mIsTapDurationConditionSatisfied;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
index ab9358fc..b0eef111 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java
@@ -20,13 +20,14 @@
      */
     TapSuppressionHeuristics(ContextualSearchSelectionController selectionController,
             ContextualSearchTapState previousTapState, int x, int y, int tapsSinceOpen,
-            ContextualSearchContext contextualSearchContext) {
+            ContextualSearchContext contextualSearchContext, int tapDurationMs) {
         super();
         mCtrSuppression = new CtrSuppression();
         mHeuristics.add(mCtrSuppression);
         mHeuristics.add(new RecentScrollTapSuppression(selectionController));
         mHeuristics.add(
                 new TapFarFromPreviousSuppression(selectionController, previousTapState, x, y));
+        mHeuristics.add(new TapDurationSuppression(tapDurationMs));
         mHeuristics.add(new TapWordLengthSuppression(contextualSearchContext));
         mHeuristics.add(new TapWordEdgeSuppression(contextualSearchContext));
         mHeuristics.add(new ContextualSearchEntityHeuristic(contextualSearchContext));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
index de4082e..8fcca29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -376,17 +376,10 @@
                 List<WeakReference<Activity>> activities = ApplicationStatus.getRunningActivities();
                 for (WeakReference<Activity> weakActivity : activities) {
                     Activity activity = weakActivity.get();
-                    if (activity == null) {
-                        continue;
-                    } else if (activity instanceof LightweightFirstRunActivity) {
-                        // A Generic or a new Lightweight First Run Experience will be launched
-                        // below, so finish the old Lightweight First Run Experience.
-                        activity.setResult(Activity.RESULT_CANCELED);
-                        activity.finish();
-                        continue;
-                    } else if (activity instanceof FirstRunActivity) {
+                    if (activity instanceof FirstRunActivity
+                            && !(activity instanceof LightweightFirstRunActivity)) {
                         isGenericFreActive = true;
-                        continue;
+                        break;
                     }
                 }
 
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index ebabaca5..a407dd6 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -263,6 +263,7 @@
   "java/src/org/chromium/chrome/browser/contextualsearch/QuickAnswersHeuristic.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/RecentScrollTapSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/SwipeRecognizer.java",
+  "java/src/org/chromium/chrome/browser/contextualsearch/TapDurationSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/TapFarFromPreviousSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java",
   "java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
index 0b23f5bd..cb1ceb7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -203,6 +203,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
+                mContextualSearchManager.getGestureStateListener().onTouchDown();
                 mContextualSearchClient.showUnhandledTapUIIfNeeded(0, 0);
             }
         });
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 4f6bd5ea..51d0c55 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1299,8 +1299,6 @@
     "ssl/chrome_ssl_host_state_delegate_factory.h",
     "ssl/common_name_mismatch_handler.cc",
     "ssl/common_name_mismatch_handler.h",
-    "ssl/ignore_errors_cert_verifier.cc",
-    "ssl/ignore_errors_cert_verifier.h",
     "ssl/security_state_tab_helper.cc",
     "ssl/security_state_tab_helper.h",
     "ssl/ssl_blocking_page.cc",
@@ -3405,6 +3403,8 @@
       "resource_coordinator/tab_manager.h",
       "resource_coordinator/tab_manager_delegate_chromeos.cc",
       "resource_coordinator/tab_manager_delegate_chromeos.h",
+      "resource_coordinator/tab_manager_grc_tab_signal_observer.cc",
+      "resource_coordinator/tab_manager_grc_tab_signal_observer.h",
       "resource_coordinator/tab_manager_observer.cc",
       "resource_coordinator/tab_manager_observer.h",
       "resource_coordinator/tab_manager_web_contents_data.cc",
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 84a39b50..b99c229 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -46,10 +46,10 @@
 void UpdateNotifier(
     DownloadManagerService* service,
     content::DownloadManager* manager,
-    std::unique_ptr<content::AllDownloadItemNotifier>& notifier) {
+    std::unique_ptr<download::AllDownloadItemNotifier>& notifier) {
   if (manager) {
     if (!notifier || notifier->GetManager() != manager)
-      notifier.reset(new content::AllDownloadItemNotifier(manager, service));
+      notifier.reset(new download::AllDownloadItemNotifier(manager, service));
   } else {
     notifier.reset(nullptr);
   }
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h
index cb66aad..7f241c63 100644
--- a/chrome/browser/android/download/download_manager_service.h
+++ b/chrome/browser/android/download/download_manager_service.h
@@ -16,7 +16,7 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/android/download/download_controller.h"
 #include "chrome/browser/download/download_history.h"
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "content/public/browser/download_manager.h"
 
 using base::android::JavaParamRef;
@@ -28,7 +28,7 @@
 // Native side of DownloadManagerService.java. The native object is owned by its
 // Java object.
 class DownloadManagerService
-    : public content::AllDownloadItemNotifier::Observer,
+    : public download::AllDownloadItemNotifier::Observer,
       public DownloadHistory::Observer {
  public:
   // JNI registration.
@@ -176,8 +176,8 @@
 
   ResumeCallback resume_callback_for_testing_;
 
-  std::unique_ptr<content::AllDownloadItemNotifier> original_notifier_;
-  std::unique_ptr<content::AllDownloadItemNotifier> off_the_record_notifier_;
+  std::unique_ptr<download::AllDownloadItemNotifier> original_notifier_;
+  std::unique_ptr<download::AllDownloadItemNotifier> off_the_record_notifier_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadManagerService);
 };
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5652731..d5a988f 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -74,6 +74,7 @@
     "//components/crx_file",
     "//components/cryptauth",
     "//components/device_event_log",
+    "//components/download/content/public",
     "//components/drive",
     "//components/drive:drive_chromeos",
     "//components/exo",
diff --git a/chrome/browser/chromeos/drive/download_handler.cc b/chrome/browser/chromeos/drive/download_handler.cc
index fde753a..7cb6663 100644
--- a/chrome/browser/chromeos/drive/download_handler.cc
+++ b/chrome/browser/chromeos/drive/download_handler.cc
@@ -171,7 +171,7 @@
 
   if (download_manager) {
     notifier_.reset(
-        new content::AllDownloadItemNotifier(download_manager, this));
+        new download::AllDownloadItemNotifier(download_manager, this));
     // Remove any persisted Drive DownloadItem. crbug.com/171384
     DownloadManager::DownloadVector downloads;
     download_manager->GetAllDownloads(&downloads);
@@ -185,7 +185,7 @@
 void DownloadHandler::ObserveIncognitoDownloadManager(
     DownloadManager* download_manager) {
   notifier_incognito_.reset(
-      new content::AllDownloadItemNotifier(download_manager, this));
+      new download::AllDownloadItemNotifier(download_manager, this));
 }
 
 void DownloadHandler::SubstituteDriveDownloadPath(
diff --git a/chrome/browser/chromeos/drive/download_handler.h b/chrome/browser/chromeos/drive/download_handler.h
index f2f54a1..b48dc49 100644
--- a/chrome/browser/chromeos/drive/download_handler.h
+++ b/chrome/browser/chromeos/drive/download_handler.h
@@ -10,8 +10,8 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "components/drive/file_errors.h"
-#include "content/public/browser/all_download_item_notifier.h"
 #include "content/public/browser/download_manager_delegate.h"
 
 class Profile;
@@ -27,7 +27,7 @@
 
 // Observes downloads to temporary local drive folder. Schedules these
 // downloads for upload to drive service.
-class DownloadHandler : public content::AllDownloadItemNotifier::Observer {
+class DownloadHandler : public download::AllDownloadItemNotifier::Observer {
  public:
   explicit DownloadHandler(FileSystemInterface* file_system);
   ~DownloadHandler() override;
@@ -122,8 +122,8 @@
   FileSystemInterface* file_system_;  // Owned by DriveIntegrationService.
 
   // Observe the DownloadManager for new downloads.
-  std::unique_ptr<content::AllDownloadItemNotifier> notifier_;
-  std::unique_ptr<content::AllDownloadItemNotifier> notifier_incognito_;
+  std::unique_ptr<download::AllDownloadItemNotifier> notifier_;
+  std::unique_ptr<download::AllDownloadItemNotifier> notifier_incognito_;
 
   // Temporary download location directory.
   base::FilePath drive_tmp_download_path_;
diff --git a/chrome/browser/download/download_history.h b/chrome/browser/download/download_history.h
index 20d6667..8598e6a 100644
--- a/chrome/browser/download/download_history.h
+++ b/chrome/browser/download/download_history.h
@@ -14,8 +14,8 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "components/history/core/browser/history_service.h"
-#include "content/public/browser/all_download_item_notifier.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
 
@@ -25,7 +25,7 @@
 
 // Observes a single DownloadManager and all its DownloadItems, keeping the
 // DownloadDatabase up to date.
-class DownloadHistory : public content::AllDownloadItemNotifier::Observer {
+class DownloadHistory : public download::AllDownloadItemNotifier::Observer {
  public:
   typedef std::set<uint32_t> IdSet;
 
@@ -133,7 +133,7 @@
   // Removes all |removing_ids_| from |history_|.
   void RemoveDownloadsBatch();
 
-  content::AllDownloadItemNotifier notifier_;
+  download::AllDownloadItemNotifier notifier_;
 
   std::unique_ptr<HistoryAdapter> history_;
 
diff --git a/chrome/browser/download/download_status_updater.cc b/chrome/browser/download/download_status_updater.cc
index ce23b5e..d5730e3 100644
--- a/chrome/browser/download/download_status_updater.cc
+++ b/chrome/browser/download/download_status_updater.cc
@@ -92,7 +92,7 @@
 
 void DownloadStatusUpdater::AddManager(content::DownloadManager* manager) {
   notifiers_.push_back(
-      base::MakeUnique<content::AllDownloadItemNotifier>(manager, this));
+      base::MakeUnique<download::AllDownloadItemNotifier>(manager, this));
   content::DownloadManager::DownloadVector items;
   manager->GetAllDownloads(&items);
   for (auto* item : items)
diff --git a/chrome/browser/download/download_status_updater.h b/chrome/browser/download/download_status_updater.h
index bed04e73..c22d852 100644
--- a/chrome/browser/download/download_status_updater.h
+++ b/chrome/browser/download/download_status_updater.h
@@ -9,13 +9,13 @@
 #include <set>
 
 #include "base/macros.h"
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
 
 // Keeps track of download progress for the entire browser.
 class DownloadStatusUpdater
-    : public content::AllDownloadItemNotifier::Observer {
+    : public download::AllDownloadItemNotifier::Observer {
  public:
   DownloadStatusUpdater();
   ~DownloadStatusUpdater() override;
@@ -47,7 +47,7 @@
   virtual void UpdateAppIconDownloadProgress(content::DownloadItem* download);
 
  private:
-  std::vector<std::unique_ptr<content::AllDownloadItemNotifier>> notifiers_;
+  std::vector<std::unique_ptr<download::AllDownloadItemNotifier>> notifiers_;
 
   DISALLOW_COPY_AND_ASSIGN(DownloadStatusUpdater);
 };
diff --git a/chrome/browser/download/download_status_updater_unittest.cc b/chrome/browser/download/download_status_updater_unittest.cc
index e11b25a..532c9b5 100644
--- a/chrome/browser/download/download_status_updater_unittest.cc
+++ b/chrome/browser/download/download_status_updater_unittest.cc
@@ -87,6 +87,7 @@
     while (manager_observers_.size() <= static_cast<size_t>(i)) {
       manager_observers_.push_back(nullptr);
     }
+    EXPECT_CALL(*mgr, IsManagerInitialized());
     EXPECT_CALL(*mgr, AddObserver(_))
         .WillOnce(WithArg<0>(Invoke(
             this, &DownloadStatusUpdaterTest::SetObserver)));
diff --git a/chrome/browser/download/download_ui_controller.h b/chrome/browser/download/download_ui_controller.h
index 43bf314..a3934e3 100644
--- a/chrome/browser/download/download_ui_controller.h
+++ b/chrome/browser/download/download_ui_controller.h
@@ -9,13 +9,14 @@
 #include <set>
 
 #include "base/macros.h"
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 
 // This class handles the task of observing a single DownloadManager for
 // notifying the UI when a new download should be displayed in the UI.
 // It invokes the OnNewDownloadReady() method of hte Delegate when the
 // target path is available for a new download.
-class DownloadUIController : public content::AllDownloadItemNotifier::Observer {
+class DownloadUIController
+    : public download::AllDownloadItemNotifier::Observer {
  public:
   // The delegate is responsible for figuring out how to notify the UI.
   class Delegate {
@@ -45,7 +46,7 @@
   void OnDownloadUpdated(content::DownloadManager* manager,
                          content::DownloadItem* item) override;
 
-  content::AllDownloadItemNotifier download_notifier_;
+  download::AllDownloadItemNotifier download_notifier_;
 
   std::unique_ptr<Delegate> delegate_;
 
diff --git a/chrome/browser/download/download_ui_controller_unittest.cc b/chrome/browser/download/download_ui_controller_unittest.cc
index 87af5bd..0df2161 100644
--- a/chrome/browser/download/download_ui_controller_unittest.cc
+++ b/chrome/browser/download/download_ui_controller_unittest.cc
@@ -170,6 +170,7 @@
   ChromeRenderViewHostTestHarness::SetUp();
 
   manager_.reset(new testing::StrictMock<MockDownloadManager>());
+  EXPECT_CALL(*manager_, IsManagerInitialized()).Times(AnyNumber());
   EXPECT_CALL(*manager_, AddObserver(_))
       .WillOnce(SaveArg<0>(&download_history_manager_observer_));
   EXPECT_CALL(*manager_,
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 07509f3..c8e7637a 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -831,6 +831,7 @@
     "//components/cryptauth",
     "//components/data_reduction_proxy/core/browser",
     "//components/dom_distiller/core",
+    "//components/download/content/public",
     "//components/drive",
     "//components/favicon/content",
     "//components/feedback",
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index a253325..084d39b 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -17,7 +17,7 @@
 #include "chrome/browser/download/download_path_reservation_tracker.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/common/extensions/api/downloads.h"
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "content/public/browser/download_manager.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_registry_observer.h"
@@ -299,7 +299,7 @@
 class ExtensionDownloadsEventRouter
     : public extensions::EventRouter::Observer,
       public extensions::ExtensionRegistryObserver,
-      public content::AllDownloadItemNotifier::Observer {
+      public download::AllDownloadItemNotifier::Observer {
  public:
   typedef base::Callback<void(
       const base::FilePath& changed_filename,
@@ -391,7 +391,7 @@
                            extensions::UnloadedExtensionReason reason) override;
 
   Profile* profile_;
-  content::AllDownloadItemNotifier notifier_;
+  download::AllDownloadItemNotifier notifier_;
   std::set<const extensions::Extension*> shelf_disabling_extensions_;
 
   base::Time last_checked_removal_;
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
index a2b8a6b..1351c63 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_unittest.cc
@@ -69,6 +69,7 @@
     ExtensionApiUnittest::SetUp();
 
     manager_.reset(new testing::StrictMock<MockDownloadManager>());
+    EXPECT_CALL(*manager_, IsManagerInitialized());
     EXPECT_CALL(*manager_, AddObserver(testing::_))
         .WillOnce(testing::SaveArg<0>(&download_history_manager_observer_));
     EXPECT_CALL(*manager_, RemoveObserver(testing::Eq(testing::ByRef(
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 9dcd7f0..be6e9b6 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/net/dns_probe_service.h"
 #include "chrome/browser/net/proxy_service_factory.h"
 #include "chrome/browser/net/sth_distributor_provider.h"
-#include "chrome/browser/ssl/ignore_errors_cert_verifier.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_content_client.h"
 #include "chrome/common/chrome_switches.h"
@@ -63,6 +62,7 @@
 #include "components/variations/variations_associated_data.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/ignore_errors_cert_verifier.h"
 #include "content/public/browser/network_quality_observer_factory.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -819,18 +819,21 @@
 
   builder->set_host_resolver(std::move(host_resolver));
 
+  std::unique_ptr<net::CertVerifier> cert_verifier;
 #if defined(OS_CHROMEOS)
   // Creates a CertVerifyProc that doesn't allow any profile-provided certs.
-  builder->SetCertVerifier(base::MakeUnique<net::CachingCertVerifier>(
+  cert_verifier = base::MakeUnique<net::CachingCertVerifier>(
       base::MakeUnique<net::MultiThreadedCertVerifier>(
-          new chromeos::CertVerifyProcChromeOS())));
+          new chromeos::CertVerifyProcChromeOS()));
 #else
-  builder->SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
-      command_line, net::CertVerifier::CreateDefault()));
+  cert_verifier = net::CertVerifier::CreateDefault();
+#endif
+  builder->SetCertVerifier(
+      content::IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+          command_line, switches::kUserDataDir, std::move(cert_verifier)));
   UMA_HISTOGRAM_BOOLEAN(
       "Net.Certificate.IgnoreCertificateErrorsSPKIListPresent",
       command_line.HasSwitch(switches::kIgnoreCertificateErrorsSPKIList));
-#endif
 
   std::unique_ptr<net::MultiLogCTVerifier> ct_verifier =
       base::MakeUnique<net::MultiLogCTVerifier>();
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
index 1ad648b..022649b 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.cc
@@ -8,7 +8,6 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "components/cast_channel/cast_socket_service.h"
-#include "components/cast_channel/cast_socket_service_factory.h"
 #include "components/net_log/chrome_net_log.h"
 #include "content/public/common/content_client.h"
 #include "net/base/host_port_pair.h"
@@ -16,8 +15,6 @@
 
 namespace {
 
-constexpr char kObserverId[] = "browser_observer_id";
-
 enum ErrorType {
   NONE,
   NOT_CAST_DEVICE,
@@ -90,10 +87,9 @@
 CastMediaSinkService::CastMediaSinkService(
     const OnSinksDiscoveredCallback& callback,
     content::BrowserContext* browser_context)
-    : MediaSinkServiceBase(callback) {
+    : MediaSinkServiceBase(callback),
+      cast_socket_service_(cast_channel::CastSocketService::GetInstance()) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  cast_socket_service_ = cast_channel::CastSocketServiceFactory::GetInstance()
-                             ->GetForBrowserContext(browser_context);
   DCHECK(cast_socket_service_);
 }
 
@@ -169,17 +165,14 @@
 void CastMediaSinkService::OpenChannelOnIOThread(
     const DnsSdService& service,
     const net::IPEndPoint& ip_endpoint) {
-  auto* observer = cast_socket_service_->GetObserver(kObserverId);
-  if (!observer) {
-    observer = new CastSocketObserver();
-    cast_socket_service_->AddObserver(kObserverId, base::WrapUnique(observer));
-  }
+  if (!observer_)
+    observer_.reset(new CastSocketObserver());
 
   cast_socket_service_->OpenSocket(
       ip_endpoint, g_browser_process->net_log(),
       base::Bind(&CastMediaSinkService::OnChannelOpenedOnIOThread, this,
                  service),
-      observer);
+      observer_.get());
 }
 
 void CastMediaSinkService::OnChannelOpenedOnIOThread(
@@ -228,7 +221,9 @@
 }
 
 CastMediaSinkService::CastSocketObserver::CastSocketObserver() {}
-CastMediaSinkService::CastSocketObserver::~CastSocketObserver() {}
+CastMediaSinkService::CastSocketObserver::~CastSocketObserver() {
+  cast_channel::CastSocketService::GetInstance()->RemoveObserver(this);
+}
 
 void CastMediaSinkService::CastSocketObserver::OnError(
     const cast_channel::CastSocket& socket,
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
index 2030c05..df6e60e 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service.h
@@ -16,6 +16,7 @@
 #include "chrome/browser/media/router/discovery/media_sink_service_base.h"
 #include "components/cast_channel/cast_channel_enum.h"
 #include "components/cast_channel/cast_socket.h"
+#include "content/public/browser/browser_thread.h"
 #include "net/base/ip_endpoint.h"
 
 namespace cast_channel {
@@ -119,8 +120,13 @@
   // Service list from current round of discovery.
   DnsSdRegistry::DnsSdServiceList current_services_;
 
-  // Service managing creating and removing cast channels.
-  scoped_refptr<cast_channel::CastSocketService> cast_socket_service_;
+  // Raw pointer of leaky singleton CastSocketService, which manages creating
+  // and removing Cast sockets.
+  cast_channel::CastSocketService* const cast_socket_service_;
+
+  std::unique_ptr<cast_channel::CastSocket::Observer,
+                  content::BrowserThread::DeleteOnIOThread>
+      observer_;
 
   THREAD_CHECKER(thread_checker_);
 
diff --git a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
index 7e12a975..963a24e 100644
--- a/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
+++ b/chrome/browser/media/router/discovery/mdns/cast_media_sink_service_unittest.cc
@@ -68,23 +68,10 @@
 
 namespace media_router {
 
-class MockCastSocketService : public cast_channel::CastSocketService {
- public:
-  MOCK_METHOD4(OpenSocket,
-               int(const net::IPEndPoint& ip_endpoint,
-                   net::NetLog* net_log,
-                   const cast_channel::CastSocket::OnOpenCallback& open_cb,
-                   cast_channel::CastSocket::Observer* observer));
-  MOCK_CONST_METHOD1(GetSocket, cast_channel::CastSocket*(int channel_id));
-
- private:
-  ~MockCastSocketService() {}
-};
-
 class CastMediaSinkServiceTest : public ::testing::Test {
  public:
   CastMediaSinkServiceTest()
-      : mock_cast_socket_service_(new MockCastSocketService()),
+      : mock_cast_socket_service_(new cast_channel::MockCastSocketService()),
         media_sink_service_(
             new CastMediaSinkService(mock_sink_discovered_cb_.Get(),
                                      mock_cast_socket_service_.get())),
@@ -103,7 +90,8 @@
 
   base::MockCallback<MediaSinkService::OnSinksDiscoveredCallback>
       mock_sink_discovered_cb_;
-  scoped_refptr<MockCastSocketService> mock_cast_socket_service_;
+  std::unique_ptr<cast_channel::MockCastSocketService>
+      mock_cast_socket_service_;
   scoped_refptr<CastMediaSinkService> media_sink_service_;
   MockDnsSdRegistry test_dns_sd_registry_;
   base::MockTimer* mock_timer_;
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index 427d73b..4356ae3d 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -228,7 +228,8 @@
   std::unique_ptr<base::File, content::BrowserThread::DeleteOnFileThread>
       temp_file) {
   if (settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2 ||
-      settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3) {
+      settings_.mode == PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3 ||
+      settings_.mode == PdfRenderSettings::Mode::TEXTONLY) {
     return base::MakeUnique<PostScriptMetaFile>(temp_dir_,
                                                 std::move(temp_file));
   }
diff --git a/chrome/browser/printing/print_job.cc b/chrome/browser/printing/print_job.cc
index d5e81cd..d9535550 100644
--- a/chrome/browser/printing/print_job.cc
+++ b/chrome/browser/printing/print_job.cc
@@ -318,6 +318,21 @@
       base::Bind(&PrintJob::OnPdfPageConverted, this));
 }
 
+void PrintJob::StartPdfToTextConversion(
+    const scoped_refptr<base::RefCountedMemory>& bytes,
+    const gfx::Size& page_size) {
+  DCHECK(!pdf_conversion_state_);
+  pdf_conversion_state_ =
+      base::MakeUnique<PdfConversionState>(gfx::Size(), gfx::Rect());
+  const int kPrinterDpi = settings().dpi();
+  gfx::Rect page_area = gfx::Rect(0, 0, page_size.width(), page_size.height());
+  PdfRenderSettings settings(page_area, gfx::Point(0, 0), kPrinterDpi,
+                             /*autorotate=*/true,
+                             PdfRenderSettings::Mode::TEXTONLY);
+  pdf_conversion_state_->Start(
+      bytes, settings, base::Bind(&PrintJob::OnPdfConversionStarted, this));
+}
+
 void PrintJob::StartPdfToPostScriptConversion(
     const scoped_refptr<base::RefCountedMemory>& bytes,
     const gfx::Rect& content_area,
diff --git a/chrome/browser/printing/print_job.h b/chrome/browser/printing/print_job.h
index aa293c8..6a189d6 100644
--- a/chrome/browser/printing/print_job.h
+++ b/chrome/browser/printing/print_job.h
@@ -105,6 +105,10 @@
       const gfx::Rect& content_area,
       const gfx::Point& physical_offset,
       bool ps_level2);
+
+  void StartPdfToTextConversion(
+      const scoped_refptr<base::RefCountedMemory>& bytes,
+      const gfx::Size& page_size);
 #endif  // defined(OS_WIN)
 
  protected:
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index d7f5ec8..9d81a019 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -189,8 +189,11 @@
     document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf"));
 
     const auto& settings = document->settings();
-    if ((settings.printer_is_ps2() || settings.printer_is_ps3()) &&
-        !base::FeatureList::IsEnabled(features::kDisablePostScriptPrinting)) {
+    if (settings.printer_is_textonly()) {
+      print_job_->StartPdfToTextConversion(bytes, params.page_size);
+    } else if ((settings.printer_is_ps2() || settings.printer_is_ps3()) &&
+               !base::FeatureList::IsEnabled(
+                   features::kDisablePostScriptPrinting)) {
       print_job_->StartPdfToPostScriptConversion(bytes, params.content_area,
                                                  params.physical_offsets,
                                                  settings.printer_is_ps2());
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index 7e3f0c7..1b84c5f 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -30,6 +30,8 @@
 #include "chrome/browser/media/webrtc/media_stream_capture_indicator.h"
 #include "chrome/browser/memory/oom_memory_details.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/resource_coordinator/resource_coordinator_web_contents_observer.h"
+#include "chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h"
 #include "chrome/browser/resource_coordinator/tab_manager_observer.h"
 #include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
 #include "chrome/browser/sessions/session_restore.h"
@@ -51,6 +53,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/page_importance_signals.h"
+#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/multi_profile_uma.h"
@@ -149,6 +152,9 @@
 #endif
   browser_tab_strip_tracker_.Init();
   session_restore_observer_.reset(new TabManagerSessionRestoreObserver(this));
+  if (resource_coordinator::IsResourceCoordinatorEnabled()) {
+    grc_tab_signal_observer_.reset(new GRCTabSignalObserver());
+  }
 }
 
 TabManager::~TabManager() {
@@ -848,6 +854,16 @@
                                content::WebContents* contents,
                                int index,
                                bool foreground) {
+  // Gets CoordinationUnitID for this WebContents and adds it to
+  // GRCTabSignalObserver.
+  if (grc_tab_signal_observer_) {
+    auto* tab_resource_coordinator =
+        ResourceCoordinatorWebContentsObserver::FromWebContents(contents)
+            ->tab_resource_coordinator();
+    grc_tab_signal_observer_->AssociateCoordinationUnitIDWithWebContents(
+        tab_resource_coordinator->id(), contents);
+  }
+
   // Only interested in background tabs, as foreground tabs get taken care of by
   // ActiveTabChanged.
   if (foreground)
@@ -861,6 +877,20 @@
       GetTimeToPurge(min_time_to_purge_, max_time_to_purge_));
 }
 
+void TabManager::TabClosingAt(TabStripModel* tab_strip_model,
+                              content::WebContents* contents,
+                              int index) {
+  // Gets CoordinationUnitID for this WebContents and removes it from
+  // GRCTabSignalObserver.
+  if (!grc_tab_signal_observer_)
+    return;
+  auto* tab_resource_coordinator =
+      ResourceCoordinatorWebContentsObserver::FromWebContents(contents)
+          ->tab_resource_coordinator();
+  grc_tab_signal_observer_->RemoveCoordinationUnitID(
+      tab_resource_coordinator->id());
+}
+
 void TabManager::OnBrowserSetLastActive(Browser* browser) {
   // Reload the active tab in |browser| if it is discarded.
   content::WebContents* contents =
diff --git a/chrome/browser/resource_coordinator/tab_manager.h b/chrome/browser/resource_coordinator/tab_manager.h
index 6600088..aa5deb5f 100644
--- a/chrome/browser/resource_coordinator/tab_manager.h
+++ b/chrome/browser/resource_coordinator/tab_manager.h
@@ -72,6 +72,8 @@
 class TabManager : public TabStripModelObserver,
                    public chrome::BrowserListObserver {
  public:
+  // Forward declaration of tab signal observer.
+  class GRCTabSignalObserver;
   // Needs to be public for DEFINE_WEB_CONTENTS_USER_DATA_KEY.
   class WebContentsData;
 
@@ -326,6 +328,9 @@
                      content::WebContents* contents,
                      int index,
                      bool foreground) override;
+  void TabClosingAt(TabStripModel* tab_strip_model,
+                    content::WebContents* contents,
+                    int index) override;
 
   // BrowserListObserver overrides.
   void OnBrowserSetLastActive(Browser* browser) override;
@@ -468,6 +473,9 @@
   // is brought to foreground.
   std::set<content::WebContents*> loading_contents_;
 
+  // GRC tab signal observer, receives tab scoped signal from GRC.
+  std::unique_ptr<GRCTabSignalObserver> grc_tab_signal_observer_;
+
   // Weak pointer factory used for posting delayed tasks.
   base::WeakPtrFactory<TabManager> weak_ptr_factory_;
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.cc b/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.cc
new file mode 100644
index 0000000..53a8638
--- /dev/null
+++ b/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.cc
@@ -0,0 +1,54 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h"
+
+#include "chrome/browser/resource_coordinator/tab_manager_web_contents_data.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
+#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace resource_coordinator {
+
+TabManager::GRCTabSignalObserver::GRCTabSignalObserver() : binding_(this) {
+  service_manager::Connector* connector =
+      content::ServiceManagerConnection::GetForProcess()->GetConnector();
+  mojom::TabSignalGeneratorPtr tab_signal_generator_ptr;
+  connector->BindInterface(mojom::kServiceName,
+                           mojo::MakeRequest(&tab_signal_generator_ptr));
+
+  mojom::TabSignalObserverPtr tab_signal_observer_ptr;
+  binding_.Bind(mojo::MakeRequest(&tab_signal_observer_ptr));
+  tab_signal_generator_ptr->AddObserver(std::move(tab_signal_observer_ptr));
+}
+
+TabManager::GRCTabSignalObserver::~GRCTabSignalObserver() = default;
+
+void TabManager::GRCTabSignalObserver::OnEventReceived(
+    const CoordinationUnitID& cu_id,
+    mojom::TabEvent event) {
+  if (event == mojom::TabEvent::kDoneLoading) {
+    auto web_contents_iter = cu_id_web_contents_map_.find(cu_id);
+    if (web_contents_iter == cu_id_web_contents_map_.end())
+      return;
+    auto* web_contents_data =
+        TabManager::WebContentsData::FromWebContents(web_contents_iter->second);
+    web_contents_data->DoneLoading();
+  }
+}
+
+void TabManager::GRCTabSignalObserver::
+    AssociateCoordinationUnitIDWithWebContents(
+        const CoordinationUnitID& cu_id,
+        content::WebContents* web_contents) {
+  cu_id_web_contents_map_[cu_id] = web_contents;
+}
+
+void TabManager::GRCTabSignalObserver::RemoveCoordinationUnitID(
+    const CoordinationUnitID& cu_id) {
+  cu_id_web_contents_map_.erase(cu_id);
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h b/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h
new file mode 100644
index 0000000..b4e019a
--- /dev/null
+++ b/chrome/browser/resource_coordinator/tab_manager_grc_tab_signal_observer.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_GRC_TAB_SIGNAL_OBSERVER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_GRC_TAB_SIGNAL_OBSERVER_H_
+
+#include "base/macros.h"
+#include "chrome/browser/resource_coordinator/tab_manager.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/resource_coordinator/public/interfaces/tab_signal.mojom.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace resource_coordinator {
+
+// Implementation of resource_coordinator::mojom::TabSignalObserver,
+// observer constructs a mojo channel to TabSignalGenerator in GRC, passes an
+// interface pointer to TabSignalGenerator, and receives tab scoped signals from
+// TabSignalGenerator once a signal is generated.
+class TabManager::GRCTabSignalObserver : public mojom::TabSignalObserver {
+ public:
+  GRCTabSignalObserver();
+  ~GRCTabSignalObserver() override;
+
+  // mojom::TabSignalObserver implementation.
+  void OnEventReceived(const CoordinationUnitID& cu_id,
+                       mojom::TabEvent event) override;
+
+  void AssociateCoordinationUnitIDWithWebContents(
+      const CoordinationUnitID& cu_id,
+      content::WebContents* web_contents);
+
+  void RemoveCoordinationUnitID(const CoordinationUnitID& cu_id);
+
+ private:
+  mojo::Binding<mojom::TabSignalObserver> binding_;
+  std::map<CoordinationUnitID, content::WebContents*> cu_id_web_contents_map_;
+  DISALLOW_COPY_AND_ASSIGN(GRCTabSignalObserver);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_GRC_TAB_SIGNAL_OBSERVER_H_
diff --git a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
index 8cbe85b..379b46b 100644
--- a/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
+++ b/chrome/browser/resource_coordinator/tab_manager_web_contents_data.h
@@ -61,6 +61,9 @@
       content::NavigationHandle* navigation_handle) override;
   void WebContentsDestroyed() override;
 
+  // Tab signal received from GRC.
+  void DoneLoading() {}
+
   // Returns true if the tab has been discarded to save memory.
   bool IsDiscarded();
 
diff --git a/chrome/browser/subresource_filter/subresource_filter_test_harness.cc b/chrome/browser/subresource_filter/subresource_filter_test_harness.cc
new file mode 100644
index 0000000..0feb38e
--- /dev/null
+++ b/chrome/browser/subresource_filter/subresource_filter_test_harness.cc
@@ -0,0 +1,163 @@
+// 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 <memory>
+#include <utility>
+
+#include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/after_startup_task_utils.h"
+#include "chrome/browser/content_settings/tab_specific_content_settings.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
+#include "chrome/browser/subresource_filter/subresource_filter_content_settings_manager.h"
+#include "chrome/browser/subresource_filter/subresource_filter_profile_context.h"
+#include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
+#include "chrome/browser/subresource_filter/subresource_filter_test_harness.h"
+#include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "components/safe_browsing_db/v4_protocol_manager_util.h"
+#include "components/subresource_filter/content/browser/content_ruleset_service.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
+#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
+#include "components/subresource_filter/core/browser/ruleset_service.h"
+#include "components/subresource_filter/core/common/activation_decision.h"
+#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+#include "components/subresource_filter/core/common/test_ruleset_creator.h"
+#include "content/public/browser/navigation_throttle.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+constexpr char const SubresourceFilterTestHarness::kDefaultDisallowedUrl[];
+
+SubresourceFilterTestHarness::SubresourceFilterTestHarness() = default;
+SubresourceFilterTestHarness::~SubresourceFilterTestHarness() = default;
+
+// ChromeRenderViewHostTestHarness:
+void SubresourceFilterTestHarness::SetUp() {
+  ChromeRenderViewHostTestHarness::SetUp();
+  AfterStartupTaskUtils::SetBrowserStartupIsCompleteForTesting();
+
+  // Ensure correct features.
+  scoped_feature_toggle_.ResetSubresourceFilterState(
+      base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+      "SafeBrowsingV4OnlyEnabled,SubresourceFilterExperimentalUI");
+  scoped_configuration_.ResetConfiguration(subresource_filter::Configuration(
+      subresource_filter::ActivationLevel::ENABLED,
+      subresource_filter::ActivationScope::ACTIVATION_LIST,
+      subresource_filter::ActivationList::SUBRESOURCE_FILTER));
+
+  NavigateAndCommit(GURL("https://example.first"));
+
+  // Set up safe browsing service with the fake database manager.
+  //
+  // TODO(csharrison): This is a bit ugly. See if the instructions in
+  // test_safe_browsing_service.h can be adapted to be used in unit tests.
+  safe_browsing::TestSafeBrowsingServiceFactory sb_service_factory;
+  fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
+  sb_service_factory.SetTestDatabaseManager(fake_safe_browsing_database_.get());
+  safe_browsing::SafeBrowsingService::RegisterFactory(&sb_service_factory);
+  auto* safe_browsing_service = sb_service_factory.CreateSafeBrowsingService();
+  safe_browsing::SafeBrowsingService::RegisterFactory(nullptr);
+  TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
+      safe_browsing_service);
+  g_browser_process->safe_browsing_service()->Initialize();
+
+  // Set up the ruleset service.
+  ASSERT_TRUE(ruleset_service_dir_.CreateUniqueTempDir());
+  subresource_filter::IndexedRulesetVersion::RegisterPrefs(
+      pref_service_.registry());
+  auto content_service =
+      base::MakeUnique<subresource_filter::ContentRulesetService>(
+          base::ThreadTaskRunnerHandle::Get());
+  auto ruleset_service = base::MakeUnique<subresource_filter::RulesetService>(
+      &pref_service_, base::ThreadTaskRunnerHandle::Get(),
+      content_service.get(), ruleset_service_dir_.GetPath());
+  content_service->set_ruleset_service(std::move(ruleset_service));
+  TestingBrowserProcess::GetGlobal()->SetRulesetService(
+      std::move(content_service));
+
+  // Publish the test ruleset.
+  subresource_filter::testing::TestRulesetCreator ruleset_creator;
+  subresource_filter::testing::TestRulesetPair test_ruleset_pair;
+  ruleset_creator.CreateRulesetToDisallowURLsWithPathSuffix("disallowed.html",
+                                                            &test_ruleset_pair);
+  subresource_filter::testing::TestRulesetPublisher test_ruleset_publisher;
+  ASSERT_NO_FATAL_FAILURE(
+      test_ruleset_publisher.SetRuleset(test_ruleset_pair.unindexed));
+
+  // Set up the tab helpers.
+  InfoBarService::CreateForWebContents(web_contents());
+  TabSpecificContentSettings::CreateForWebContents(web_contents());
+  ChromeSubresourceFilterClient::CreateForWebContents(web_contents());
+
+  base::RunLoop().RunUntilIdle();
+}
+
+void SubresourceFilterTestHarness::TearDown() {
+  fake_safe_browsing_database_ = nullptr;
+  TestingBrowserProcess::GetGlobal()->safe_browsing_service()->ShutDown();
+
+  // Must explicitly set these to null and pump the run loop to ensure that
+  // all cleanup related to these classes actually happens.
+  TestingBrowserProcess::GetGlobal()->SetRulesetService(nullptr);
+  TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
+  base::RunLoop().RunUntilIdle();
+
+  ChromeRenderViewHostTestHarness::TearDown();
+}
+
+// Will return nullptr if the navigation fails.
+content::RenderFrameHost*
+SubresourceFilterTestHarness::SimulateNavigateAndCommit(
+    const GURL& url,
+    content::RenderFrameHost* rfh) {
+  auto simulator =
+      content::NavigationSimulator::CreateRendererInitiated(url, rfh);
+  simulator->Commit();
+  return simulator->GetLastThrottleCheckResult() ==
+                 content::NavigationThrottle::PROCEED
+             ? simulator->GetFinalRenderFrameHost()
+             : nullptr;
+}
+
+// Returns the frame host the navigation commit in, or nullptr if it did not
+// succeed.
+content::RenderFrameHost*
+SubresourceFilterTestHarness::CreateAndNavigateDisallowedSubframe(
+    content::RenderFrameHost* parent) {
+  auto* subframe =
+      content::RenderFrameHostTester::For(parent)->AppendChild("subframe");
+  return SimulateNavigateAndCommit(GURL(kDefaultDisallowedUrl), subframe);
+}
+
+void SubresourceFilterTestHarness::ConfigureAsSubresourceFilterOnlyURL(
+    const GURL& url) {
+  fake_safe_browsing_database_->AddBlacklistedUrl(
+      url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
+}
+
+ChromeSubresourceFilterClient* SubresourceFilterTestHarness::GetClient() {
+  return ChromeSubresourceFilterClient::FromWebContents(web_contents());
+}
+
+void SubresourceFilterTestHarness::RemoveURLFromBlacklist(const GURL& url) {
+  fake_safe_browsing_database_->RemoveBlacklistedUrl(url);
+}
+
+SubresourceFilterContentSettingsManager*
+SubresourceFilterTestHarness::GetSettingsManager() {
+  return SubresourceFilterProfileContextFactory::GetForProfile(
+             static_cast<Profile*>(profile()))
+      ->settings_manager();
+}
diff --git a/chrome/browser/subresource_filter/subresource_filter_test_harness.h b/chrome/browser/subresource_filter/subresource_filter_test_harness.h
new file mode 100644
index 0000000..110d0db
--- /dev/null
+++ b/chrome/browser/subresource_filter/subresource_filter_test_harness.h
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_TEST_HARNESS_H_
+#define CHROME_BROWSER_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_TEST_HARNESS_H_
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features.h"
+#include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
+
+class ChromeSubresourceFilterClient;
+class GURL;
+class SubresourceFilterContentSettingsManager;
+
+namespace content {
+class RenderFrameHost;
+}  // namespace content
+
+// End to end unit test harness of (most of) the browser process portions of the
+// subresource filtering code.
+class SubresourceFilterTestHarness : public ChromeRenderViewHostTestHarness {
+ public:
+  static constexpr char const kDefaultDisallowedUrl[] =
+      "https://example.test/disallowed.html";
+  SubresourceFilterTestHarness();
+  ~SubresourceFilterTestHarness() override;
+
+  // ChromeRenderViewHostTestHarness:
+  void SetUp() override;
+  void TearDown() override;
+
+  // Returns the frame host the navigation commit in, or nullptr if it did not
+  // succeed.
+  content::RenderFrameHost* SimulateNavigateAndCommit(
+      const GURL& url,
+      content::RenderFrameHost* rfh);
+
+  // Creates a subframe as a child of |parent|, and navigates it to a URL
+  // disallowed by the default ruleset (kDefaultDisallowedUrl). Returns the
+  // frame host the navigation commit in, or nullptr if it did not succeed.
+  content::RenderFrameHost* CreateAndNavigateDisallowedSubframe(
+      content::RenderFrameHost* parent);
+
+  void ConfigureAsSubresourceFilterOnlyURL(const GURL& url);
+
+  ChromeSubresourceFilterClient* GetClient();
+
+  void RemoveURLFromBlacklist(const GURL& url);
+
+  SubresourceFilterContentSettingsManager* GetSettingsManager();
+
+  subresource_filter::testing::ScopedSubresourceFilterConfigurator&
+  scoped_configuration() {
+    return scoped_configuration_;
+  }
+
+ private:
+  base::ScopedTempDir ruleset_service_dir_;
+  TestingPrefServiceSimple pref_service_;
+  subresource_filter::testing::ScopedSubresourceFilterFeatureToggle
+      scoped_feature_toggle_;
+  subresource_filter::testing::ScopedSubresourceFilterConfigurator
+      scoped_configuration_;
+
+  scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
+
+  DISALLOW_COPY_AND_ASSIGN(SubresourceFilterTestHarness);
+};
+
+#endif  // CHROME_BROWSER_SUBRESOURCE_FILTER_SUBRESOURCE_FILTER_TEST_HARNESS_H_
diff --git a/chrome/browser/subresource_filter/subresource_filter_unittest.cc b/chrome/browser/subresource_filter/subresource_filter_unittest.cc
index 4886201..0bfee7c 100644
--- a/chrome/browser/subresource_filter/subresource_filter_unittest.cc
+++ b/chrome/browser/subresource_filter/subresource_filter_unittest.cc
@@ -2,196 +2,28 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include <memory>
-#include <utility>
-
-#include "base/feature_list.h"
-#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/test/scoped_feature_list.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/after_startup_task_utils.h"
-#include "chrome/browser/content_settings/tab_specific_content_settings.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/safe_browsing/test_safe_browsing_service.h"
 #include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
 #include "chrome/browser/subresource_filter/subresource_filter_content_settings_manager.h"
-#include "chrome/browser/subresource_filter/subresource_filter_profile_context.h"
-#include "chrome/browser/subresource_filter/subresource_filter_profile_context_factory.h"
-#include "chrome/browser/subresource_filter/test_ruleset_publisher.h"
-#include "chrome/test/base/chrome_render_view_host_test_harness.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/safe_browsing_db/v4_protocol_manager_util.h"
-#include "components/subresource_filter/content/browser/content_ruleset_service.h"
+#include "chrome/browser/subresource_filter/subresource_filter_test_harness.h"
 #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h"
-#include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h"
 #include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
-#include "components/subresource_filter/core/browser/ruleset_service.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features.h"
 #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h"
 #include "components/subresource_filter/core/common/activation_decision.h"
-#include "components/subresource_filter/core/common/test_ruleset_creator.h"
-#include "content/public/browser/navigation_throttle.h"
-#include "content/public/test/navigation_simulator.h"
-#include "content/public/test/test_renderer_host.h"
+#include "components/subresource_filter/core/common/activation_level.h"
+#include "components/subresource_filter/core/common/activation_list.h"
+#include "components/subresource_filter/core/common/activation_scope.h"
+#include "components/subresource_filter/core/common/load_policy.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-namespace {
-using subresource_filter::testing::ScopedSubresourceFilterConfigurator;
-using subresource_filter::testing::ScopedSubresourceFilterFeatureToggle;
-const char kDisallowedUrl[] = "https://example.test/disallowed.html";
-}  // namespace
-
-// End to end unit test harness of (most of) the browser process portions of the
-// subresource filtering code.
-class SubresourceFilterTest : public ChromeRenderViewHostTestHarness {
- public:
-  SubresourceFilterTest() {}
-  ~SubresourceFilterTest() override {}
-
-  // ChromeRenderViewHostTestHarness:
-  void SetUp() override {
-    ChromeRenderViewHostTestHarness::SetUp();
-    AfterStartupTaskUtils::SetBrowserStartupIsCompleteForTesting();
-
-    // Ensure correct features.
-    scoped_feature_toggle_.ResetSubresourceFilterState(
-        base::FeatureList::OVERRIDE_ENABLE_FEATURE,
-        "SafeBrowsingV4OnlyEnabled,SubresourceFilterExperimentalUI");
-    scoped_configuration_.ResetConfiguration(subresource_filter::Configuration(
-        subresource_filter::ActivationLevel::ENABLED,
-        subresource_filter::ActivationScope::ACTIVATION_LIST,
-        subresource_filter::ActivationList::SUBRESOURCE_FILTER));
-
-    NavigateAndCommit(GURL("https://example.first"));
-
-    // Set up safe browsing service with the fake database manager.
-    //
-    // TODO(csharrison): This is a bit ugly. See if the instructions in
-    // test_safe_browsing_service.h can be adapted to be used in unit tests.
-    safe_browsing::TestSafeBrowsingServiceFactory sb_service_factory;
-    fake_safe_browsing_database_ = new FakeSafeBrowsingDatabaseManager();
-    sb_service_factory.SetTestDatabaseManager(
-        fake_safe_browsing_database_.get());
-    safe_browsing::SafeBrowsingService::RegisterFactory(&sb_service_factory);
-    auto* safe_browsing_service =
-        sb_service_factory.CreateSafeBrowsingService();
-    safe_browsing::SafeBrowsingService::RegisterFactory(nullptr);
-    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(
-        safe_browsing_service);
-    g_browser_process->safe_browsing_service()->Initialize();
-
-    // Set up the ruleset service.
-    ASSERT_TRUE(ruleset_service_dir_.CreateUniqueTempDir());
-    subresource_filter::IndexedRulesetVersion::RegisterPrefs(
-        pref_service_.registry());
-    auto content_service =
-        base::MakeUnique<subresource_filter::ContentRulesetService>(
-            base::ThreadTaskRunnerHandle::Get());
-    auto ruleset_service = base::MakeUnique<subresource_filter::RulesetService>(
-        &pref_service_, base::ThreadTaskRunnerHandle::Get(),
-        content_service.get(), ruleset_service_dir_.GetPath());
-    content_service->set_ruleset_service(std::move(ruleset_service));
-    TestingBrowserProcess::GetGlobal()->SetRulesetService(
-        std::move(content_service));
-
-    // Publish the test ruleset.
-    subresource_filter::testing::TestRulesetCreator ruleset_creator;
-    subresource_filter::testing::TestRulesetPair test_ruleset_pair;
-    ruleset_creator.CreateRulesetToDisallowURLsWithPathSuffix(
-        "disallowed.html", &test_ruleset_pair);
-    subresource_filter::testing::TestRulesetPublisher test_ruleset_publisher;
-    ASSERT_NO_FATAL_FAILURE(
-        test_ruleset_publisher.SetRuleset(test_ruleset_pair.unindexed));
-
-    // Set up the tab helpers.
-    InfoBarService::CreateForWebContents(web_contents());
-    TabSpecificContentSettings::CreateForWebContents(web_contents());
-    ChromeSubresourceFilterClient::CreateForWebContents(web_contents());
-
-    base::RunLoop().RunUntilIdle();
-  }
-
-  void TearDown() override {
-    fake_safe_browsing_database_ = nullptr;
-    TestingBrowserProcess::GetGlobal()->safe_browsing_service()->ShutDown();
-
-    // Must explicitly set these to null and pump the run loop to ensure that
-    // all cleanup related to these classes actually happens.
-    TestingBrowserProcess::GetGlobal()->SetRulesetService(nullptr);
-    TestingBrowserProcess::GetGlobal()->SetSafeBrowsingService(nullptr);
-    base::RunLoop().RunUntilIdle();
-
-    ChromeRenderViewHostTestHarness::TearDown();
-  }
-
-  // Will return nullptr if the navigation fails.
-  content::RenderFrameHost* SimulateNavigateAndCommit(
-      const GURL& url,
-      content::RenderFrameHost* rfh) {
-    auto simulator =
-        content::NavigationSimulator::CreateRendererInitiated(url, rfh);
-    simulator->Commit();
-    return simulator->GetLastThrottleCheckResult() ==
-                   content::NavigationThrottle::PROCEED
-               ? simulator->GetFinalRenderFrameHost()
-               : nullptr;
-  }
-
-  // Returns the frame host the navigation commit in, or nullptr if it did not
-  // succeed.
-  content::RenderFrameHost* CreateAndNavigateDisallowedSubframe(
-      content::RenderFrameHost* parent) {
-    auto* subframe =
-        content::RenderFrameHostTester::For(parent)->AppendChild("subframe");
-    return SimulateNavigateAndCommit(GURL(kDisallowedUrl), subframe);
-  }
-
-  void ConfigureAsSubresourceFilterOnlyURL(const GURL& url) {
-    fake_safe_browsing_database_->AddBlacklistedUrl(
-        url, safe_browsing::SB_THREAT_TYPE_SUBRESOURCE_FILTER);
-  }
-
-  ChromeSubresourceFilterClient* client() {
-    return ChromeSubresourceFilterClient::FromWebContents(web_contents());
-  }
-
-  void RemoveURLFromBlacklist(const GURL& url) {
-    fake_safe_browsing_database_->RemoveBlacklistedUrl(url);
-  }
-
-  SubresourceFilterContentSettingsManager* settings_manager() {
-    return SubresourceFilterProfileContextFactory::GetForProfile(
-               static_cast<Profile*>(profile()))
-        ->settings_manager();
-  }
-
-  ScopedSubresourceFilterConfigurator& scoped_configuration() {
-    return scoped_configuration_;
-  }
-
- private:
-  base::ScopedTempDir ruleset_service_dir_;
-  TestingPrefServiceSimple pref_service_;
-  ScopedSubresourceFilterFeatureToggle scoped_feature_toggle_;
-  ScopedSubresourceFilterConfigurator scoped_configuration_;
-
-  scoped_refptr<FakeSafeBrowsingDatabaseManager> fake_safe_browsing_database_;
-
-  DISALLOW_COPY_AND_ASSIGN(SubresourceFilterTest);
-};
+class SubresourceFilterTest : public SubresourceFilterTestHarness {};
 
 TEST_F(SubresourceFilterTest, SimpleAllowedLoad) {
   GURL url("https://example.test");
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_TRUE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-  EXPECT_FALSE(client()->did_show_ui_for_navigation());
+  EXPECT_FALSE(GetClient()->did_show_ui_for_navigation());
 }
 
 TEST_F(SubresourceFilterTest, SimpleDisallowedLoad) {
@@ -199,7 +31,7 @@
   ConfigureAsSubresourceFilterOnlyURL(url);
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-  EXPECT_TRUE(client()->did_show_ui_for_navigation());
+  EXPECT_TRUE(GetClient()->did_show_ui_for_navigation());
 }
 
 TEST_F(SubresourceFilterTest, DeactivateUrl_ClearsSiteMetadata) {
@@ -208,7 +40,7 @@
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
-  EXPECT_NE(nullptr, settings_manager()->GetSiteMetadata(url));
+  EXPECT_NE(nullptr, GetSettingsManager()->GetSiteMetadata(url));
 
   RemoveURLFromBlacklist(url);
 
@@ -216,7 +48,7 @@
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_TRUE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
-  EXPECT_EQ(nullptr, settings_manager()->GetSiteMetadata(url));
+  EXPECT_EQ(nullptr, GetSettingsManager()->GetSiteMetadata(url));
 }
 
 // If the underlying configuration changes and a site only activates to DRYRUN,
@@ -227,7 +59,7 @@
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
-  EXPECT_NE(nullptr, settings_manager()->GetSiteMetadata(url));
+  EXPECT_NE(nullptr, GetSettingsManager()->GetSiteMetadata(url));
 
   // If the site later activates as DRYRUN due to e.g. a configuration change,
   // it should also be removed from the metadata.
@@ -240,7 +72,7 @@
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_TRUE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
-  EXPECT_EQ(nullptr, settings_manager()->GetSiteMetadata(url));
+  EXPECT_EQ(nullptr, GetSettingsManager()->GetSiteMetadata(url));
 }
 
 TEST_F(SubresourceFilterTest, ExplicitWhitelisting_ShouldNotClearMetadata) {
@@ -250,13 +82,13 @@
   EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
   // Simulate explicit whitelisting and reload.
-  settings_manager()->WhitelistSite(url);
+  GetSettingsManager()->WhitelistSite(url);
   SimulateNavigateAndCommit(url, main_rfh());
   EXPECT_TRUE(CreateAndNavigateDisallowedSubframe(main_rfh()));
 
   // Should not have cleared the metadata, since the site is still on the SB
   // blacklist.
-  EXPECT_NE(nullptr, settings_manager()->GetSiteMetadata(url));
+  EXPECT_NE(nullptr, GetSettingsManager()->GetSiteMetadata(url));
 }
 
 TEST_F(SubresourceFilterTest,
@@ -308,10 +140,10 @@
   EXPECT_EQ(subresource_filter::ActivationDecision::ACTIVATED,
             observer.GetPageActivation(url).value());
 
+  GURL disallowed_url(SubresourceFilterTest::kDefaultDisallowedUrl);
   EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh()));
-  auto optional_load_policy =
-      observer.GetSubframeLoadPolicy(GURL(kDisallowedUrl));
+  auto optional_load_policy = observer.GetSubframeLoadPolicy(disallowed_url);
   EXPECT_TRUE(optional_load_policy.has_value());
   EXPECT_EQ(subresource_filter::LoadPolicy::DISALLOW,
-            observer.GetSubframeLoadPolicy(GURL(kDisallowedUrl)).value());
+            observer.GetSubframeLoadPolicy(disallowed_url).value());
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f12717b..b0103f3 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -507,6 +507,7 @@
     "//components/dom_distiller/content/browser",
     "//components/dom_distiller/webui",
     "//components/domain_reliability",
+    "//components/download/content/public",
     "//components/favicon/content",
     "//components/favicon/core",
     "//components/feedback",
diff --git a/chrome/browser/ui/cocoa/browser_window_layout.mm b/chrome/browser/ui/cocoa/browser_window_layout.mm
index 041f0f8f..fcf2da13 100644
--- a/chrome/browser/ui/cocoa/browser_window_layout.mm
+++ b/chrome/browser/ui/cocoa/browser_window_layout.mm
@@ -24,9 +24,10 @@
   // stopped the window buttons from being covered by the content view. This
   // may break in a future macOS release. NSFullSizeContentViewWindowMask is a
   // new (10.10+), supported way to make the content view the full size of the
-  // window without covering the controls.
+  // window without covering the controls. It's only enabled in 10.12+ due to a
+  // performance regression seen in 10.11 (https://crbug.com/742472).
   return base::FeatureList::IsEnabled(features::kMacFullSizeContentView) &&
-         base::mac::IsAtLeastOS10_11();
+         base::mac::IsAtLeastOS10_12();
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index 8bd5b218..5ca4247 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -56,8 +56,7 @@
 
 TabRendererData::NetworkState TabContentsNetworkState(
     WebContents* contents) {
-  if (!contents)
-    return TabRendererData::NETWORK_STATE_NONE;
+  DCHECK(contents);
 
   if (!contents->IsLoadingToDifferentDocument()) {
     content::NavigationEntry* entry =
@@ -500,7 +499,6 @@
   data->network_state = TabContentsNetworkState(contents);
   data->title = contents->GetTitle();
   data->url = contents->GetURL();
-  data->loading = contents->IsLoading();
   data->crashed_status = contents->GetCrashedStatus();
   data->incognito = contents->GetBrowserContext()->IsOffTheRecord();
   data->pinned = model_->IsTabPinned(model_index);
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 55766eac..f1b8614 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -540,9 +540,9 @@
 
   base::string16 title = data_.title;
   if (title.empty()) {
-    title = data_.loading ?
-        l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE) :
-        CoreTabHelper::GetDefaultTitle();
+    title = ShouldShowThrobber(data_.network_state)
+                ? l10n_util::GetStringUTF16(IDS_TAB_LOADING_TITLE)
+                : CoreTabHelper::GetDefaultTitle();
   } else {
     Browser::FormatTitleForDisplay(&title);
   }
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.cc b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
index 4f10179..030695c 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.cc
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.cc
@@ -9,7 +9,6 @@
 
 TabRendererData::TabRendererData()
     : network_state(NETWORK_STATE_NONE),
-      loading(false),
       crashed_status(base::TERMINATION_STATUS_STILL_RUNNING),
       incognito(false),
       show_icon(true),
@@ -39,7 +38,6 @@
       network_state == data.network_state &&
       title == data.title &&
       url == data.url &&
-      loading == data.loading &&
       crashed_status == data.crashed_status &&
       incognito == data.incognito &&
       show_icon == data.show_icon &&
diff --git a/chrome/browser/ui/views/tabs/tab_renderer_data.h b/chrome/browser/ui/views/tabs/tab_renderer_data.h
index 9b1d2ab..15ad5f6e 100644
--- a/chrome/browser/ui/views/tabs/tab_renderer_data.h
+++ b/chrome/browser/ui/views/tabs/tab_renderer_data.h
@@ -39,7 +39,6 @@
   NetworkState network_state;
   base::string16 title;
   GURL url;
-  bool loading;
   base::TerminationStatus crashed_status;
   bool incognito;
   bool show_icon;
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
index fe52433d..30cb212 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/all_download_item_notifier.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
@@ -354,7 +353,7 @@
       GetMainNotifierManager()->GetBrowserContext());
   if (profile->IsOffTheRecord()) {
     Profile* original_profile = profile->GetOriginalProfile();
-    original_notifier_.reset(new content::AllDownloadItemNotifier(
+    original_notifier_.reset(new download::AllDownloadItemNotifier(
         BrowserContext::GetDownloadManager(original_profile), this));
   }
 
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
index 8d99d185..b92245ac 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.h
@@ -15,7 +15,7 @@
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "base/values.h"
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "content/public/browser/download_item.h"
 
 namespace base {
@@ -30,7 +30,8 @@
 
 // A class that tracks all downloads activity and keeps a sorted representation
 // of the downloads as chrome://downloads wants to display them.
-class DownloadsListTracker : public content::AllDownloadItemNotifier::Observer {
+class DownloadsListTracker
+    : public download::AllDownloadItemNotifier::Observer {
  public:
   DownloadsListTracker(content::DownloadManager* download_manager,
                        content::WebUI* web_ui);
@@ -109,8 +110,8 @@
   // if sending updates.
   void RemoveItem(const SortedSet::iterator& remove);
 
-  content::AllDownloadItemNotifier main_notifier_;
-  std::unique_ptr<content::AllDownloadItemNotifier> original_notifier_;
+  download::AllDownloadItemNotifier main_notifier_;
+  std::unique_ptr<download::AllDownloadItemNotifier> original_notifier_;
 
   // The WebUI object corresponding to the page we care about.
   content::WebUI* const web_ui_;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index e833c10a..1874ff1 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -493,19 +493,6 @@
 // proxy connection, and the endpoint host in a SOCKS proxy connection).
 const char kHostRules[]                     = "host-rules";
 
-// A set of public key hashes for which to ignore certificate-related errors.
-//
-// If the certificate chain presented by the server does not validate, and one
-// or more certificates have public key hashes that match a key from this list,
-// the error is ignored.
-//
-// The switch value must a be a comma-separated list of Base64-encoded SHA-256
-// SPKI Fingerprints (RFC 7469, Section 2.4).
-//
-// This switch has no effect unless --user-data-dir is also present.
-const char kIgnoreCertificateErrorsSPKIList[] =
-    "ignore-certificate-errors-spki-list";
-
 // Causes net::URLFetchers to ignore requests for SSL client certificates,
 // causing them to attempt an unauthenticated SSL/TLS session. This is intended
 // for use when testing various service URLs (eg: kPromoServerURL, kSbURLPrefix,
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 25d3512..007fe78 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -148,7 +148,6 @@
 extern const char kForceLocalNtp[];
 extern const char kHomePage[];
 extern const char kHostRules[];
-extern const char kIgnoreCertificateErrorsSPKIList[];
 extern const char kIgnoreUrlFetcherCertRequests[];
 extern const char kIncognito[];
 extern const char kInstallChromeApp[];
diff --git a/chrome/installer/zucchini/BUILD.gn b/chrome/installer/zucchini/BUILD.gn
index 97ea2b42..b1fbd88 100644
--- a/chrome/installer/zucchini/BUILD.gn
+++ b/chrome/installer/zucchini/BUILD.gn
@@ -7,6 +7,10 @@
 
 static_library("zucchini_lib") {
   sources = [
+    "buffer_sink.cc",
+    "buffer_sink.h",
+    "buffer_source.cc",
+    "buffer_source.h",
     "buffer_view.h",
     "crc32.cc",
     "crc32.h",
@@ -51,6 +55,8 @@
 
 test("zucchini_unittests") {
   sources = [
+    "buffer_sink_unittest.cc",
+    "buffer_source_unittest.cc",
     "buffer_view_unittest.cc",
     "crc32_unittest.cc",
     "io_utils_unittest.cc",
diff --git a/chrome/installer/zucchini/buffer_sink.cc b/chrome/installer/zucchini/buffer_sink.cc
new file mode 100644
index 0000000..9c09af85
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_sink.cc
@@ -0,0 +1,11 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/buffer_sink.h"
+
+namespace zucchini {
+
+BufferSink::BufferSink(MutableBufferView buffer) : MutableBufferView(buffer) {}
+
+}  // namespace zucchini
diff --git a/chrome/installer/zucchini/buffer_sink.h b/chrome/installer/zucchini/buffer_sink.h
new file mode 100644
index 0000000..3e3be8e
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_sink.h
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_INSTALLER_ZUCCHINI_BUFFER_SINK_H_
+#define CHROME_INSTALLER_ZUCCHINI_BUFFER_SINK_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <iterator>
+
+#include "base/logging.h"
+#include "chrome/installer/zucchini/buffer_view.h"
+
+namespace zucchini {
+
+// BufferSink acts like an output stream with convenience methods to serialize
+// data into a contiguous sequence of raw data. The underlying MutableBufferView
+// emulates a cursor to track current write position, and guards against buffer
+// overrun. Where applicable, BufferSink should be passed by pointer to maintain
+// cursor progress across writes.
+class BufferSink : public MutableBufferView {
+ public:
+  using iterator = MutableBufferView::iterator;
+
+  using MutableBufferView::MutableBufferView;
+  BufferSink() = default;
+  explicit BufferSink(MutableBufferView buffer);
+  BufferSink(const BufferSink&) = default;
+
+  BufferSink& operator=(BufferSink&&) = default;
+
+  // If sufficient space is available, writes the binary representation of
+  // |value| starting at cursor, while advancing the cursor beyond the written
+  // region, and returns true. Otherwise returns false.
+  template <class T>
+  bool PutValue(const T& value) {
+    DCHECK_NE(begin(), nullptr);
+    if (Remaining() < sizeof(T))
+      return false;
+    *reinterpret_cast<T*>(begin()) = value;
+    remove_prefix(sizeof(T));
+    return true;
+  }
+
+  // If sufficient space is available, writes the raw bytes [|first|, |last|)
+  // starting at cursor, while advancing the cursor beyond the written region,
+  // and returns true. Otherwise returns false.
+  template <class It>
+  bool PutRange(It first, It last) {
+    static_assert(sizeof(typename std::iterator_traits<It>::value_type) ==
+                      sizeof(uint8_t),
+                  "value_type should fit in uint8_t");
+    DCHECK_NE(begin(), nullptr);
+    DCHECK(last >= first);
+    if (Remaining() < size_type(last - first))
+      return false;
+    std::copy(first, last, begin());
+    remove_prefix(last - first);
+    return true;
+  }
+
+  size_type Remaining() const { return size(); }
+};
+
+}  // namespace zucchini
+
+#endif  // CHROME_INSTALLER_ZUCCHINI_BUFFER_SINK_H_
diff --git a/chrome/installer/zucchini/buffer_sink_unittest.cc b/chrome/installer/zucchini/buffer_sink_unittest.cc
new file mode 100644
index 0000000..c371cd72
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_sink_unittest.cc
@@ -0,0 +1,71 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/buffer_sink.h"
+
+#include <vector>
+
+#include "base/test/gtest_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+constexpr uint8_t kUninit = 0xFF;
+
+class BufferSinkTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    buffer_ = std::vector<uint8_t>(10, kUninit);
+    sink_ = BufferSink(buffer_.data(), buffer_.size());
+  }
+
+  std::vector<uint8_t> buffer_;
+  BufferSink sink_;
+};
+
+TEST_F(BufferSinkTest, PutValue) {
+  EXPECT_EQ(size_t(10), sink_.Remaining());
+
+  EXPECT_TRUE(sink_.PutValue(uint32_t(0x76543210)));
+  EXPECT_EQ(size_t(6), sink_.Remaining());
+
+  EXPECT_TRUE(sink_.PutValue(uint32_t(0xFEDCBA98)));
+  EXPECT_EQ(size_t(2), sink_.Remaining());
+
+  EXPECT_FALSE(sink_.PutValue(uint32_t(0x00)));
+  EXPECT_EQ(size_t(2), sink_.Remaining());
+
+  EXPECT_TRUE(sink_.PutValue(uint16_t(0x0010)));
+  EXPECT_EQ(size_t(0), sink_.Remaining());
+
+  // Assuming little-endian architecture.
+  EXPECT_EQ(std::vector<uint8_t>(
+                {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, 0x10, 0x00}),
+            buffer_);
+}
+
+TEST_F(BufferSinkTest, PutRange) {
+  std::vector<uint8_t> range = {0x10, 0x32, 0x54, 0x76, 0x98, 0xBA,
+                                0xDC, 0xFE, 0x10, 0x00, 0x42};
+
+  EXPECT_EQ(size_t(10), sink_.Remaining());
+  EXPECT_FALSE(sink_.PutRange(range.begin(), range.end()));
+  EXPECT_EQ(size_t(10), sink_.Remaining());
+
+  EXPECT_TRUE(sink_.PutRange(range.begin(), range.begin() + 8));
+  EXPECT_EQ(size_t(2), sink_.Remaining());
+  EXPECT_EQ(std::vector<uint8_t>({0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC,
+                                  0xFE, kUninit, kUninit}),
+            buffer_);
+
+  EXPECT_FALSE(sink_.PutRange(range.begin(), range.begin() + 4));
+  EXPECT_EQ(size_t(2), sink_.Remaining());
+
+  // range is not written
+  EXPECT_EQ(std::vector<uint8_t>({0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC,
+                                  0xFE, kUninit, kUninit}),
+            buffer_);
+}
+
+}  // namespace zucchini
diff --git a/chrome/installer/zucchini/buffer_source.cc b/chrome/installer/zucchini/buffer_source.cc
new file mode 100644
index 0000000..b688dc4c
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_source.cc
@@ -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.
+
+#include "chrome/installer/zucchini/buffer_source.h"
+
+#include <algorithm>
+
+namespace zucchini {
+
+BufferSource::BufferSource(ConstBufferView buffer) : ConstBufferView(buffer) {}
+
+BufferSource& BufferSource::Skip(size_type n) {
+  remove_prefix(std::min(n, Remaining()));
+  return *this;
+}
+
+bool BufferSource::CheckNextBytes(std::initializer_list<uint8_t> bytes) const {
+  if (Remaining() < bytes.size())
+    return false;
+  return std::mismatch(bytes.begin(), bytes.end(), begin()).first ==
+         bytes.end();
+}
+
+bool BufferSource::ConsumeBytes(std::initializer_list<uint8_t> bytes) {
+  if (!CheckNextBytes(bytes))
+    return false;
+  remove_prefix(bytes.size());
+  return true;
+}
+
+bool BufferSource::GetRegion(size_type count, ConstBufferView* buffer) {
+  DCHECK_NE(begin(), nullptr);
+  if (Remaining() < count)
+    return false;
+  *buffer = ConstBufferView(begin(), count);
+  remove_prefix(count);
+  return true;
+}
+
+}  // namespace zucchini
diff --git a/chrome/installer/zucchini/buffer_source.h b/chrome/installer/zucchini/buffer_source.h
new file mode 100644
index 0000000..6dab416
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_source.h
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_INSTALLER_ZUCCHINI_BUFFER_SOURCE_H_
+#define CHROME_INSTALLER_ZUCCHINI_BUFFER_SOURCE_H_
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <initializer_list>
+#include <type_traits>
+
+#include "chrome/installer/zucchini/buffer_view.h"
+
+namespace zucchini {
+
+// BufferSource acts like an input stream with convenience methods to parse data
+// from a contiguous sequence of raw data. The underlying ConstBufferView
+// emulates a cursor to track current read position, and guards against buffer
+// overrun. Where applicable, BufferSource should be passed by pointer to
+// maintain cursor progress across reads.
+class BufferSource : public ConstBufferView {
+ public:
+  static BufferSource FromRange(const_iterator first, const_iterator last) {
+    return BufferSource(ConstBufferView::FromRange(first, last));
+  }
+
+  using ConstBufferView::ConstBufferView;
+  BufferSource() = default;
+  explicit BufferSource(ConstBufferView buffer);
+  BufferSource(const BufferSource&) = default;
+
+  BufferSource& operator=(BufferSource&&) = default;
+
+  // Moves cursor forward by |n| bytes, or until end if data is exhausted.
+  // Returns a reference to *this, to allow chaining, e.g.:
+  //   if (!buffer_source.Skip(1024).GetValue<uint32_t>(&value)) {
+  //      ... // Handle error.
+  //   }
+  // Notice that Skip() defers error handling to GetValue().
+  BufferSource& Skip(size_type n);
+
+  // Returns true if |value| matches data starting at cursor when reinterpreted
+  // as the integral type |T|.
+  template <class T>
+  bool CheckNextValue(const T& value) const {
+    static_assert(std::is_integral<T>::value,
+                  "Value type must be an integral type");
+
+    DCHECK_NE(begin(), nullptr);
+    if (Remaining() < sizeof(T))
+      return false;
+    return value == *reinterpret_cast<const T*>(begin());
+  }
+
+  // Returns true if the next bytes.size() bytes at the cursor match those in
+  // |bytes|.
+  bool CheckNextBytes(std::initializer_list<uint8_t> bytes) const;
+
+  // Same as CheckNextBytes(), but moves the cursor by bytes.size() if read is
+  // successfull.
+  bool ConsumeBytes(std::initializer_list<uint8_t> bytes);
+
+  // Tries to reinterpret data as type |T|, starting at cursor and to write the
+  // result into |value|, while moving the cursor forward by sizeof(T). Returns
+  // true if sufficient data is available, and false otherwise.
+  template <class T>
+  bool GetValue(T* value) {
+    static_assert(std::is_standard_layout<T>::value,
+                  "Value type must be a standard layout type");
+
+    DCHECK_NE(begin(), nullptr);
+    if (Remaining() < sizeof(T))
+      return false;
+    *value = *reinterpret_cast<const T*>(begin());
+    remove_prefix(sizeof(T));
+    return true;
+  }
+
+  // Tries to reinterpret data as type |T| at cursor and to return a
+  // reinterpreted pointer of type |T| pointing into the underlying data, while
+  // moving the cursor forward by sizeof(T). Returns nullptr if insufficient
+  // data is available.
+  template <class T>
+  const T* GetPointer() {
+    static_assert(std::is_standard_layout<T>::value,
+                  "Value type must be a standard layout type");
+
+    DCHECK_NE(begin(), nullptr);
+    if (Remaining() < sizeof(T))
+      return nullptr;
+    const T* ptr = reinterpret_cast<const T*>(begin());
+    remove_prefix(sizeof(T));
+    return ptr;
+  }
+
+  // Tries to reinterpret data as an array of type |T| with |count| elements,
+  // starting at cursor, and to return a reinterpreted pointer of type |T|
+  // pointing into the underlying data, while advancing the cursor beyond the
+  // array. Returns nullptr if insufficient data is available.
+  template <class T>
+  const T* GetArray(size_t count) {
+    static_assert(std::is_standard_layout<T>::value,
+                  "Value type must be a standard layout type");
+
+    if (Remaining() / sizeof(T) < count)
+      return nullptr;
+    const T* array = reinterpret_cast<const T*>(begin());
+    remove_prefix(count * sizeof(T));
+    return array;
+  }
+
+  // If sufficient data is available, assigns |buffer| to point to a region of
+  // |size| bytes starting at cursor, while advancing the cursor beyond the
+  // region, and returns true. Otherwise returns false.
+  bool GetRegion(size_type size, ConstBufferView* buffer);
+
+  // Returns the number of bytes remaining from cursor until end.
+  size_type Remaining() const { return size(); }
+};
+
+}  // namespace zucchini
+
+#endif  // CHROME_INSTALLER_ZUCCHINI_BUFFER_SOURCE_H_
diff --git a/chrome/installer/zucchini/buffer_source_unittest.cc b/chrome/installer/zucchini/buffer_source_unittest.cc
new file mode 100644
index 0000000..edc04de5
--- /dev/null
+++ b/chrome/installer/zucchini/buffer_source_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/installer/zucchini/buffer_source.h"
+
+#include <cstdint>
+#include <iterator>
+#include <vector>
+
+#include "base/test/gtest_util.h"
+
+namespace zucchini {
+
+using vec = std::vector<uint8_t>;
+
+static constexpr size_t kLen = 10;
+constexpr const uint8_t bytes[kLen] = {0x10, 0x32, 0x54, 0x76, 0x98,
+                                       0xBA, 0xDC, 0xFE, 0x10, 0x00};
+
+class BufferSourceTest : public testing::Test {
+ protected:
+  BufferSource source_ = {std::begin(bytes), kLen};
+};
+
+TEST_F(BufferSourceTest, Skip) {
+  EXPECT_EQ(kLen, source_.Remaining());
+  source_.Skip(2);
+  EXPECT_EQ(kLen - 2, source_.Remaining());
+  source_.Skip(10);  // Skipping past end just moves cursor to end.
+  EXPECT_EQ(size_t(0), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, CheckNextBytes) {
+  EXPECT_TRUE(source_.CheckNextBytes({0x10, 0x32, 0x54, 0x76}));
+  source_.Skip(4);
+  EXPECT_TRUE(source_.CheckNextBytes({0x98, 0xBA, 0xDC, 0xFE}));
+
+  // Cursor has not advanced, so check fails.
+  EXPECT_FALSE(source_.CheckNextBytes({0x10, 0x00}));
+
+  source_.Skip(4);
+  EXPECT_EQ(size_t(2), source_.Remaining());
+
+  // Goes beyond end by 2 bytes.
+  EXPECT_FALSE(source_.CheckNextBytes({0x10, 0x00, 0x00, 0x00}));
+  EXPECT_EQ(size_t(2), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, ConsumeBytes) {
+  EXPECT_FALSE(source_.ConsumeBytes({0x10, 0x00}));
+  EXPECT_EQ(kLen, source_.Remaining());
+  EXPECT_TRUE(source_.ConsumeBytes({0x10, 0x32, 0x54, 0x76}));
+  EXPECT_EQ(size_t(6), source_.Remaining());
+  EXPECT_TRUE(source_.ConsumeBytes({0x98, 0xBA, 0xDC, 0xFE}));
+  EXPECT_EQ(size_t(2), source_.Remaining());
+
+  // Goes beyond end by 2 bytes.
+  EXPECT_FALSE(source_.ConsumeBytes({0x10, 0x00, 0x00, 0x00}));
+  EXPECT_EQ(size_t(2), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, CheckNextValue) {
+  EXPECT_TRUE(source_.CheckNextValue(uint32_t(0x76543210)));
+  EXPECT_FALSE(source_.CheckNextValue(uint32_t(0x0)));
+  EXPECT_TRUE(source_.CheckNextValue(uint64_t(0xFEDCBA9876543210)));
+  EXPECT_FALSE(source_.CheckNextValue(uint64_t(0x0)));
+
+  source_.Skip(8);
+  EXPECT_EQ(size_t(2), source_.Remaining());
+
+  // Goes beyond end by 2 bytes.
+  EXPECT_FALSE(source_.CheckNextValue(uint32_t(0x1000)));
+}
+
+// Supported by MSVC, g++, and clang++.
+// Ensures no gaps in packing.
+#pragma pack(push, 1)
+struct ValueType {
+  uint32_t a;
+  uint16_t b;
+};
+#pragma pack(pop)
+
+TEST_F(BufferSourceTest, GetValueIntegral) {
+  uint32_t value = 0;
+  EXPECT_TRUE(source_.GetValue(&value));
+  EXPECT_EQ(uint32_t(0x76543210), value);
+  EXPECT_EQ(size_t(6), source_.Remaining());
+
+  EXPECT_TRUE(source_.GetValue(&value));
+  EXPECT_EQ(uint32_t(0xFEDCBA98), value);
+  EXPECT_EQ(size_t(2), source_.Remaining());
+
+  EXPECT_FALSE(source_.GetValue(&value));
+  EXPECT_EQ(size_t(2), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, GetValueAggregate) {
+  ValueType value = {};
+  EXPECT_TRUE(source_.GetValue(&value));
+  EXPECT_EQ(uint32_t(0x76543210), value.a);
+  EXPECT_EQ(uint32_t(0xBA98), value.b);
+  EXPECT_EQ(size_t(4), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, GetRegion) {
+  ConstBufferView region;
+  EXPECT_TRUE(source_.GetRegion(0, &region));
+  EXPECT_EQ(kLen, source_.Remaining());
+  EXPECT_TRUE(region.empty());
+
+  EXPECT_TRUE(source_.GetRegion(2, &region));
+  EXPECT_EQ(size_t(2), region.size());
+  EXPECT_EQ(vec({0x10, 0x32}), vec(region.begin(), region.end()));
+  EXPECT_EQ(size_t(8), source_.Remaining());
+
+  EXPECT_FALSE(source_.GetRegion(kLen, &region));
+  EXPECT_EQ(size_t(8), source_.Remaining());
+  // |region| is left untouched.
+  EXPECT_EQ(vec({0x10, 0x32}), vec(region.begin(), region.end()));
+  EXPECT_EQ(size_t(2), region.size());
+}
+
+TEST_F(BufferSourceTest, GetPointerIntegral) {
+  const uint32_t* ptr = source_.GetPointer<uint32_t>();
+  EXPECT_NE(nullptr, ptr);
+  EXPECT_EQ(uint32_t(0x76543210), *ptr);
+  EXPECT_EQ(size_t(6), source_.Remaining());
+
+  ptr = source_.GetPointer<uint32_t>();
+  EXPECT_NE(nullptr, ptr);
+  EXPECT_EQ(uint32_t(0xFEDCBA98), *ptr);
+  EXPECT_EQ(size_t(2), source_.Remaining());
+
+  EXPECT_EQ(nullptr, source_.GetPointer<uint32_t>());
+  EXPECT_EQ(size_t(2), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, GetPointerAggregate) {
+  const ValueType* ptr = source_.GetPointer<ValueType>();
+  EXPECT_NE(nullptr, ptr);
+  EXPECT_EQ(uint32_t(0x76543210), ptr->a);
+  EXPECT_EQ(uint32_t(0xBA98), ptr->b);
+  EXPECT_EQ(size_t(4), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, GetArrayIntegral) {
+  EXPECT_EQ(nullptr, source_.GetArray<uint32_t>(3));
+
+  const uint32_t* ptr = source_.GetArray<uint32_t>(2);
+  EXPECT_NE(nullptr, ptr);
+  EXPECT_EQ(uint32_t(0x76543210), ptr[0]);
+  EXPECT_EQ(uint32_t(0xFEDCBA98), ptr[1]);
+  EXPECT_EQ(size_t(2), source_.Remaining());
+}
+
+TEST_F(BufferSourceTest, GetArrayAggregate) {
+  const ValueType* ptr = source_.GetArray<ValueType>(2);
+  EXPECT_EQ(nullptr, ptr);
+
+  ptr = source_.GetArray<ValueType>(1);
+
+  EXPECT_NE(nullptr, ptr);
+  EXPECT_EQ(uint32_t(0x76543210), ptr[0].a);
+  EXPECT_EQ(uint32_t(0xBA98), ptr[0].b);
+  EXPECT_EQ(size_t(4), source_.Remaining());
+}
+
+}  // namespace zucchini
diff --git a/chrome/installer/zucchini/buffer_view.h b/chrome/installer/zucchini/buffer_view.h
index cf13fc48..8ac43ed6 100644
--- a/chrome/installer/zucchini/buffer_view.h
+++ b/chrome/installer/zucchini/buffer_view.h
@@ -28,7 +28,7 @@
   using difference_type = std::ptrdiff_t;
 
   static BufferViewBase FromRange(iterator first, iterator last) {
-    DCHECK(last >= first);
+    DCHECK_GE(last, first);
     BufferViewBase ret;
     ret.first_ = first;
     ret.last_ = last;
@@ -39,7 +39,7 @@
 
   BufferViewBase(iterator first, size_type size)
       : first_(first), last_(first_ + size) {
-    DCHECK(last_ >= first_);
+    DCHECK_GE(last_, first_);
   }
 
   BufferViewBase(const BufferViewBase&) = default;
@@ -57,7 +57,7 @@
   // Returns the raw value at specified location |pos|.
   // If |pos| is not within the range of the buffer, the process is terminated.
   reference operator[](size_type pos) const {
-    CHECK(first_ + pos < last_);
+    CHECK_LT(first_ + pos, last_);
     return first_[pos];
   }
 
@@ -69,10 +69,16 @@
   // Modifiers
 
   void shrink(size_type new_size) {
-    DCHECK(first_ + new_size <= last_);
+    DCHECK_LE(first_ + new_size, last_);
     last_ = first_ + new_size;
   }
 
+  // Moves the start of the view forward by n bytes.
+  void remove_prefix(size_type n) {
+    DCHECK_LE(n, size());
+    first_ += n;
+  }
+
  private:
   iterator first_ = nullptr;
   iterator last_ = nullptr;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index cf44149..fc3e011 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3309,7 +3309,6 @@
     "../browser/signin/test_signin_client_builder.cc",
     "../browser/signin/test_signin_client_builder.h",
     "../browser/ssl/chrome_expect_ct_reporter_unittest.cc",
-    "../browser/ssl/ignore_errors_cert_verifier_unittest.cc",
     "../browser/ssl/security_state_tab_helper_unittest.cc",
     "../browser/ssl/ssl_error_handler_unittest.cc",
     "../browser/status_icons/status_icon_menu_model_unittest.cc",
@@ -3317,6 +3316,8 @@
     "../browser/status_icons/status_tray_unittest.cc",
     "../browser/storage/durable_storage_permission_context_unittest.cc",
     "../browser/subresource_filter/subresource_filter_content_settings_manager_unittest.cc",
+    "../browser/subresource_filter/subresource_filter_test_harness.cc",
+    "../browser/subresource_filter/subresource_filter_test_harness.h",
     "../browser/subresource_filter/subresource_filter_unittest.cc",
     "../browser/subresource_filter/test_ruleset_publisher.cc",
     "../browser/subresource_filter/test_ruleset_publisher.h",
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout.js b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout.js
index f8949ffd..2ec299d 100644
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout.js
+++ b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout.js
@@ -18,7 +18,9 @@
         chrome.test.assertEq(channel.keepAlive, true);
         if (channel.readyState == 'closed' &&
             error.errorState == 'ping_timeout') {
-          chrome.test.sendMessage('timeout_ssl');
+          chrome.cast.channel.close(channel, () => {
+            chrome.test.sendMessage('timeout_ssl');
+          });
         }
       });
   chrome.test.notifyPass();
diff --git a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout_verified.js b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout_verified.js
index 52b6a4d..f667b61c 100644
--- a/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout_verified.js
+++ b/chrome/test/data/extensions/api_test/cast_channel/api/test_open_timeout_verified.js
@@ -17,7 +17,9 @@
         chrome.test.assertEq(channel.keepAlive, true);
         if (channel.readyState == 'closed' &&
             error.errorState == 'ping_timeout') {
-          chrome.test.sendMessage('timeout_ssl_verified');
+          chrome.cast.channel.close(channel, () => {
+            chrome.test.sendMessage('timeout_ssl_verified');
+          });
         }
       });
   chrome.test.notifyPass();
diff --git a/chrome/test/media_router/media_router_integration_ui_browsertest.cc b/chrome/test/media_router/media_router_integration_ui_browsertest.cc
index 3cd9737..ecf58df 100644
--- a/chrome/test/media_router/media_router_integration_ui_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_ui_browsertest.cc
@@ -46,9 +46,8 @@
   // closing after the route has been created. Then, check that the dialog
   // remains open.
   std::string mouse_enter_script = base::StringPrintf(
-      "domAutomationController.send("
-      "window.document.getElementById('media-router-container').dispatchEvent("
-      "new Event('mouseenter')))");
+      "window.document.getElementById('media-router-container')"
+      "    .dispatchEvent(new Event('mouseenter'));");
   ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_enter_script));
 #endif
   WaitUntilRouteCreated();
@@ -121,9 +120,8 @@
   // the timer started when the route is initially closed times out before the
   // mouseleave event is dispatched. In that case, the dialog remains open.
   std::string mouse_leave_script = base::StringPrintf(
-      "domAutomationController.send("
-      "window.document.getElementById('media-router-container').dispatchEvent("
-      "new Event('mouseleave')))");
+      "window.document.getElementById('media-router-container')"
+      "    .dispatchEvent(new Event('mouseleave'));");
   ASSERT_TRUE(content::ExecuteScript(dialog_contents, mouse_leave_script));
 #endif
   LOG(INFO) << "Closing route on UI";
diff --git a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
index 82ae9da..93e270e 100644
--- a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
+++ b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
@@ -41,7 +41,7 @@
 class TraceEventCastBenckmark(_BaseCastBenchmark):
   """Benchmark for dialog latency from trace event."""
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     media_router_category = 'media_router'
     category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
         media_router_category)
diff --git a/chrome/utility/printing_handler.cc b/chrome/utility/printing_handler.cc
index 83366b9a..42b343c4 100644
--- a/chrome/utility/printing_handler.cc
+++ b/chrome/utility/printing_handler.cc
@@ -91,18 +91,22 @@
   pdf_rendering_settings_ = settings;
   chrome_pdf::SetPDFUseGDIPrinting(pdf_rendering_settings_.mode ==
                                    PdfRenderSettings::Mode::GDI_TEXT);
-  int postscript_level;
+  int printing_mode;
   switch (pdf_rendering_settings_.mode) {
+    case PdfRenderSettings::Mode::TEXTONLY:
+      printing_mode = chrome_pdf::PrintingMode::kTextOnly;
+      break;
     case PdfRenderSettings::Mode::POSTSCRIPT_LEVEL2:
-      postscript_level = 2;
+      printing_mode = chrome_pdf::PrintingMode::kPostScript2;
       break;
     case PdfRenderSettings::Mode::POSTSCRIPT_LEVEL3:
-      postscript_level = 3;
+      printing_mode = chrome_pdf::PrintingMode::kPostScript3;
       break;
     default:
-      postscript_level = 0;  // Not using postscript.
+      // Not using postscript or text only.
+      printing_mode = chrome_pdf::PrintingMode::kEmf;
   }
-  chrome_pdf::SetPDFPostscriptPrintingLevel(postscript_level);
+  chrome_pdf::SetPDFUsePrintMode(printing_mode);
 
   base::File pdf_file = IPC::PlatformFileForTransitToFile(pdf_transit);
   int page_count = LoadPDF(std::move(pdf_file));
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 555611ca..f1a4b9b9 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -174,6 +174,8 @@
       "//media/mojo/services",
     ]
   }
+
+  configs += [ "//media/audio:platform_config" ]
 }
 
 # This target generates an "overlay" interface spec, allowing the Cast build to
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index 7846871..bade8515 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -82,6 +82,10 @@
 #include "chromecast/media/cdm/cast_cdm_factory.h"
 #endif  // BUILDFLAG(IS_CAST_USING_CMA_BACKEND)
 
+#if defined(USE_ALSA)
+#include "chromecast/media/audio/cast_audio_manager_alsa.h"  // nogncheck
+#endif  // defined(USE_ALSA)
+
 namespace chromecast {
 namespace shell {
 
@@ -202,11 +206,19 @@
   // because we already have a mixer in the audio pipeline downstream of
   // CastAudioManager.
   bool use_mixer = true;
+#if defined(USE_ALSA)
+  return base::MakeUnique<media::CastAudioManagerAlsa>(
+      base::MakeUnique<::media::AudioThreadImpl>(), audio_log_factory,
+      base::MakeUnique<media::MediaPipelineBackendFactoryImpl>(
+          media_pipeline_backend_manager()),
+      GetMediaTaskRunner(), use_mixer);
+#else
   return base::MakeUnique<media::CastAudioManager>(
       base::MakeUnique<::media::AudioThreadImpl>(), audio_log_factory,
       base::MakeUnique<media::MediaPipelineBackendFactoryImpl>(
           media_pipeline_backend_manager()),
       GetMediaTaskRunner(), use_mixer);
+#endif  // defined(USE_ALSA)
 }
 
 std::unique_ptr<::media::CdmFactory>
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn
index 896700bdd..6711bd1 100644
--- a/chromecast/media/BUILD.gn
+++ b/chromecast/media/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//chromecast/chromecast.gni")
+import("//media/media_options.gni")
 import("//testing/test.gni")
 
 group("media") {
@@ -24,6 +25,10 @@
     "test/run_all_unittests.cc",
   ]
 
+  if (use_alsa && !is_cast_desktop_build) {
+    sources += [ "audio/cast_audio_manager_alsa_unittest.cc" ]
+  }
+
   deps = [
     ":media",
     "//base",
diff --git a/chromecast/media/audio/BUILD.gn b/chromecast/media/audio/BUILD.gn
index cfead8c..fb07a2b7 100644
--- a/chromecast/media/audio/BUILD.gn
+++ b/chromecast/media/audio/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//media/media_options.gni")
+
 source_set("audio") {
   sources = [
     "cast_audio_manager.cc",
@@ -12,6 +14,13 @@
     "cast_audio_output_stream.h",
   ]
 
+  if (use_alsa) {
+    sources += [
+      "cast_audio_manager_alsa.cc",
+      "cast_audio_manager_alsa.h",
+    ]
+  }
+
   deps = [
     "//base",
     "//chromecast/base",
@@ -22,4 +31,6 @@
     "//media",
     "//media:shared_memory_support",
   ]
+
+  configs += [ "//media/audio:platform_config" ]
 }
diff --git a/chromecast/media/audio/cast_audio_manager.cc b/chromecast/media/audio/cast_audio_manager.cc
index 3cd80d6f..7627bfb 100644
--- a/chromecast/media/audio/cast_audio_manager.cc
+++ b/chromecast/media/audio/cast_audio_manager.cc
@@ -24,6 +24,10 @@
 static const int kMinimumOutputBufferSize = 512;
 static const int kMaximumOutputBufferSize = 8192;
 static const int kDefaultOutputBufferSize = 2048;
+
+// TODO(jyw): Query the preferred value from media backend.
+static const int kDefaultInputBufferSize = 1024;
+
 }  // namespace
 
 namespace chromecast {
@@ -65,10 +69,11 @@
 ::media::AudioParameters CastAudioManager::GetInputStreamParameters(
     const std::string& device_id) {
   LOG(WARNING) << "No support for input audio devices";
-  // Need to send a valid AudioParameters object even when it will unused.
+  // Need to send a valid AudioParameters object even when it will be unused.
   return ::media::AudioParameters(
       ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
-      ::media::CHANNEL_LAYOUT_STEREO, 48000, 16, 1024);
+      ::media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate, 16,
+      kDefaultInputBufferSize);
 }
 
 const char* CastAudioManager::GetName() {
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.cc b/chromecast/media/audio/cast_audio_manager_alsa.cc
new file mode 100644
index 0000000..fa1bd58
--- /dev/null
+++ b/chromecast/media/audio/cast_audio_manager_alsa.cc
@@ -0,0 +1,213 @@
+// 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 "chromecast/media/audio/cast_audio_manager_alsa.h"
+
+#include <string>
+
+#include "base/memory/free_deleter.h"
+#include "chromecast/media/cma/backend/media_pipeline_backend_factory.h"
+#include "media/audio/alsa/alsa_input.h"
+#include "media/audio/alsa/alsa_wrapper.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+// TODO(alokp): Query the preferred value from media backend.
+const int kDefaultSampleRate = 48000;
+
+// TODO(jyw): Query the preferred value from media backend.
+static const int kDefaultInputBufferSize = 1024;
+
+// Since "default" and "dmix" devices are virtual devices mapped to real
+// devices, we remove them from the list to avoiding duplicate counting.
+static const char* kInvalidAudioInputDevices[] = {
+    "default", "dmix", "null",
+};
+
+}  // namespace
+
+CastAudioManagerAlsa::CastAudioManagerAlsa(
+    std::unique_ptr<::media::AudioThread> audio_thread,
+    ::media::AudioLogFactory* audio_log_factory,
+    std::unique_ptr<MediaPipelineBackendFactory> backend_factory,
+    scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner,
+    bool use_mixer)
+    : CastAudioManager(std::move(audio_thread),
+                       audio_log_factory,
+                       std::move(backend_factory),
+                       backend_task_runner,
+                       use_mixer),
+      wrapper_(new ::media::AlsaWrapper()) {}
+
+CastAudioManagerAlsa::~CastAudioManagerAlsa() {}
+
+bool CastAudioManagerAlsa::HasAudioInputDevices() {
+  return true;
+}
+
+void CastAudioManagerAlsa::ShowAudioInputSettings() {
+  LOG(WARNING) << "No support for input audio devices";
+}
+
+void CastAudioManagerAlsa::GetAudioInputDeviceNames(
+    ::media::AudioDeviceNames* device_names) {
+  DCHECK(device_names->empty());
+  GetAlsaAudioDevices(kStreamCapture, device_names);
+}
+
+::media::AudioParameters CastAudioManagerAlsa::GetInputStreamParameters(
+    const std::string& device_id) {
+  // TODO(jyw): Be smarter about sample rate instead of hardcoding it.
+  // Need to send a valid AudioParameters object even when it will be unused.
+  return ::media::AudioParameters(
+      ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+      ::media::CHANNEL_LAYOUT_STEREO, kDefaultSampleRate, 16,
+      kDefaultInputBufferSize);
+}
+
+::media::AudioInputStream* CastAudioManagerAlsa::MakeLinearInputStream(
+    const ::media::AudioParameters& params,
+    const std::string& device_id,
+    const ::media::AudioManager::LogCallback& log_callback) {
+  DCHECK_EQ(::media::AudioParameters::AUDIO_PCM_LINEAR, params.format());
+  return MakeInputStream(params, device_id);
+}
+
+::media::AudioInputStream* CastAudioManagerAlsa::MakeLowLatencyInputStream(
+    const ::media::AudioParameters& params,
+    const std::string& device_id,
+    const ::media::AudioManager::LogCallback& log_callback) {
+  DCHECK_EQ(::media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
+  return MakeInputStream(params, device_id);
+}
+
+::media::AudioInputStream* CastAudioManagerAlsa::MakeInputStream(
+    const ::media::AudioParameters& params,
+    const std::string& device_id) {
+  std::string device_name =
+      (device_id == ::media::AudioDeviceDescription::kDefaultDeviceId)
+          ? ::media::AlsaPcmInputStream::kAutoSelectDevice
+          : device_id;
+  return new ::media::AlsaPcmInputStream(this, device_name, params,
+                                         wrapper_.get());
+}
+
+void CastAudioManagerAlsa::GetAlsaAudioDevices(
+    StreamType type,
+    ::media::AudioDeviceNames* device_names) {
+  // Constants specified by the ALSA API for device hints.
+  static const char kPcmInterfaceName[] = "pcm";
+  int card = -1;
+
+  // Loop through the sound cards to get ALSA device hints.
+  while (!wrapper_->CardNext(&card) && card >= 0) {
+    void** hints = NULL;
+    int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
+    if (!error) {
+      GetAlsaDevicesInfo(type, hints, device_names);
+
+      // Destroy the hints now that we're done with it.
+      wrapper_->DeviceNameFreeHint(hints);
+    } else {
+      DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: "
+                    << wrapper_->StrError(error);
+    }
+  }
+}
+
+void CastAudioManagerAlsa::GetAlsaDevicesInfo(
+    StreamType type,
+    void** hints,
+    ::media::AudioDeviceNames* device_names) {
+  static const char kIoHintName[] = "IOID";
+  static const char kNameHintName[] = "NAME";
+  static const char kDescriptionHintName[] = "DESC";
+
+  const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type);
+
+  for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
+    // Only examine devices of the right type.  Valid values are
+    // "Input", "Output", and NULL which means both input and output.
+    std::unique_ptr<char, base::FreeDeleter> io(
+        wrapper_->DeviceNameGetHint(*hint_iter, kIoHintName));
+    if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0)
+      continue;
+
+    // Found a device, prepend the default device since we always want
+    // it to be on the top of the list for all platforms. And there is
+    // no duplicate counting here since it is only done if the list is
+    // still empty.  Note, pulse has exclusively opened the default
+    // device, so we must open the device via the "default" moniker.
+    if (device_names->empty())
+      device_names->push_front(::media::AudioDeviceName::CreateDefault());
+
+    // Get the unique device name for the device.
+    std::unique_ptr<char, base::FreeDeleter> unique_device_name(
+        wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
+
+    // Find out if the device is available.
+    if (IsAlsaDeviceAvailable(type, unique_device_name.get())) {
+      // Get the description for the device.
+      std::unique_ptr<char, base::FreeDeleter> desc(
+          wrapper_->DeviceNameGetHint(*hint_iter, kDescriptionHintName));
+
+      ::media::AudioDeviceName name;
+      name.unique_id = unique_device_name.get();
+      if (desc) {
+        // Use the more user friendly description as name.
+        // Replace '\n' with '-'.
+        char* pret = strchr(desc.get(), '\n');
+        if (pret)
+          *pret = '-';
+        name.device_name = desc.get();
+      } else {
+        // Virtual devices don't necessarily have descriptions.
+        // Use their names instead.
+        name.device_name = unique_device_name.get();
+      }
+
+      // Store the device information.
+      device_names->push_back(name);
+    }
+  }
+}
+
+// static
+bool CastAudioManagerAlsa::IsAlsaDeviceAvailable(StreamType type,
+                                                 const char* device_name) {
+  if (!device_name)
+    return false;
+
+  // We do prefix matches on the device name to see whether to include
+  // it or not.
+  if (type == kStreamCapture) {
+    // Check if the device is in the list of invalid devices.
+    for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
+      if (strncmp(kInvalidAudioInputDevices[i], device_name,
+                  strlen(kInvalidAudioInputDevices[i])) == 0)
+        return false;
+    }
+    return true;
+  } else {
+    DCHECK_EQ(kStreamPlayback, type);
+    // We prefer the device type that maps straight to hardware but
+    // goes through software conversion if needed (e.g. incompatible
+    // sample rate).
+    // TODO(joi): Should we prefer "hw" instead?
+    static const char kDeviceTypeDesired[] = "plughw";
+    return strncmp(kDeviceTypeDesired, device_name,
+                   arraysize(kDeviceTypeDesired) - 1) == 0;
+  }
+}
+
+// static
+const char* CastAudioManagerAlsa::UnwantedDeviceTypeWhenEnumerating(
+    StreamType wanted_type) {
+  return wanted_type == kStreamPlayback ? "Input" : "Output";
+}
+
+}  // namespace media
+}  // namespace chromecast
diff --git a/chromecast/media/audio/cast_audio_manager_alsa.h b/chromecast/media/audio/cast_audio_manager_alsa.h
new file mode 100644
index 0000000..e0d8522e
--- /dev/null
+++ b/chromecast/media/audio/cast_audio_manager_alsa.h
@@ -0,0 +1,82 @@
+// 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 CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_MANAGER_ALSA_H_
+#define CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_MANAGER_ALSA_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "chromecast/media/audio/cast_audio_manager.h"
+
+namespace media {
+class AlsaWrapper;
+}
+
+namespace chromecast {
+
+namespace media {
+
+class CastAudioManagerAlsa : public CastAudioManager {
+ public:
+  CastAudioManagerAlsa(
+      std::unique_ptr<::media::AudioThread> audio_thread,
+      ::media::AudioLogFactory* audio_log_factory,
+      std::unique_ptr<MediaPipelineBackendFactory> backend_factory,
+      scoped_refptr<base::SingleThreadTaskRunner> backend_task_runner,
+      bool use_mixer);
+  ~CastAudioManagerAlsa() override;
+
+  // CastAudioManager implementation.
+  bool HasAudioInputDevices() override;
+  void ShowAudioInputSettings() override;
+  void GetAudioInputDeviceNames(
+      ::media::AudioDeviceNames* device_names) override;
+  ::media::AudioParameters GetInputStreamParameters(
+      const std::string& device_id) override;
+
+ private:
+  enum StreamType {
+    kStreamPlayback = 0,
+    kStreamCapture,
+  };
+
+  // CastAudioManager implementation.
+  ::media::AudioInputStream* MakeLinearInputStream(
+      const ::media::AudioParameters& params,
+      const std::string& device_id,
+      const ::media::AudioManager::LogCallback& log_callback) override;
+  ::media::AudioInputStream* MakeLowLatencyInputStream(
+      const ::media::AudioParameters& params,
+      const std::string& device_id,
+      const ::media::AudioManager::LogCallback& log_callback) override;
+
+  ::media::AudioInputStream* MakeInputStream(
+      const ::media::AudioParameters& params,
+      const std::string& device_id);
+
+  // Gets a list of available ALSA devices.
+  void GetAlsaAudioDevices(StreamType type,
+                           ::media::AudioDeviceNames* device_names);
+
+  // Gets the ALSA devices' names and ids that support streams of the
+  // given type.
+  void GetAlsaDevicesInfo(StreamType type,
+                          void** hint,
+                          ::media::AudioDeviceNames* device_names);
+
+  // Checks if the specific ALSA device is available.
+  static bool IsAlsaDeviceAvailable(StreamType type, const char* device_name);
+
+  static const char* UnwantedDeviceTypeWhenEnumerating(StreamType wanted_type);
+
+  std::unique_ptr<::media::AlsaWrapper> wrapper_;
+
+  DISALLOW_COPY_AND_ASSIGN(CastAudioManagerAlsa);
+};
+
+}  // namespace media
+}  // namespace chromecast
+
+#endif  // CHROMECAST_MEDIA_AUDIO_CAST_AUDIO_MANAGER_ALSA_H_
diff --git a/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc b/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc
new file mode 100644
index 0000000..f2aca60
--- /dev/null
+++ b/chromecast/media/audio/cast_audio_manager_alsa_unittest.cc
@@ -0,0 +1,68 @@
+// 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 "chromecast/media/audio/cast_audio_manager_alsa.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_message_loop.h"
+#include "chromecast/media/cma/test/mock_media_pipeline_backend_factory.h"
+#include "media/audio/fake_audio_log_factory.h"
+#include "media/audio/test_audio_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::Return;
+using testing::StrictMock;
+using testing::_;
+
+namespace chromecast {
+namespace media {
+namespace {
+
+const char kDefaultAlsaDevice[] = "plug:default";
+
+const ::media::AudioParameters kDefaultAudioParams(
+    ::media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+    ::media::CHANNEL_LAYOUT_STEREO,
+    ::media::AudioParameters::kAudioCDSampleRate,
+    16,
+    256);
+
+void OnLogMessage(const std::string& message) {}
+
+class CastAudioManagerAlsaTest : public testing::Test {
+ public:
+  CastAudioManagerAlsaTest() : media_thread_("CastMediaThread") {
+    CHECK(media_thread_.Start());
+
+    backend_factory_ = new MockMediaPipelineBackendFactory();
+    audio_manager_ = base::MakeUnique<CastAudioManagerAlsa>(
+        base::MakeUnique<::media::TestAudioThread>(), &audio_log_factory_,
+        base::WrapUnique(backend_factory_), media_thread_.task_runner(), false);
+  }
+
+  ~CastAudioManagerAlsaTest() override { audio_manager_->Shutdown(); }
+
+ protected:
+  base::TestMessageLoop message_loop_;
+  base::Thread media_thread_;
+  ::media::FakeAudioLogFactory audio_log_factory_;
+  std::unique_ptr<CastAudioManagerAlsa> audio_manager_;
+
+  // Owned by |audio_manager_|
+  MockMediaPipelineBackendFactory* backend_factory_;
+};
+
+TEST_F(CastAudioManagerAlsaTest, MakeAudioInputStream) {
+  ::media::AudioInputStream* stream = audio_manager_->MakeAudioInputStream(
+      kDefaultAudioParams, kDefaultAlsaDevice, base::Bind(&OnLogMessage));
+  ASSERT_TRUE(stream);
+  EXPECT_TRUE(stream->Open());
+  stream->Close();
+}
+
+}  // namespace
+}  // namespace media
+}  // namespace chromecast
diff --git a/components/cast_channel/BUILD.gn b/components/cast_channel/BUILD.gn
index 71f791ed..a766875 100644
--- a/components/cast_channel/BUILD.gn
+++ b/components/cast_channel/BUILD.gn
@@ -16,8 +16,6 @@
     "cast_socket.h",
     "cast_socket_service.cc",
     "cast_socket_service.h",
-    "cast_socket_service_factory.cc",
-    "cast_socket_service_factory.h",
     "cast_transport.cc",
     "cast_transport.h",
     "keep_alive_delegate.cc",
diff --git a/components/cast_channel/cast_socket.cc b/components/cast_channel/cast_socket.cc
index 86adf57..4039ade 100644
--- a/components/cast_channel/cast_socket.cc
+++ b/components/cast_channel/cast_socket.cc
@@ -296,6 +296,11 @@
     observers_.AddObserver(observer);
 }
 
+void CastSocketImpl::RemoveObserver(Observer* observer) {
+  DCHECK(observer);
+  observers_.RemoveObserver(observer);
+}
+
 void CastSocketImpl::OnConnectTimeout() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   // Stop all pending connection setup tasks and report back to the client.
diff --git a/components/cast_channel/cast_socket.h b/components/cast_channel/cast_socket.h
index 566993b..31d829ee 100644
--- a/components/cast_channel/cast_socket.h
+++ b/components/cast_channel/cast_socket.h
@@ -129,6 +129,9 @@
 
   // Registers |observer| with the socket to receive messages and error events.
   virtual void AddObserver(Observer* observer) = 0;
+
+  // Unregisters |observer|.
+  virtual void RemoveObserver(Observer* observer) = 0;
 };
 
 // This class implements a channel between Chrome and a Cast device using a TCP
@@ -181,6 +184,7 @@
   bool keep_alive() const override;
   bool audio_only() const override;
   void AddObserver(Observer* observer) override;
+  void RemoveObserver(Observer* observer) override;
 
  protected:
   // CastTransport::Delegate methods for receiving handshake messages.
diff --git a/components/cast_channel/cast_socket_service.cc b/components/cast_channel/cast_socket_service.cc
index 6bdeae3..7932395 100644
--- a/components/cast_channel/cast_socket_service.cc
+++ b/components/cast_channel/cast_socket_service.cc
@@ -28,15 +28,17 @@
 
 int CastSocketService::last_channel_id_ = 0;
 
-CastSocketService::CastSocketService()
-    : RefcountedKeyedService(
-          BrowserThread::GetTaskRunnerForThread(BrowserThread::IO)),
-      logger_(new Logger()) {
+CastSocketService::CastSocketService() : logger_(new Logger()) {
   DETACH_FROM_THREAD(thread_checker_);
 }
 
-CastSocketService::~CastSocketService() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+// This is a leaky singleton and the dtor won't be called.
+CastSocketService::~CastSocketService() = default;
+
+// static
+CastSocketService* CastSocketService::GetInstance() {
+  return base::Singleton<CastSocketService,
+                         base::LeakySingletonTraits<CastSocketService>>::get();
 }
 
 scoped_refptr<Logger> CastSocketService::GetLogger() {
@@ -128,17 +130,9 @@
                     observer);
 }
 
-CastSocket::Observer* CastSocketService::GetObserver(const std::string& id) {
-  auto it = socket_observer_map_.find(id);
-  return it == socket_observer_map_.end() ? nullptr : it->second.get();
-}
-
-CastSocket::Observer* CastSocketService::AddObserver(
-    const std::string& id,
-    std::unique_ptr<CastSocket::Observer> observer) {
-  CastSocket::Observer* observer_ptr = observer.get();
-  socket_observer_map_.insert(std::make_pair(id, std::move(observer)));
-  return observer_ptr;
+void CastSocketService::RemoveObserver(CastSocket::Observer* observer) {
+  for (auto& socket_it : sockets_)
+    socket_it.second->RemoveObserver(observer);
 }
 
 void CastSocketService::SetSocketForTest(
@@ -146,6 +140,4 @@
   socket_for_test_ = std::move(socket_for_test);
 }
 
-void CastSocketService::ShutdownOnUIThread() {}
-
 }  // namespace cast_channel
diff --git a/components/cast_channel/cast_socket_service.h b/components/cast_channel/cast_socket_service.h
index bb465e9..d7dc8c2 100644
--- a/components/cast_channel/cast_socket_service.h
+++ b/components/cast_channel/cast_socket_service.h
@@ -9,9 +9,9 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/singleton.h"
 #include "base/threading/thread_checker.h"
 #include "components/cast_channel/cast_socket.h"
-#include "components/keyed_service/core/refcounted_keyed_service.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace cast_channel {
@@ -20,9 +20,9 @@
 // to underlying storage.
 // Instance of this class is created on the UI thread and destroyed on the IO
 // thread. All public API must be called from the IO thread.
-class CastSocketService : public RefcountedKeyedService {
+class CastSocketService {
  public:
-  CastSocketService();
+  static CastSocketService* GetInstance();
 
   // Returns a pointer to the Logger member variable.
   scoped_refptr<cast_channel::Logger> GetLogger();
@@ -77,24 +77,20 @@
                          const CastSocket::OnOpenCallback& open_cb,
                          CastSocket::Observer* observer);
 
-  // Returns an observer corresponding to |id|.
-  CastSocket::Observer* GetObserver(const std::string& id);
-
-  // Adds |observer| to |socket_observer_map_| keyed by |id|. Return raw pointer
-  // of the newly added observer.
-  CastSocket::Observer* AddObserver(
-      const std::string& id,
-      std::unique_ptr<CastSocket::Observer> observer);
+  // Remove |observer| from each socket in |sockets_|
+  void RemoveObserver(CastSocket::Observer* observer);
 
   // Allow test to inject a mock cast socket.
   void SetSocketForTest(std::unique_ptr<CastSocket> socket_for_test);
 
- protected:
-  ~CastSocketService() override;
-
  private:
-  // RefcountedKeyedService implementation.
-  void ShutdownOnUIThread() override;
+  friend class CastSocketServiceTest;
+  friend class MockCastSocketService;
+  friend struct base::DefaultSingletonTraits<CastSocketService>;
+  friend struct std::default_delete<CastSocketService>;
+
+  CastSocketService();
+  virtual ~CastSocketService();
 
   // Used to generate CastSocket id.
   static int last_channel_id_;
@@ -102,13 +98,7 @@
   // The collection of CastSocket keyed by channel_id.
   std::map<int, std::unique_ptr<CastSocket>> sockets_;
 
-  // Map of CastSocket::Observer keyed by observer id. For extension side
-  // observers, id is extension_id; For browser side observers, id is a hard
-  // coded string.
-  std::map<std::string, std::unique_ptr<CastSocket::Observer>>
-      socket_observer_map_;
-
-  scoped_refptr<cast_channel::Logger> logger_;
+  scoped_refptr<Logger> logger_;
 
   std::unique_ptr<CastSocket> socket_for_test_;
 
diff --git a/components/cast_channel/cast_socket_service_factory.cc b/components/cast_channel/cast_socket_service_factory.cc
deleted file mode 100644
index bf0757d..0000000
--- a/components/cast_channel/cast_socket_service_factory.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cast_channel/cast_socket_service_factory.h"
-
-#include "components/cast_channel/cast_socket_service.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-
-namespace cast_channel {
-
-using content::BrowserContext;
-
-namespace {
-
-base::LazyInstance<CastSocketServiceFactory>::DestructorAtExit service_factory =
-    LAZY_INSTANCE_INITIALIZER;
-}  // namespace
-
-// static
-scoped_refptr<CastSocketService> CastSocketServiceFactory::GetForBrowserContext(
-    BrowserContext* context) {
-  DCHECK(context);
-  // GetServiceForBrowserContext returns a KeyedService hence the static_cast<>
-  // to construct a temporary scoped_refptr on the stack for the return value.
-  return static_cast<CastSocketService*>(
-      service_factory.Get().GetServiceForBrowserContext(context, true).get());
-}
-
-// static
-CastSocketServiceFactory* CastSocketServiceFactory::GetInstance() {
-  return &service_factory.Get();
-}
-
-CastSocketServiceFactory::CastSocketServiceFactory()
-    : RefcountedBrowserContextKeyedServiceFactory(
-          "CastSocketService",
-          BrowserContextDependencyManager::GetInstance()) {}
-
-CastSocketServiceFactory::~CastSocketServiceFactory() {}
-
-content::BrowserContext* CastSocketServiceFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return context;
-}
-
-scoped_refptr<RefcountedKeyedService>
-CastSocketServiceFactory::BuildServiceInstanceFor(
-    BrowserContext* context) const {
-  return make_scoped_refptr(new CastSocketService());
-}
-
-}  // namespace cast_channel
diff --git a/components/cast_channel/cast_socket_service_factory.h b/components/cast_channel/cast_socket_service_factory.h
deleted file mode 100644
index f3824c7..0000000
--- a/components/cast_channel/cast_socket_service_factory.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CAST_CHANNEL_CAST_SOCKET_SERVICE_FACTORY_H_
-#define COMPONENTS_CAST_CHANNEL_CAST_SOCKET_SERVICE_FACTORY_H_
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "components/keyed_service/content/refcounted_browser_context_keyed_service_factory.h"
-
-namespace cast_channel {
-
-class CastSocketService;
-
-// TODO(crbug.com/725717): CastSocket created by one profile (browser context)
-// could be shared with other profiles.
-class CastSocketServiceFactory
-    : public RefcountedBrowserContextKeyedServiceFactory {
- public:
-  // Caller needs to make sure that it passes in the same |context| instance to
-  // this function for both normal profile and incognito profile.
-  static scoped_refptr<CastSocketService> GetForBrowserContext(
-      content::BrowserContext* context);
-
-  static CastSocketServiceFactory* GetInstance();
-
- private:
-  friend struct base::LazyInstanceTraitsBase<CastSocketServiceFactory>;
-
-  CastSocketServiceFactory();
-  ~CastSocketServiceFactory() override;
-
-  // BrowserContextKeyedServiceFactory interface.
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-
-  scoped_refptr<RefcountedKeyedService> BuildServiceInstanceFor(
-      content::BrowserContext* context) const override;
-
-  DISALLOW_COPY_AND_ASSIGN(CastSocketServiceFactory);
-};
-
-}  // namespace cast_channel
-
-#endif  // COMPONENTS_CAST_CHANNEL_CAST_SOCKET_SERVICE_FACTORY_H_
diff --git a/components/cast_channel/cast_socket_service_unittest.cc b/components/cast_channel/cast_socket_service_unittest.cc
index ca4f9307..1c2abbc 100644
--- a/components/cast_channel/cast_socket_service_unittest.cc
+++ b/components/cast_channel/cast_socket_service_unittest.cc
@@ -34,7 +34,7 @@
 
  protected:
   content::TestBrowserThreadBundle thread_bundle_;
-  scoped_refptr<CastSocketService> cast_socket_service_;
+  std::unique_ptr<CastSocketService> cast_socket_service_;
   base::MockCallback<CastSocket::OnOpenCallback> mock_on_open_callback_;
   MockCastSocketObserver mock_observer_;
 };
diff --git a/components/cast_channel/cast_test_util.cc b/components/cast_channel/cast_test_util.cc
index 36efe11..ab6ce72 100644
--- a/components/cast_channel/cast_test_util.cc
+++ b/components/cast_channel/cast_test_util.cc
@@ -29,6 +29,9 @@
 MockCastSocketObserver::MockCastSocketObserver() {}
 MockCastSocketObserver::~MockCastSocketObserver() {}
 
+MockCastSocketService::MockCastSocketService() {}
+MockCastSocketService::~MockCastSocketService() {}
+
 MockCastSocket::MockCastSocket()
     : channel_id_(0),
       error_state_(ChannelError::NONE),
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index 66bac563..7e37ca4 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/cast_channel/cast_socket.h"
+#include "components/cast_channel/cast_socket_service.h"
 #include "components/cast_channel/cast_transport.h"
 #include "components/cast_channel/proto/cast_channel.pb.h"
 #include "net/base/ip_endpoint.h"
@@ -64,6 +65,19 @@
                void(const CastSocket& socket, const CastMessage& message));
 };
 
+class MockCastSocketService : public CastSocketService {
+ public:
+  MockCastSocketService();
+  ~MockCastSocketService() override;
+
+  MOCK_METHOD4(OpenSocket,
+               int(const net::IPEndPoint& ip_endpoint,
+                   net::NetLog* net_log,
+                   const CastSocket::OnOpenCallback& open_cb,
+                   CastSocket::Observer* observer));
+  MOCK_CONST_METHOD1(GetSocket, CastSocket*(int channel_id));
+};
+
 class MockCastSocket : public CastSocket {
  public:
   MockCastSocket();
@@ -73,6 +87,7 @@
   MOCK_METHOD1(Close, void(const net::CompletionCallback& callback));
   MOCK_CONST_METHOD0(ready_state, ReadyState());
   MOCK_METHOD1(AddObserver, void(Observer* observer));
+  MOCK_METHOD1(RemoveObserver, void(Observer* observer));
 
   const net::IPEndPoint& ip_endpoint() const override { return ip_endpoint_; }
   void SetIPEndpoint(const net::IPEndPoint& ip_endpoint) {
diff --git a/components/download/components_unittests.filter b/components/download/components_unittests.filter
index 023467a6..f694bb6 100644
--- a/components/download/components_unittests.filter
+++ b/components/download/components_unittests.filter
@@ -1,3 +1,4 @@
+AllDownloadItemNotifierTest.*
 DeviceStatusListenerTest.*
 DownloadDriverImplTest.*
 DownloadSchedulerImplTest.*
diff --git a/components/download/content/BUILD.gn b/components/download/content/BUILD.gn
index 416f317cf..049294f 100644
--- a/components/download/content/BUILD.gn
+++ b/components/download/content/BUILD.gn
@@ -9,5 +9,6 @@
 
   deps = [
     "//components/download/content/internal:unit_tests",
+    "//components/download/content/public:unit_tests",
   ]
 }
diff --git a/components/download/content/internal/BUILD.gn b/components/download/content/internal/BUILD.gn
index 09d11a2..77025b91 100644
--- a/components/download/content/internal/BUILD.gn
+++ b/components/download/content/internal/BUILD.gn
@@ -14,6 +14,7 @@
   ]
 
   public_deps = [
+    "//components/download/content/public",
     "//components/download/internal",
     "//components/download/public",
   ]
@@ -36,6 +37,7 @@
   deps = [
     ":internal",
     "//base/test:test_support",
+    "//components/download/content/public",
     "//content/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/download/content/internal/download_driver_impl.cc b/components/download/content/internal/download_driver_impl.cc
index 2b4641f..74b7c801 100644
--- a/components/download/content/internal/download_driver_impl.cc
+++ b/components/download/content/internal/download_driver_impl.cc
@@ -7,6 +7,7 @@
 #include <set>
 #include <vector>
 
+#include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/download/internal/driver_entry.h"
 #include "content/public/browser/download_interrupt_reasons.h"
@@ -84,13 +85,7 @@
   DCHECK(download_manager_);
 }
 
-DownloadDriverImpl::~DownloadDriverImpl() {
-  // TODO(xingliu): We should maintain a list of observing download items, and
-  // remove the observer here. This can be fixed if we use
-  // AllDownloadItemNotifier.
-  if (download_manager_)
-    download_manager_->RemoveObserver(this);
-}
+DownloadDriverImpl::~DownloadDriverImpl() = default;
 
 void DownloadDriverImpl::Initialize(DownloadDriver::Client* client) {
   DCHECK(!client_);
@@ -103,9 +98,8 @@
     return;
   }
 
-  download_manager_->AddObserver(this);
-  if (download_manager_->IsManagerInitialized())
-    client_->OnDriverReady(true);
+  notifier_ =
+      base::MakeUnique<AllDownloadItemNotifier>(download_manager_, this);
 }
 
 void DownloadDriverImpl::HardRecover() {
@@ -216,7 +210,8 @@
   return guids;
 }
 
-void DownloadDriverImpl::OnDownloadUpdated(content::DownloadItem* item) {
+void DownloadDriverImpl::OnDownloadUpdated(content::DownloadManager* manager,
+                                           content::DownloadItem* item) {
   DCHECK(client_);
   // Blocks the observer call if we asked to remove the download.
   if (guid_to_remove_.find(item->GetGuid()) != guid_to_remove_.end())
@@ -237,7 +232,8 @@
   }
 }
 
-void DownloadDriverImpl::OnDownloadRemoved(content::DownloadItem* download) {
+void DownloadDriverImpl::OnDownloadRemoved(content::DownloadManager* manager,
+                                           content::DownloadItem* download) {
   guid_to_remove_.erase(download->GetGuid());
   // |download| is about to be deleted.
 }
@@ -245,7 +241,6 @@
 void DownloadDriverImpl::OnDownloadCreated(content::DownloadManager* manager,
                                            content::DownloadItem* item) {
   // Listens to all downloads.
-  item->AddObserver(this);
   DCHECK(client_);
   DriverEntry entry = CreateDriverEntry(item);
 
@@ -255,14 +250,17 @@
     client_->OnDownloadCreated(entry);
 }
 
-void DownloadDriverImpl::OnManagerInitialized() {
+void DownloadDriverImpl::OnManagerInitialized(
+    content::DownloadManager* manager) {
+  DCHECK_EQ(download_manager_, manager);
   DCHECK(client_);
   DCHECK(download_manager_);
   client_->OnDriverReady(true);
 }
 
-void DownloadDriverImpl::ManagerGoingDown(content::DownloadManager* manager) {
+void DownloadDriverImpl::OnManagerGoingDown(content::DownloadManager* manager) {
   DCHECK_EQ(download_manager_, manager);
+  notifier_.reset();
   download_manager_ = nullptr;
 }
 
diff --git a/components/download/content/internal/download_driver_impl.h b/components/download/content/internal/download_driver_impl.h
index 18b7d3e..e6348620 100644
--- a/components/download/content/internal/download_driver_impl.h
+++ b/components/download/content/internal/download_driver_impl.h
@@ -5,11 +5,13 @@
 #ifndef COMPONENTS_DOWNLOAD_CONTENT_INTERNAL_DOWNLOAD_DRIVER_IMPL_H_
 #define COMPONENTS_DOWNLOAD_CONTENT_INTERNAL_DOWNLOAD_DRIVER_IMPL_H_
 
+#include <memory>
 #include <set>
 #include <string>
 
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "components/download/internal/download_driver.h"
 #include "components/download/public/download_params.h"
 #include "content/public/browser/browser_context.h"
@@ -23,8 +25,7 @@
 // Aggregates and handles all interaction between download service and content
 // download logic.
 class DownloadDriverImpl : public DownloadDriver,
-                           public content::DownloadManager::Observer,
-                           public content::DownloadItem::Observer {
+                           public AllDownloadItemNotifier::Observer {
  public:
   // Creates a driver entry based on a download item.
   static DriverEntry CreateDriverEntry(const content::DownloadItem* item);
@@ -49,15 +50,15 @@
   std::set<std::string> GetActiveDownloads() override;
 
  private:
-  // content::DownloadItem::Observer implementation.
-  void OnDownloadUpdated(content::DownloadItem* item) override;
-  void OnDownloadRemoved(content::DownloadItem* download) override;
-
-  // content::DownloadManager::Observer implementation.
+  // content::AllDownloadItemNotifier::Observer implementation.
+  void OnManagerInitialized(content::DownloadManager* manager) override;
+  void OnManagerGoingDown(content::DownloadManager* manager) override;
   void OnDownloadCreated(content::DownloadManager* manager,
                          content::DownloadItem* item) override;
-  void OnManagerInitialized() override;
-  void ManagerGoingDown(content::DownloadManager* manager) override;
+  void OnDownloadUpdated(content::DownloadManager* manager,
+                         content::DownloadItem* item) override;
+  void OnDownloadRemoved(content::DownloadManager* manager,
+                         content::DownloadItem* item) override;
 
   void OnHardRecoverComplete(bool success);
 
@@ -70,6 +71,9 @@
   // The client that receives updates from low level download logic.
   DownloadDriver::Client* client_;
 
+  // Built lazily on initialize and destroyed when/if the manager is torn down.
+  std::unique_ptr<AllDownloadItemNotifier> notifier_;
+
   // Pending guid set of downloads that will be removed soon.
   std::set<std::string> guid_to_remove_;
 
diff --git a/components/download/content/internal/download_driver_impl_unittest.cc b/components/download/content/internal/download_driver_impl_unittest.cc
index 32c1a987..f4937e0 100644
--- a/components/download/content/internal/download_driver_impl_unittest.cc
+++ b/components/download/content/internal/download_driver_impl_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 #include "content/public/test/fake_download_item.h"
 #include "content/public/test/mock_download_manager.h"
 #include "net/http/http_response_headers.h"
@@ -85,8 +86,8 @@
   driver_->Initialize(&mock_client_);
 
   EXPECT_CALL(mock_client_, OnDriverReady(true));
-  static_cast<content::DownloadManager::Observer*>(driver_.get())
-      ->OnManagerInitialized();
+  static_cast<AllDownloadItemNotifier::Observer*>(driver_.get())
+      ->OnManagerInitialized(&mock_manager_);
 }
 
 TEST_F(DownloadDriverImplTest, TestHardRecover) {
@@ -121,13 +122,13 @@
   EXPECT_CALL(mock_client_, OnDownloadUpdated(DriverEntryEqual(entry)))
       .Times(1)
       .RetiresOnSaturation();
-  static_cast<content::DownloadItem::Observer*>(driver_.get())
-      ->OnDownloadUpdated(&fake_item);
+  static_cast<AllDownloadItemNotifier::Observer*>(driver_.get())
+      ->OnDownloadUpdated(&mock_manager_, &fake_item);
 
   // Nothing happens for cancelled state.
   fake_item.SetState(DownloadState::CANCELLED);
-  static_cast<content::DownloadItem::Observer*>(driver_.get())
-      ->OnDownloadUpdated(&fake_item);
+  static_cast<AllDownloadItemNotifier::Observer*>(driver_.get())
+      ->OnDownloadUpdated(&mock_manager_, &fake_item);
 
   fake_item.SetReceivedBytes(1024);
   fake_item.SetState(DownloadState::COMPLETE);
@@ -135,8 +136,8 @@
   EXPECT_CALL(mock_client_, OnDownloadSucceeded(DriverEntryEqual(entry)))
       .Times(1)
       .RetiresOnSaturation();
-  static_cast<content::DownloadItem::Observer*>(driver_.get())
-      ->OnDownloadUpdated(&fake_item);
+  static_cast<AllDownloadItemNotifier::Observer*>(driver_.get())
+      ->OnDownloadUpdated(&mock_manager_, &fake_item);
 
   fake_item.SetState(DownloadState::INTERRUPTED);
   fake_item.SetLastReason(
@@ -146,8 +147,8 @@
                                              FailureType::RECOVERABLE))
       .Times(1)
       .RetiresOnSaturation();
-  static_cast<content::DownloadItem::Observer*>(driver_.get())
-      ->OnDownloadUpdated(&fake_item);
+  static_cast<AllDownloadItemNotifier::Observer*>(driver_.get())
+      ->OnDownloadUpdated(&mock_manager_, &fake_item);
 }
 
 TEST_F(DownloadDriverImplTest, TestGetActiveDownloadsCall) {
diff --git a/components/download/content/public/BUILD.gn b/components/download/content/public/BUILD.gn
new file mode 100644
index 0000000..4cb80da
--- /dev/null
+++ b/components/download/content/public/BUILD.gn
@@ -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.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+}
+
+source_set("public") {
+  sources = [
+    "all_download_item_notifier.cc",
+    "all_download_item_notifier.h",
+  ]
+
+  public_deps = [
+    "//base",
+  ]
+
+  deps = [
+    "//content/public/browser",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "all_download_item_notifier_unittest.cc",
+  ]
+
+  deps = [
+    ":public",
+    "//content/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/download/content/public/all_download_item_notifier.cc b/components/download/content/public/all_download_item_notifier.cc
new file mode 100644
index 0000000..81159f57
--- /dev/null
+++ b/components/download/content/public/all_download_item_notifier.cc
@@ -0,0 +1,75 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/download/content/public/all_download_item_notifier.h"
+
+namespace download {
+
+AllDownloadItemNotifier::AllDownloadItemNotifier(
+    content::DownloadManager* manager,
+    AllDownloadItemNotifier::Observer* observer)
+    : manager_(manager), observer_(observer) {
+  DCHECK(observer_);
+  manager_->AddObserver(this);
+  content::DownloadManager::DownloadVector items;
+  manager_->GetAllDownloads(&items);
+  for (content::DownloadManager::DownloadVector::const_iterator it =
+           items.begin();
+       it != items.end(); ++it) {
+    (*it)->AddObserver(this);
+    observing_.insert(*it);
+  }
+
+  if (manager_->IsManagerInitialized())
+    observer_->OnManagerInitialized(manager_);
+}
+
+AllDownloadItemNotifier::~AllDownloadItemNotifier() {
+  if (manager_)
+    manager_->RemoveObserver(this);
+  for (std::set<content::DownloadItem*>::const_iterator it = observing_.begin();
+       it != observing_.end(); ++it) {
+    (*it)->RemoveObserver(this);
+  }
+  observing_.clear();
+}
+
+void AllDownloadItemNotifier::OnManagerInitialized() {
+  observer_->OnManagerInitialized(manager_);
+}
+
+void AllDownloadItemNotifier::ManagerGoingDown(
+    content::DownloadManager* manager) {
+  DCHECK_EQ(manager_, manager);
+  observer_->OnManagerGoingDown(manager);
+  manager_->RemoveObserver(this);
+  manager_ = NULL;
+}
+
+void AllDownloadItemNotifier::OnDownloadCreated(
+    content::DownloadManager* manager,
+    content::DownloadItem* item) {
+  item->AddObserver(this);
+  observing_.insert(item);
+  observer_->OnDownloadCreated(manager, item);
+}
+
+void AllDownloadItemNotifier::OnDownloadUpdated(content::DownloadItem* item) {
+  observer_->OnDownloadUpdated(manager_, item);
+}
+
+void AllDownloadItemNotifier::OnDownloadOpened(content::DownloadItem* item) {
+  observer_->OnDownloadOpened(manager_, item);
+}
+
+void AllDownloadItemNotifier::OnDownloadRemoved(content::DownloadItem* item) {
+  observer_->OnDownloadRemoved(manager_, item);
+}
+
+void AllDownloadItemNotifier::OnDownloadDestroyed(content::DownloadItem* item) {
+  item->RemoveObserver(this);
+  observing_.erase(item);
+}
+
+}  // namespace download
diff --git a/components/download/content/public/all_download_item_notifier.h b/components/download/content/public/all_download_item_notifier.h
new file mode 100644
index 0000000..d52cc92
--- /dev/null
+++ b/components/download/content/public/all_download_item_notifier.h
@@ -0,0 +1,94 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
+#define COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
+
+#include <set>
+
+#include "base/macros.h"
+#include "content/public/browser/download_item.h"
+#include "content/public/browser/download_manager.h"
+
+// AllDownloadItemNotifier observes ALL the DownloadItems on a given
+// DownloadManager.
+// Clients should use GetManager() instead of storing their own pointer to the
+// manager so that they can be sensitive to managers that have gone down.
+
+// Example Usage:
+// class DownloadSystemConsumer : public AllDownloadItemNotifier::Observer {
+//  public:
+//   DownloadSystemConsumer(DownloadManager* original_manager,
+//            DownloadManager* incognito_manager)
+//     : original_notifier_(original_manager, this),
+//       incognito_notifier_(incognito_manager, this) {
+//   }
+//
+//   virtual void OnDownloadUpdated(
+//     DownloadManager* manager, DownloadItem* item) { ... }
+//
+//  private:
+//   AllDownloadItemNotifier original_notifier_;
+//   AllDownloadItemNotifier incognito_notifier_;
+// };
+
+namespace download {
+
+class AllDownloadItemNotifier : public content::DownloadManager::Observer,
+                                public content::DownloadItem::Observer {
+ public:
+  // All of the methods take the DownloadManager so that subclasses can observe
+  // multiple managers at once and easily distinguish which manager a given item
+  // belongs to.
+  class Observer {
+   public:
+    Observer() {}
+    virtual ~Observer() {}
+
+    virtual void OnManagerInitialized(content::DownloadManager* manager) {}
+    virtual void OnManagerGoingDown(content::DownloadManager* manager) {}
+    virtual void OnDownloadCreated(content::DownloadManager* manager,
+                                   content::DownloadItem* item) {}
+    virtual void OnDownloadUpdated(content::DownloadManager* manager,
+                                   content::DownloadItem* item) {}
+    virtual void OnDownloadOpened(content::DownloadManager* manager,
+                                  content::DownloadItem* item) {}
+    virtual void OnDownloadRemoved(content::DownloadManager* manager,
+                                   content::DownloadItem* item) {}
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Observer);
+  };
+
+  AllDownloadItemNotifier(content::DownloadManager* manager,
+                          Observer* observer);
+
+  ~AllDownloadItemNotifier() override;
+
+  // Returns NULL if the manager has gone down.
+  content::DownloadManager* GetManager() const { return manager_; }
+
+ private:
+  // DownloadManager::Observer
+  void OnManagerInitialized() override;
+  void ManagerGoingDown(content::DownloadManager* manager) override;
+  void OnDownloadCreated(content::DownloadManager* manager,
+                         content::DownloadItem* item) override;
+
+  // DownloadItem::Observer
+  void OnDownloadUpdated(content::DownloadItem* item) override;
+  void OnDownloadOpened(content::DownloadItem* item) override;
+  void OnDownloadRemoved(content::DownloadItem* item) override;
+  void OnDownloadDestroyed(content::DownloadItem* item) override;
+
+  content::DownloadManager* manager_;
+  AllDownloadItemNotifier::Observer* observer_;
+  std::set<content::DownloadItem*> observing_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllDownloadItemNotifier);
+};
+
+}  // namespace download
+
+#endif  // COMPONENTS_DOWNLOAD_CONTENT_PUBLIC_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
diff --git a/content/browser/download/all_download_item_notifier_unittest.cc b/components/download/content/public/all_download_item_notifier_unittest.cc
similarity index 96%
rename from content/browser/download/all_download_item_notifier_unittest.cc
rename to components/download/content/public/all_download_item_notifier_unittest.cc
index 81f5f5a..271fed8 100644
--- a/content/browser/download/all_download_item_notifier_unittest.cc
+++ b/components/download/content/public/all_download_item_notifier_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/browser/all_download_item_notifier.h"
+#include "components/download/content/public/all_download_item_notifier.h"
 
 #include "base/macros.h"
 #include "content/public/test/mock_download_item.h"
@@ -14,7 +14,7 @@
 using testing::SetArgPointee;
 using testing::_;
 
-namespace content {
+namespace download {
 namespace {
 
 class MockNotifierObserver : public AllDownloadItemNotifier::Observer {
@@ -111,4 +111,4 @@
   ClearNotifier();
 }
 
-}  // namespace content
+}  // namespace download
diff --git a/components/net_log/net_export_file_writer.cc b/components/net_log/net_export_file_writer.cc
index e20448d..94d64e6 100644
--- a/components/net_log/net_export_file_writer.cc
+++ b/components/net_log/net_export_file_writer.cc
@@ -38,11 +38,6 @@
 const base::FilePath::CharType kLogRelativePath[] =
     FILE_PATH_LITERAL("net-export/chrome-net-export-log.json");
 
-// Old path used by net-export. Used to delete old files.
-// TODO(mmenke): Should remove at some point. Added in M46.
-const base::FilePath::CharType kOldLogRelativePath[] =
-    FILE_PATH_LITERAL("chrome-net-export-log.json");
-
 // Contains file-related initialization tasks for NetExportFileWriter.
 NetExportFileWriter::DefaultLogPathResults SetUpDefaultLogPath(
     const NetExportFileWriter::DirectoryGetter& default_log_base_dir_getter) {
@@ -54,9 +49,6 @@
   if (!default_log_base_dir_getter.Run(&default_base_dir))
     return results;
 
-  // Delete log file at old location, if present.
-  base::DeleteFile(default_base_dir.Append(kOldLogRelativePath), false);
-
   results.default_log_path = default_base_dir.Append(kLogRelativePath);
   if (!base::CreateDirectoryAndGetError(results.default_log_path.DirName(),
                                         nullptr))
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 5eaffb20..d4ddb38c 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -180,11 +180,14 @@
       continue;
     }
     base::DictionaryValue* verdict_entry = nullptr;
-    CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion(
-        it.key() /* cache_expression */, &verdict_entry));
+    verdict_dictionary->GetDictionaryWithoutPathExpansion(
+        it.key() /* cache_expression */, &verdict_entry);
     int verdict_received_time;
     LoginReputationClientResponse verdict;
-    CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict));
+    // Ignore any entry that we cannot parse. These invalid entries will be
+    // cleaned up during shutdown.
+    if (!ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict))
+      continue;
     // Since password protection content settings are keyed by origin, we only
     // need to compare the path part of the cache_expression and the given url.
     std::string cache_expression_path =
@@ -609,13 +612,13 @@
       continue;
 
     base::DictionaryValue* verdict_entry = nullptr;
-    CHECK(verdict_dictionary->GetDictionaryWithoutPathExpansion(
-        it.key(), &verdict_entry));
+    verdict_dictionary->GetDictionaryWithoutPathExpansion(it.key(),
+                                                          &verdict_entry);
     int verdict_received_time;
     LoginReputationClientResponse verdict;
-    CHECK(ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict));
 
-    if (IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) {
+    if (!ParseVerdictEntry(verdict_entry, &verdict_received_time, &verdict) ||
+        IsCacheExpired(verdict_received_time, verdict.cache_duration_sec())) {
       // Since DictionaryValue::Iterator cannot be used to modify the
       // dictionary, we record the keys of expired verdicts in |expired_keys|
       // and remove them in the next for-loop.
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 4ce4a41..dbf0ec6 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -222,6 +222,27 @@
                                                verdict_received_time);
   }
 
+  void CacheInvalidVerdict() {
+    GURL invalid_hostname("http://invalid.com");
+    std::unique_ptr<base::DictionaryValue> verdict_dictionary =
+        base::DictionaryValue::From(content_setting_map_->GetWebsiteSetting(
+            invalid_hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+            std::string(), nullptr));
+
+    if (!verdict_dictionary.get())
+      verdict_dictionary = base::MakeUnique<base::DictionaryValue>();
+
+    std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
+        base::MakeUnique<base::DictionaryValue>();
+    invalid_verdict_entry->SetString("invalid", "invalid_string");
+
+    verdict_dictionary->SetWithoutPathExpansion(
+        "invalid_cache_expression", std::move(invalid_verdict_entry));
+    content_setting_map_->SetWebsiteSettingDefaultScope(
+        invalid_hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
+        std::string(), std::move(verdict_dictionary));
+  }
+
   size_t GetStoredVerdictCount(LoginReputationClientRequest::TriggerType type) {
     return password_protection_service_->GetStoredVerdictCount(type);
   }
@@ -815,6 +836,23 @@
                 &actual_verdict));
 }
 
+TEST_F(PasswordProtectionServiceTest,
+       TestCleanUpExpiredVerdictWithInvalidEntry) {
+  CacheInvalidVerdict();
+  ContentSettingsForOneType password_protection_settings;
+  content_setting_map_->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(),
+      &password_protection_settings);
+  ASSERT_FALSE(password_protection_settings.empty());
+
+  password_protection_service_->CleanUpExpiredVerdicts();
+
+  content_setting_map_->GetSettingsForOneType(
+      CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(),
+      &password_protection_settings);
+  EXPECT_TRUE(password_protection_settings.empty());
+}
+
 TEST_F(PasswordProtectionServiceTest, VerifyPasswordOnFocusRequestProto) {
   // Set up valid response.
   net::TestURLFetcher fetcher(0, GURL("http://bar.com"), nullptr);
diff --git a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
index a44ccfae..d8ae42f 100644
--- a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
+++ b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
@@ -123,6 +123,17 @@
   navigation_handle()->Resume();
 }
 
+AsyncDocumentSubresourceFilter*
+ActivationStateComputingNavigationThrottle::filter() const {
+  // TODO(csharrison): This should not really be necessary, as we should be
+  // delaying the navigation until the filter has computed an activation state.
+  // See crbug.com/736249. In the mean time, have a check here to avoid
+  // returning a filter in an invalid state.
+  if (async_filter_ && async_filter_->has_activation_state())
+    return async_filter_.get();
+  return nullptr;
+}
+
 // Ensure the caller cannot take ownership of a subresource filter for cases
 // when activation IPCs are not sent to the render process.
 std::unique_ptr<AsyncDocumentSubresourceFilter>
diff --git a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
index 7850de3d..0cee864 100644
--- a/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
+++ b/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
@@ -69,16 +69,12 @@
   // frame.
   std::unique_ptr<AsyncDocumentSubresourceFilter> ReleaseFilter();
 
-  AsyncDocumentSubresourceFilter* filter() { return async_filter_.get(); }
+  AsyncDocumentSubresourceFilter* filter() const;
 
   void WillSendActivationToRenderer();
 
  private:
   void OnActivationStateComputed(ActivationState state);
-  void set_filter(
-      std::unique_ptr<AsyncDocumentSubresourceFilter> async_filter) {
-    async_filter_ = std::move(async_filter);
-  }
 
   ActivationStateComputingNavigationThrottle(
       content::NavigationHandle* navigation_handle,
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.h b/components/subresource_filter/content/browser/async_document_subresource_filter.h
index fa607e8..1c3b511 100644
--- a/components/subresource_filter/content/browser/async_document_subresource_filter.h
+++ b/components/subresource_filter/content/browser/async_document_subresource_filter.h
@@ -116,6 +116,8 @@
   // Must be called after activation state computation is finished.
   const ActivationState& activation_state() const;
 
+  bool has_activation_state() const { return activation_state_.has_value(); }
+
   // The |first_disallowed_load_callback|, if it is non-null, is invoked on the
   // first ReportDisallowedLoad() call.
   void set_first_disallowed_load_callback(base::OnceClosure callback) {
diff --git a/components/sync/syncable/directory_backing_store.cc b/components/sync/syncable/directory_backing_store.cc
index 677ffc5..17fa7b9 100644
--- a/components/sync/syncable/directory_backing_store.cc
+++ b/components/sync/syncable/directory_backing_store.cc
@@ -39,6 +39,61 @@
 namespace syncer {
 namespace syncable {
 
+// Must be in exact same order as fields in entry_kernel.h.
+const ColumnSpec g_metas_columns[] = {
+    //////////////////////////////////////
+    // int64s
+    {"metahandle", "bigint primary key ON CONFLICT FAIL"},
+    {"base_version", "bigint default " CHANGES_VERSION_STRING},
+    {"server_version", "bigint default 0"},
+    // This is the item ID that we store for the embedding application.
+    {"local_external_id", "bigint default 0"},
+    {"transaction_version", "bigint default 0"},
+    // These timestamps are kept in the same format as that of the
+    // protocol (ms since Unix epoch).
+    {"mtime", "bigint default 0"},
+    {"server_mtime", "bigint default 0"},
+    {"ctime", "bigint default 0"},
+    {"server_ctime", "bigint default 0"},
+    //////////////////////////////////////
+    // Ids
+    {"id", "varchar(255) default \"r\""},
+    {"parent_id", "varchar(255) default \"r\""},
+    {"server_parent_id", "varchar(255) default \"r\""},
+    //////////////////////////////////////
+    // bits
+    {"is_unsynced", "bit default 0"},
+    {"is_unapplied_update", "bit default 0"},
+    {"is_del", "bit default 0"},
+    {"is_dir", "bit default 0"},
+    {"server_is_dir", "bit default 0"},
+    {"server_is_del", "bit default 0"},
+    //////////////////////////////////////
+    // Strings
+    {"non_unique_name", "varchar"},
+    {"server_non_unique_name", "varchar(255)"},
+    {"unique_server_tag", "varchar"},
+    {"unique_client_tag", "varchar"},
+    {"unique_bookmark_tag", "varchar"},
+    //////////////////////////////////////
+    // Blobs (serialized protos).
+    {"specifics", "blob"},
+    {"server_specifics", "blob"},
+    {"base_server_specifics", "blob"},
+    //////////////////////////////////////
+    // Blobs (positions).
+    {"server_unique_position", "blob"},
+    {"unique_position", "blob"},
+    //////////////////////////////////////
+    // AttachmentMetadata is a proto that contains all the metadata associated
+    // with an entry's attachments.  Each entry has only one AttachmentMetadata
+    // proto.  We store a single proto per entry (as opposed to one for each
+    // attachment) because it simplifies the database schema and implementation
+    // of
+    // DirectoryBackingStore.
+    {"attachment_metadata", "blob"},
+    {"server_attachment_metadata", "blob"}};
+
 // Increment this version whenever updating DB tables.
 const int32_t kCurrentDBVersion = 91;
 
@@ -205,6 +260,8 @@
 string ComposeCreateTableColumnSpecs() {
   const ColumnSpec* begin = g_metas_columns;
   const ColumnSpec* end = g_metas_columns + arraysize(g_metas_columns);
+  // Verify that the array was fully initialized.
+  DCHECK(g_metas_columns[arraysize(g_metas_columns) - 1].name != nullptr);
   string query;
   query.reserve(kUpdateStatementBufferSize);
   char separator = '(';
diff --git a/components/sync/syncable/entry_kernel.h b/components/sync/syncable/entry_kernel.h
index fa57de9..fbaac41 100644
--- a/components/sync/syncable/entry_kernel.h
+++ b/components/sync/syncable/entry_kernel.h
@@ -174,6 +174,7 @@
 enum {
   ATTACHMENT_METADATA_FIELDS_COUNT =
       ATTACHMENT_METADATA_FIELDS_END - ATTACHMENT_METADATA_FIELDS_BEGIN,
+  // If FIELD_COUNT is changed then g_metas_columns must be updated.
   FIELD_COUNT = ATTACHMENT_METADATA_FIELDS_END - BEGIN_FIELDS,
   // Past this point we have temporaries, stored in memory only.
   BEGIN_TEMPS = ATTACHMENT_METADATA_FIELDS_END,
diff --git a/components/sync/syncable/syncable_columns.h b/components/sync/syncable/syncable_columns.h
index 23b1871..4f29f21 100644
--- a/components/sync/syncable/syncable_columns.h
+++ b/components/sync/syncable/syncable_columns.h
@@ -17,67 +17,10 @@
   const char* spec;
 };
 
-// Must be in exact same order as fields in entry_kernel.h.
-static const ColumnSpec g_metas_columns[] = {
-    //////////////////////////////////////
-    // int64s
-    {"metahandle", "bigint primary key ON CONFLICT FAIL"},
-    {"base_version", "bigint default " CHANGES_VERSION_STRING},
-    {"server_version", "bigint default 0"},
-    // This is the item ID that we store for the embedding application.
-    {"local_external_id", "bigint default 0"},
-    {"transaction_version", "bigint default 0"},
-    // These timestamps are kept in the same format as that of the
-    // protocol (ms since Unix epoch).
-    {"mtime", "bigint default 0"},
-    {"server_mtime", "bigint default 0"},
-    {"ctime", "bigint default 0"},
-    {"server_ctime", "bigint default 0"},
-    //////////////////////////////////////
-    // Ids
-    {"id", "varchar(255) default \"r\""},
-    {"parent_id", "varchar(255) default \"r\""},
-    {"server_parent_id", "varchar(255) default \"r\""},
-    //////////////////////////////////////
-    // bits
-    {"is_unsynced", "bit default 0"},
-    {"is_unapplied_update", "bit default 0"},
-    {"is_del", "bit default 0"},
-    {"is_dir", "bit default 0"},
-    {"server_is_dir", "bit default 0"},
-    {"server_is_del", "bit default 0"},
-    //////////////////////////////////////
-    // Strings
-    {"non_unique_name", "varchar"},
-    {"server_non_unique_name", "varchar(255)"},
-    {"unique_server_tag", "varchar"},
-    {"unique_client_tag", "varchar"},
-    {"unique_bookmark_tag", "varchar"},
-    //////////////////////////////////////
-    // Blobs (serialized protos).
-    {"specifics", "blob"},
-    {"server_specifics", "blob"},
-    {"base_server_specifics", "blob"},
-    //////////////////////////////////////
-    // Blobs (positions).
-    {"server_unique_position", "blob"},
-    {"unique_position", "blob"},
-    //////////////////////////////////////
-    // AttachmentMetadata is a proto that contains all the metadata associated
-    // with an entry's attachments.  Each entry has only one AttachmentMetadata
-    // proto.  We store a single proto per entry (as opposed to one for each
-    // attachment) because it simplifies the database schema and implementation
-    // of
-    // DirectoryBackingStore.
-    {"attachment_metadata", "blob"},
-    {"server_attachment_metadata", "blob"}};
-
-// At least enforce that there are equal number of column names and fields.
-static_assert(arraysize(g_metas_columns) >= FIELD_COUNT, "missing column name");
-static_assert(arraysize(g_metas_columns) <= FIELD_COUNT, "extra column names");
+extern const ColumnSpec g_metas_columns[FIELD_COUNT];
 
 static inline const char* ColumnName(int field) {
-  DCHECK(field < BEGIN_TEMPS);
+  DCHECK(field >= 0 && field < BEGIN_TEMPS);
   return g_metas_columns[field].name;
 }
 
diff --git a/components/viz/client/client_shared_bitmap_manager.cc b/components/viz/client/client_shared_bitmap_manager.cc
index 2a35491..8c1d51a 100644
--- a/components/viz/client/client_shared_bitmap_manager.cc
+++ b/components/viz/client/client_shared_bitmap_manager.cc
@@ -24,24 +24,27 @@
 class ClientSharedBitmap : public SharedBitmap {
  public:
   ClientSharedBitmap(
-      scoped_refptr<
-          cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+      scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
           shared_bitmap_allocation_notifier,
       base::SharedMemory* shared_memory,
-      const SharedBitmapId& id)
-      : SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
+      const SharedBitmapId& id,
+      uint32_t sequence_number)
+      : SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()),
+                     id,
+                     sequence_number),
         shared_bitmap_allocation_notifier_(
             std::move(shared_bitmap_allocation_notifier)) {}
 
   ClientSharedBitmap(
-      scoped_refptr<
-          cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+      scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
           shared_bitmap_allocation_notifier,
       std::unique_ptr<base::SharedMemory> shared_memory_holder,
-      const SharedBitmapId& id)
+      const SharedBitmapId& id,
+      uint32_t sequence_number)
       : ClientSharedBitmap(std::move(shared_bitmap_allocation_notifier),
                            shared_memory_holder.get(),
-                           id) {
+                           id,
+                           sequence_number) {
     shared_memory_holder_ = std::move(shared_memory_holder);
   }
 
@@ -57,8 +60,7 @@
   }
 
  private:
-  scoped_refptr<
-      cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+  scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
       shared_bitmap_allocation_notifier_;
   std::unique_ptr<base::SharedMemory> shared_memory_holder_;
 };
@@ -110,8 +112,7 @@
 }  // namespace
 
 ClientSharedBitmapManager::ClientSharedBitmapManager(
-    scoped_refptr<
-        cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+    scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
         shared_bitmap_allocation_notifier)
     : shared_bitmap_allocation_notifier_(
           std::move(shared_bitmap_allocation_notifier)) {}
@@ -131,14 +132,15 @@
   if (!memory || !memory->Map(memory_size))
     CollectMemoryUsageAndDie(size, memory_size);
 
-  NotifyAllocatedSharedBitmap(memory.get(), id);
+  uint32_t sequence_number = NotifyAllocatedSharedBitmap(memory.get(), id);
 
   // Close the associated FD to save resources, the previously mapped memory
   // remains available.
   memory->Close();
 
   return base::MakeUnique<ClientSharedBitmap>(
-      shared_bitmap_allocation_notifier_, std::move(memory), id);
+      shared_bitmap_allocation_notifier_, std::move(memory), id,
+      sequence_number);
 }
 
 std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::GetSharedBitmapFromId(
@@ -151,28 +153,32 @@
 std::unique_ptr<SharedBitmap>
 ClientSharedBitmapManager::GetBitmapForSharedMemory(base::SharedMemory* mem) {
   SharedBitmapId id = SharedBitmap::GenerateId();
-  NotifyAllocatedSharedBitmap(mem, SharedBitmap::GenerateId());
+  uint32_t sequence_number = NotifyAllocatedSharedBitmap(mem, id);
   return base::MakeUnique<ClientSharedBitmap>(
-      shared_bitmap_allocation_notifier_, mem, id);
+      shared_bitmap_allocation_notifier_, mem, id, sequence_number);
 }
 
 // Notifies the browser process that a shared bitmap with the given ID was
 // allocated. Caller keeps ownership of |memory|.
-void ClientSharedBitmapManager::NotifyAllocatedSharedBitmap(
+uint32_t ClientSharedBitmapManager::NotifyAllocatedSharedBitmap(
     base::SharedMemory* memory,
     const SharedBitmapId& id) {
   base::SharedMemoryHandle handle_to_send =
       base::SharedMemory::DuplicateHandle(memory->handle());
   if (!base::SharedMemory::IsHandleValid(handle_to_send)) {
     LOG(ERROR) << "Failed to duplicate shared memory handle for bitmap.";
-    return;
+    return 0;
   }
 
   mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
       handle_to_send, memory->mapped_size(), true /* read_only */);
 
-  (*shared_bitmap_allocation_notifier_)
-      ->DidAllocateSharedBitmap(std::move(buffer_handle), id);
+  {
+    base::AutoLock lock(lock_);
+    (*shared_bitmap_allocation_notifier_)
+        ->DidAllocateSharedBitmap(std::move(buffer_handle), id);
+    return ++last_sequence_number_;
+  }
 }
 
 }  // namespace viz
diff --git a/components/viz/client/client_shared_bitmap_manager.h b/components/viz/client/client_shared_bitmap_manager.h
index 095c535..8bb479c 100644
--- a/components/viz/client/client_shared_bitmap_manager.h
+++ b/components/viz/client/client_shared_bitmap_manager.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/shared_memory.h"
+#include "base/synchronization/lock.h"
 #include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
 #include "components/viz/common/resources/shared_bitmap_manager.h"
 #include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
@@ -24,8 +25,7 @@
 class ClientSharedBitmapManager : public SharedBitmapManager {
  public:
   explicit ClientSharedBitmapManager(
-      scoped_refptr<
-          cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+      scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
           shared_bitmap_allocation_notifier);
   ~ClientSharedBitmapManager() override;
 
@@ -40,13 +40,18 @@
       base::SharedMemory* mem);
 
  private:
-  void NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
-                                   const SharedBitmapId& id);
+  uint32_t NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
+                                       const SharedBitmapId& id);
 
-  scoped_refptr<
-      cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr>
+  scoped_refptr<cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
       shared_bitmap_allocation_notifier_;
 
+  base::Lock lock_;
+
+  // Each SharedBitmap allocated by this class is assigned a unique sequence
+  // number that is incremental.
+  uint32_t last_sequence_number_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(ClientSharedBitmapManager);
 };
 
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index a0f0dc8..b074c74 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -13,6 +13,7 @@
     "gl_helper_readback_support.h",
     "gl_helper_scaling.cc",
     "gl_helper_scaling.h",
+    "hit_test/aggregated_hit_test_region.h",
     "quads/resource_format.h",
     "quads/shared_bitmap.cc",
     "quads/shared_bitmap.h",
@@ -51,6 +52,7 @@
     "//mojo/public/cpp/bindings",
     "//skia",
     "//ui/gfx:color_space",
+    "//ui/gfx:geometry_skia",
     "//ui/gfx/geometry",
   ]
 
diff --git a/components/viz/common/hit_test/DEPS b/components/viz/common/hit_test/DEPS
new file mode 100644
index 0000000..b49b863
--- /dev/null
+++ b/components/viz/common/hit_test/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+ui/gfx/geometry",
+  "+ui/gfx/transform.h",
+]
\ No newline at end of file
diff --git a/components/viz/common/hit_test/aggregated_hit_test_region.h b/components/viz/common/hit_test/aggregated_hit_test_region.h
new file mode 100644
index 0000000..b90bfb19
--- /dev/null
+++ b/components/viz/common/hit_test/aggregated_hit_test_region.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 COMPONENTS_VIZ_COMMON_HIT_TEST_AGGREGATED_HIT_TEST_REGION_H_
+#define COMPONENTS_VIZ_COMMON_HIT_TEST_AGGREGATED_HIT_TEST_REGION_H_
+
+#include <stdint.h>
+
+#include "components/viz/common/surfaces/surface_id.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/transform.h"
+
+namespace viz {
+
+// A AggregatedHitTestRegion element with child_count of kEndOfList indicates
+// the last element and end of the list.
+constexpr int kEndOfList = -1;
+
+// An array of AggregatedHitTestRegion elements is used to define the
+// aggregated hit-test data for the Display.
+//
+// It is designed to be in shared memory so that the viz service can
+// write the hit_test data, and the viz host can read without
+// process hops.
+struct AggregatedHitTestRegion {
+  // The FrameSinkId corresponding to this region.  Events that match
+  // are routed to this surface.
+  FrameSinkId frame_sink_id;
+
+  // Flags to indicate the type of region as defined for
+  // mojom::HitTestRegion
+  uint32_t flags;
+
+  // The rectangle that defines the region in parent region's coordinate space.
+  gfx::Rect rect;
+
+  // The transform applied to the rect in parent region's coordinate space.
+  gfx::Transform transform;
+
+  // The number of children including their children below this entry.
+  // If this element is not matched then child_count elements can be skipped
+  // to move to the next entry.
+  int child_count;
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_COMMON_HIT_TEST_AGGREGATED_HIT_TEST_REGION_H_
diff --git a/components/viz/common/quads/shared_bitmap.cc b/components/viz/common/quads/shared_bitmap.cc
index 9f78ee18..c17074b 100644
--- a/components/viz/common/quads/shared_bitmap.cc
+++ b/components/viz/common/quads/shared_bitmap.cc
@@ -16,8 +16,10 @@
 
 namespace viz {
 
-SharedBitmap::SharedBitmap(uint8_t* pixels, const SharedBitmapId& id)
-    : pixels_(pixels), id_(id) {}
+SharedBitmap::SharedBitmap(uint8_t* pixels,
+                           const SharedBitmapId& id,
+                           uint32_t sequence_number)
+    : pixels_(pixels), id_(id), sequence_number_(sequence_number) {}
 
 SharedBitmap::~SharedBitmap() {}
 
diff --git a/components/viz/common/quads/shared_bitmap.h b/components/viz/common/quads/shared_bitmap.h
index 9eb1d977..98e9cca 100644
--- a/components/viz/common/quads/shared_bitmap.h
+++ b/components/viz/common/quads/shared_bitmap.h
@@ -32,7 +32,9 @@
 
 class SharedBitmap {
  public:
-  SharedBitmap(uint8_t* pixels, const SharedBitmapId& id);
+  SharedBitmap(uint8_t* pixels,
+               const SharedBitmapId& id,
+               uint32_t sequence_number);
 
   virtual ~SharedBitmap();
 
@@ -40,6 +42,10 @@
 
   const SharedBitmapId& id() { return id_; }
 
+  // The sequence number that ClientSharedBitmapManager assigned to this
+  // SharedBitmap.
+  uint32_t sequence_number() const { return sequence_number_; }
+
   // Returns the shared memory's handle when the back end is base::SharedMemory.
   // Otherwise, this returns an invalid handle.
   virtual base::SharedMemoryHandle GetSharedMemoryHandle() const = 0;
@@ -60,6 +66,7 @@
  private:
   uint8_t* pixels_;
   SharedBitmapId id_;
+  const uint32_t sequence_number_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedBitmap);
 };
diff --git a/components/viz/host/host_frame_sink_manager_unittests.cc b/components/viz/host/host_frame_sink_manager_unittests.cc
index c4c6cbe6..6ee7cf7 100644
--- a/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -131,10 +131,10 @@
       nullptr /* client */, kFrameSinkId1, true /* is_root */,
       true /* handles_frame_sink_id_invalidation */,
       false /* needs_sync_points */);
-  EXPECT_TRUE(FrameSinkIdExists(support->frame_sink_id()));
+  EXPECT_TRUE(FrameSinkIdExists(kFrameSinkId1));
 
   support.reset();
-  EXPECT_FALSE(FrameSinkIdExists(support->frame_sink_id()));
+  EXPECT_FALSE(FrameSinkIdExists(kFrameSinkId1));
 }
 
 }  // namespace test
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 81c6075f..1edce15e 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -51,6 +51,8 @@
     "frame_sinks/gpu_compositor_frame_sink_delegate.h",
     "frame_sinks/gpu_root_compositor_frame_sink.cc",
     "frame_sinks/gpu_root_compositor_frame_sink.h",
+    "hit_test/hit_test_aggregator.cc",
+    "hit_test/hit_test_aggregator.h",
     "viz_service_export.h",
   ]
 
@@ -77,6 +79,7 @@
     "//cc/surfaces",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/ipc:command_buffer",
+    "//services/viz/hit_test/public/interfaces",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/latency",
@@ -127,6 +130,7 @@
     "frame_sinks/compositor_frame_sink_support_unittest.cc",
     "frame_sinks/direct_layer_tree_frame_sink_unittest.cc",
     "frame_sinks/frame_sink_manager_unittest.cc",
+    "hit_test/hit_test_aggregator_unittest.cc",
   ]
 
   if (!use_aura && !is_mac) {
@@ -144,6 +148,12 @@
     "//base/test:test_support",
     "//cc:test_support",
     "//components/viz/common",
+    "//gpu/command_buffer/client",
+    "//gpu/command_buffer/client:gles2_implementation",
+    "//gpu/ipc:gl_in_process_context",
+    "//media",
+    "//services/viz/hit_test/public/interfaces",
+    "//skia",
     "//testing/gmock",
     "//testing/gtest",
     "//ui/display/types",
diff --git a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
index adb493a..5f1f77b1 100644
--- a/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
+++ b/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -40,7 +40,7 @@
                      scoped_refptr<BitmapData> bitmap_data,
                      const SharedBitmapId& id,
                      ServerSharedBitmapManager* manager)
-      : SharedBitmap(pixels, id),
+      : SharedBitmap(pixels, id, 0 /* sequence_number */),
         bitmap_data_(bitmap_data),
         manager_(manager) {}
 
diff --git a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
index 0c667bd..d320a3d 100644
--- a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
+++ b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
@@ -11,31 +11,44 @@
 
 SharedBitmapAllocationNotifierImpl::SharedBitmapAllocationNotifierImpl(
     ServerSharedBitmapManager* manager)
-    : manager_(manager), binding_(this) {}
+    : manager_(manager), binding_(this) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
 
 SharedBitmapAllocationNotifierImpl::~SharedBitmapAllocationNotifierImpl() {
-  for (const auto& id : owned_bitmaps_)
-    manager_->ChildDeletedSharedBitmap(id);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  ChildDied();
 }
 
 void SharedBitmapAllocationNotifierImpl::Bind(
-    cc::mojom::SharedBitmapAllocationNotifierAssociatedRequest request) {
+    cc::mojom::SharedBitmapAllocationNotifierRequest request) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  if (binding_.is_bound()) {
+    DLOG(ERROR) << "Only one SharedBitmapAllocationNotifierRequest is "
+                << "expected from the renderer.";
+    return;
+  }
   binding_.Bind(std::move(request));
 }
 
 void SharedBitmapAllocationNotifierImpl::DidAllocateSharedBitmap(
     mojo::ScopedSharedBufferHandle buffer,
     const SharedBitmapId& id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   base::SharedMemoryHandle memory_handle;
   size_t size;
   MojoResult result = mojo::UnwrapSharedMemoryHandle(
       std::move(buffer), &memory_handle, &size, NULL);
   DCHECK_EQ(result, MOJO_RESULT_OK);
   this->ChildAllocatedSharedBitmap(size, memory_handle, id);
+  last_sequence_number_++;
+  for (SharedBitmapAllocationObserver& observer : observers_)
+    observer.DidAllocateSharedBitmap(last_sequence_number_);
 }
 
 void SharedBitmapAllocationNotifierImpl::DidDeleteSharedBitmap(
     const SharedBitmapId& id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   manager_->ChildDeletedSharedBitmap(id);
   owned_bitmaps_.erase(id);
 }
@@ -44,8 +57,29 @@
     size_t buffer_size,
     const base::SharedMemoryHandle& handle,
     const SharedBitmapId& id) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (manager_->ChildAllocatedSharedBitmap(buffer_size, handle, id))
     owned_bitmaps_.insert(id);
 }
 
+void SharedBitmapAllocationNotifierImpl::ChildDied() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  for (const auto& id : owned_bitmaps_)
+    manager_->ChildDeletedSharedBitmap(id);
+  owned_bitmaps_.clear();
+  binding_.Close();
+}
+
+void SharedBitmapAllocationNotifierImpl::AddObserver(
+    SharedBitmapAllocationObserver* observer) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  observers_.AddObserver(observer);
+}
+
+void SharedBitmapAllocationNotifierImpl::RemoveObserver(
+    SharedBitmapAllocationObserver* observer) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  observers_.RemoveObserver(observer);
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
index c807b55f..4e9330a 100644
--- a/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
+++ b/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
@@ -7,14 +7,21 @@
 
 #include <unordered_set>
 
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
 #include "cc/ipc/shared_bitmap_allocation_notifier.mojom.h"
 #include "components/viz/common/quads/shared_bitmap.h"
 #include "components/viz/service/viz_service_export.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/binding.h"
 
 namespace viz {
 class ServerSharedBitmapManager;
 
+class SharedBitmapAllocationObserver {
+ public:
+  virtual void DidAllocateSharedBitmap(uint32_t sequence_number) = 0;
+};
+
 class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl
     : NON_EXPORTED_BASE(public cc::mojom::SharedBitmapAllocationNotifier) {
  public:
@@ -23,7 +30,10 @@
 
   ~SharedBitmapAllocationNotifierImpl() override;
 
-  void Bind(cc::mojom::SharedBitmapAllocationNotifierAssociatedRequest request);
+  void AddObserver(SharedBitmapAllocationObserver* observer);
+  void RemoveObserver(SharedBitmapAllocationObserver* observer);
+
+  void Bind(cc::mojom::SharedBitmapAllocationNotifierRequest request);
 
   // cc::mojom::SharedBitmapAllocationNotifier overrides:
   void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
@@ -34,10 +44,17 @@
                                   const base::SharedMemoryHandle& handle,
                                   const SharedBitmapId& id);
 
+  void ChildDied();
+
+  uint32_t last_sequence_number() const { return last_sequence_number_; }
+
  private:
+  THREAD_CHECKER(thread_checker_);
   ServerSharedBitmapManager* const manager_;
-  mojo::AssociatedBinding<cc::mojom::SharedBitmapAllocationNotifier> binding_;
+  mojo::Binding<cc::mojom::SharedBitmapAllocationNotifier> binding_;
   std::unordered_set<SharedBitmapId, SharedBitmapIdHash> owned_bitmaps_;
+  base::ObserverList<SharedBitmapAllocationObserver> observers_;
+  uint32_t last_sequence_number_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(SharedBitmapAllocationNotifierImpl);
 };
diff --git a/components/viz/service/hit_test/DEPS b/components/viz/service/hit_test/DEPS
new file mode 100644
index 0000000..e207341
--- /dev/null
+++ b/components/viz/service/hit_test/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+  "+components/viz/common",
+  "+cc/surfaces/surface_observer.h",
+  "+services/viz/hit_test/public/interfaces",
+]
diff --git a/components/viz/service/hit_test/OWNERS b/components/viz/service/hit_test/OWNERS
new file mode 100644
index 0000000..3940e4c
--- /dev/null
+++ b/components/viz/service/hit_test/OWNERS
@@ -0,0 +1 @@
+rjkroege@chromium.org
\ No newline at end of file
diff --git a/components/viz/service/hit_test/hit_test_aggregator.cc b/components/viz/service/hit_test/hit_test_aggregator.cc
new file mode 100644
index 0000000..fbd4751
--- /dev/null
+++ b/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -0,0 +1,212 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/hit_test/hit_test_aggregator.h"
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+
+namespace viz {
+
+namespace {
+// TODO(gklassen): Review and select appropriate sizes based on
+// telemetry / UMA.
+constexpr int kInitialSize = 1024;
+constexpr int kIncrementalSize = 1024;
+constexpr int kMaxRegionsPerSurface = 1024;
+constexpr int kMaxSize = 100 * 1024;
+
+bool ValidateHitTestRegion(const mojom::HitTestRegionPtr& hit_test_region) {
+  if (hit_test_region->flags == mojom::kHitTestChildSurface) {
+    if (!hit_test_region->surface_id.is_valid())
+      return false;
+  }
+
+  return true;
+}
+
+bool ValidateHitTestRegionList(
+    const mojom::HitTestRegionListPtr& hit_test_region_list) {
+  if (hit_test_region_list->regions.size() > kMaxRegionsPerSurface)
+    return false;
+  for (auto& region : hit_test_region_list->regions) {
+    if (!ValidateHitTestRegion(region))
+      return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+HitTestAggregator::HitTestAggregator() : weak_ptr_factory_(this) {
+  AllocateHitTestRegionArray();
+}
+
+HitTestAggregator::~HitTestAggregator() = default;
+
+void HitTestAggregator::SubmitHitTestRegionList(
+    mojom::HitTestRegionListPtr hit_test_region_list) {
+  DCHECK(ValidateHitTestRegionList(hit_test_region_list));
+  // TODO(gklassen): Runtime validation that hit_test_region_list is valid.
+  // TODO(gklassen): Inform FrameSink that the hit_test_region_list is invalid.
+  // TODO(gklassen): FrameSink needs to inform the host of a difficult renderer.
+  pending_[hit_test_region_list->surface_id] = std::move(hit_test_region_list);
+}
+
+bool HitTestAggregator::OnSurfaceDamaged(const SurfaceId& surface_id,
+                                         const cc::BeginFrameAck& ack) {
+  return false;
+}
+
+void HitTestAggregator::OnSurfaceDiscarded(const SurfaceId& surface_id) {
+  // Update the region count.
+  auto active_search = active_.find(surface_id);
+  if (active_search != active_.end()) {
+    mojom::HitTestRegionList* old_hit_test_data = active_search->second.get();
+    active_region_count_ -= old_hit_test_data->regions.size();
+  }
+  DCHECK_GE(active_region_count_, 0);
+
+  pending_.erase(surface_id);
+  active_.erase(surface_id);
+}
+
+void HitTestAggregator::OnSurfaceWillDraw(const SurfaceId& surface_id) {
+  auto pending_search = pending_.find(surface_id);
+  if (pending_search == pending_.end()) {
+    // Have already activated pending hit_test_region_list objects for this
+    // surface.
+    return;
+  }
+  mojom::HitTestRegionList* hit_test_region_list = pending_search->second.get();
+
+  // Update the region count.
+  auto active_search = active_.find(surface_id);
+  if (active_search != active_.end()) {
+    mojom::HitTestRegionList* old_hit_test_data = active_search->second.get();
+    active_region_count_ -= old_hit_test_data->regions.size();
+  }
+  active_region_count_ += hit_test_region_list->regions.size();
+  DCHECK_GE(active_region_count_, 0);
+
+  active_[surface_id] = std::move(pending_[surface_id]);
+  pending_.erase(surface_id);
+}
+
+void HitTestAggregator::AllocateHitTestRegionArray() {
+  AllocateHitTestRegionArray(kInitialSize);
+  Swap();
+  AllocateHitTestRegionArray(kInitialSize);
+}
+
+void HitTestAggregator::AllocateHitTestRegionArray(int size) {
+  size_t num_bytes = size * sizeof(AggregatedHitTestRegion);
+  write_handle_ = mojo::SharedBufferHandle::Create(num_bytes);
+  write_size_ = size;
+  write_buffer_ = write_handle_->Map(num_bytes);
+
+  AggregatedHitTestRegion* region =
+      (AggregatedHitTestRegion*)write_buffer_.get();
+  region[0].child_count = kEndOfList;
+}
+
+void HitTestAggregator::PostTaskAggregate(SurfaceId display_surface_id) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&HitTestAggregator::Aggregate,
+                     weak_ptr_factory_.GetWeakPtr(), display_surface_id));
+}
+
+void HitTestAggregator::Aggregate(SurfaceId display_surface_id) {
+  // Check to ensure that enough memory has been allocated.
+  int size = write_size_;
+  int max_size = active_region_count_ + active_.size() + 1;
+  if (max_size > kMaxSize)
+    max_size = kMaxSize;
+
+  if (max_size > size) {
+    size = (1 + max_size / kIncrementalSize) * kIncrementalSize;
+    AllocateHitTestRegionArray(size);
+  }
+
+  AppendRoot(display_surface_id);
+}
+
+void HitTestAggregator::AppendRoot(SurfaceId surface_id) {
+  auto search = active_.find(surface_id);
+  DCHECK(search != active_.end());
+
+  mojom::HitTestRegionList* hit_test_region_list = search->second.get();
+
+  AggregatedHitTestRegion* regions =
+      static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
+
+  regions[0].frame_sink_id = hit_test_region_list->surface_id.frame_sink_id();
+  regions[0].flags = hit_test_region_list->flags;
+  regions[0].rect = hit_test_region_list->bounds;
+  regions[0].transform = hit_test_region_list->transform;
+
+  int region_index = 1;
+  for (const auto& region : hit_test_region_list->regions) {
+    if (region_index >= write_size_ - 1)
+      break;
+    region_index = AppendRegion(regions, region_index, region);
+  }
+
+  DCHECK_GE(region_index, 1);
+  regions[0].child_count = region_index - 1;
+  regions[region_index].child_count = kEndOfList;
+}
+
+int HitTestAggregator::AppendRegion(AggregatedHitTestRegion* regions,
+                                    int region_index,
+                                    const mojom::HitTestRegionPtr& region) {
+  AggregatedHitTestRegion* element = &regions[region_index];
+
+  element->frame_sink_id = region->surface_id.frame_sink_id();
+  element->flags = region->flags;
+  element->rect = region->rect;
+  element->transform = region->transform;
+
+  int parent_index = region_index++;
+  if (region_index >= write_size_ - 1) {
+    element->child_count = 0;
+    return region_index;
+  }
+
+  if (region->flags == mojom::kHitTestChildSurface) {
+    auto search = active_.find(region->surface_id);
+    if (search == active_.end()) {
+      // Surface HitTestRegionList not found - it may be late.
+      // Don't include this region so that it doesn't receive events.
+      return parent_index;
+    }
+
+    // Rather than add a node in the tree for this hit_test_region_list element
+    // we can simplify the tree by merging the flags and transform into
+    // the kHitTestChildSurface element.
+    mojom::HitTestRegionList* hit_test_region_list = search->second.get();
+    if (!hit_test_region_list->transform.IsIdentity())
+      element->transform.PreconcatTransform(hit_test_region_list->transform);
+
+    element->flags |= hit_test_region_list->flags;
+
+    for (const auto& child_region : hit_test_region_list->regions) {
+      region_index = AppendRegion(regions, region_index, child_region);
+      if (region_index >= write_size_ - 1)
+        break;
+    }
+  }
+  DCHECK_GE(region_index - parent_index - 1, 0);
+  element->child_count = region_index - parent_index - 1;
+  return region_index;
+}
+
+void HitTestAggregator::Swap() {
+  using std::swap;
+
+  swap(read_handle_, write_handle_);
+  swap(read_size_, write_size_);
+  swap(read_buffer_, write_buffer_);
+}
+
+}  // namespace viz
diff --git a/components/viz/service/hit_test/hit_test_aggregator.h b/components/viz/service/hit_test/hit_test_aggregator.h
new file mode 100644
index 0000000..2977c37
--- /dev/null
+++ b/components/viz/service/hit_test/hit_test_aggregator.h
@@ -0,0 +1,107 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_H_
+#define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_H_
+
+#include "cc/surfaces/surface_observer.h"
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/viz_service_export.h"
+#include "services/viz/hit_test/public/interfaces/hit_test_region_list.mojom.h"
+
+namespace viz {
+
+// HitTestAggregator collects HitTestRegionList objects from surfaces and
+// aggregates them into a DisplayHitTesData structue made available in
+// shared memory to enable efficient hit testing across processes.
+//
+// This is intended to be created in the viz or GPU process. For mus+ash this
+// will be true after the mus process split.
+class VIZ_SERVICE_EXPORT HitTestAggregator : public cc::SurfaceObserver {
+ public:
+  HitTestAggregator();
+  ~HitTestAggregator();
+
+  // Called when HitTestRegionList is submitted along with every call
+  // to SubmitCompositorFrame.  This is collected in pending_ until
+  // surfaces are aggregated and put on the display.
+  void SubmitHitTestRegionList(
+      mojom::HitTestRegionListPtr hit_test_region_list);
+
+  // Called after surfaces have been aggregated into the DisplayFrame.
+  // In this call HitTestRegionList structures received from active surfaces
+  // are aggregated into the HitTestRegionList structure in
+  // shared memory used for event targetting.
+  void Aggregate(SurfaceId display_surface_id);
+
+  // Performs the work of Aggregate by creating a PostTask so that
+  // the work is not directly on the call.
+  void PostTaskAggregate(SurfaceId display_surface_id);
+
+  // Called at BeginFrame. Swaps buffers in shared memory.
+  void Swap();
+
+ protected:
+  // cc::SurfaceObserver:
+  void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+  void OnSurfaceDestroyed(const SurfaceId& surface_id) override {}
+  bool OnSurfaceDamaged(const SurfaceId& surface_id,
+                        const cc::BeginFrameAck& ack) override;
+  void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
+  void OnSurfaceDamageExpected(const SurfaceId& surface_id,
+                               const cc::BeginFrameArgs& args) override {}
+
+  // Called when a surface has been aggregated and added to the
+  // display frame.  HitTestRegionList objects are held but ignored until
+  // this happens.  HitTestRegionList for the surface is copied from |pending_|
+  // to |active_| in this method.
+  void OnSurfaceWillDraw(const SurfaceId& surface_id) override;
+
+  // The collection of received HitTestRegionList objects that have not yet
+  // been added to the DisplayFrame (OnSurfaceWillDraw has not been called).
+  std::map<SurfaceId, mojom::HitTestRegionListPtr> pending_;
+
+  // The collection of HitTestRegionList objects that have been added to the
+  // DisplayFrame (OnSurfaceWillDraw has been called).
+  std::map<SurfaceId, mojom::HitTestRegionListPtr> active_;
+
+  // Keeps track of the number of regions in the active list
+  // so that we know when we exceed the available length.
+  int active_region_count_ = 0;
+
+  mojo::ScopedSharedBufferHandle read_handle_;
+  mojo::ScopedSharedBufferHandle write_handle_;
+
+  // The number of elements allocated.
+  int read_size_ = 0;
+  int write_size_ = 0;
+
+  mojo::ScopedSharedBufferMapping read_buffer_;
+  mojo::ScopedSharedBufferMapping write_buffer_;
+
+ private:
+  // Allocates memory for the AggregatedHitTestRegion array.
+  void AllocateHitTestRegionArray();
+  void AllocateHitTestRegionArray(int length);
+
+  // Appends the root element to the AggregatedHitTestRegion array.
+  void AppendRoot(SurfaceId surface_id);
+
+  // Appends a region to the HitTestRegionList structure to recursively
+  // build the tree.
+  int AppendRegion(AggregatedHitTestRegion* regions,
+                   int region_index,
+                   const mojom::HitTestRegionPtr& region);
+
+  // Handles the case when this object is deleted after
+  // the PostTaskAggregation call is scheduled but before invocation.
+  base::WeakPtrFactory<HitTestAggregator> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(HitTestAggregator);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_H_
diff --git a/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
new file mode 100644
index 0000000..4a23b4d
--- /dev/null
+++ b/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -0,0 +1,1017 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/hit_test/hit_test_aggregator.h"
+
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/surfaces/local_surface_id.h"
+#include "components/viz/common/surfaces/surface_id.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+
+namespace {
+
+constexpr FrameSinkId kDisplayFrameSink(2, 0);
+
+SurfaceId MakeSurfaceId(const FrameSinkId& frame_sink_id, uint32_t local_id) {
+  return SurfaceId(
+      frame_sink_id,
+      LocalSurfaceId(local_id, base::UnguessableToken::Deserialize(0, 1u)));
+}
+
+}  // namespace
+
+class TestHitTestAggregator : public HitTestAggregator {
+ public:
+  TestHitTestAggregator() = default;
+  ~TestHitTestAggregator() = default;
+
+  void CallOnSurfaceWillDraw(SurfaceId surface_id) {
+    OnSurfaceWillDraw(surface_id);
+  }
+  void CallOnSurfaceDiscarded(SurfaceId surface_id) {
+    OnSurfaceDiscarded(surface_id);
+  }
+
+  int Count() {
+    AggregatedHitTestRegion* start =
+        static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
+    AggregatedHitTestRegion* end = start;
+    while (end->child_count != kEndOfList)
+      end++;
+
+    int count = end - start;
+    return count;
+  }
+  int GetPendingCount() { return pending_.size(); }
+  int GetActiveCount() { return active_.size(); }
+  int GetActiveRegionCount() { return active_region_count_; }
+  int GetHitTestRegionListSize() { return read_size_; }
+  AggregatedHitTestRegion* GetRegions() {
+    return static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
+  }
+
+  void Reset() {
+    AggregatedHitTestRegion* regions =
+        static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
+    regions[0].child_count = kEndOfList;
+
+    regions = static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
+    regions[0].child_count = kEndOfList;
+
+    pending_.clear();
+    active_.clear();
+  }
+};
+
+class HitTestAggregatorTest : public testing::Test {
+ public:
+  HitTestAggregatorTest() = default;
+  ~HitTestAggregatorTest() override = default;
+
+  // testing::Test:
+  void SetUp() override {}
+  void TearDown() override { aggregator_.Reset(); }
+
+  TestHitTestAggregator aggregator_;
+
+  // Creates a hit test data element with 8 children recursively to
+  // the specified depth.  SurfaceIds are generated in sequential order and
+  // the method returns the next unused id.
+  int CreateAndSubmitHitTestRegionListWith8Children(int id, int depth) {
+    SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, id);
+    id++;
+
+    auto hit_test_region_list = mojom::HitTestRegionList::New();
+    hit_test_region_list->surface_id = surface_id;
+    hit_test_region_list->flags = mojom::kHitTestMine;
+    hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+
+    for (int i = 0; i < 8; i++) {
+      auto hit_test_region = mojom::HitTestRegion::New();
+      hit_test_region->rect.SetRect(100, 100, 100, 100);
+
+      if (depth > 0) {
+        hit_test_region->flags = mojom::kHitTestChildSurface;
+        hit_test_region->surface_id = MakeSurfaceId(kDisplayFrameSink, id);
+        id = CreateAndSubmitHitTestRegionListWith8Children(id, depth - 1);
+      } else {
+        hit_test_region->flags = mojom::kHitTestMine;
+      }
+      hit_test_region_list->regions.push_back(std::move(hit_test_region));
+    }
+
+    aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list));
+    return id;
+  }
+};
+
+// TODO(gklassen): Add tests for 3D use cases as suggested by and with
+// input from rjkroege.
+
+// One surface.
+//
+//  +----------+
+//  |          |
+//  |          |
+//  |          |
+//  +----------+
+//
+TEST_F(HitTestAggregatorTest, OneSurface) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+
+  auto hit_test_region_list = mojom::HitTestRegionList::New();
+  hit_test_region_list->surface_id = display_surface_id;
+  hit_test_region_list->flags = mojom::kHitTestMine;
+  hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+
+  aggregator_.SubmitHitTestRegionList(std::move(hit_test_region_list));
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(display_surface_id);
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.Aggregate(display_surface_id);
+  aggregator_.Swap();
+
+  // Expect 1 entry routing all events to the one surface (display root).
+  EXPECT_EQ(1, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(display_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// One opaque embedder with two regions.
+//
+//  +e-------------+
+//  | +r1-+ +r2--+ |
+//  | |   | |    | |
+//  | |   | |    | |
+//  | +---+ +----+ |
+//  +--------------+
+//
+TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_r1 = mojom::HitTestRegion::New();
+  e_hit_test_region_r1->flags = mojom::kHitTestMine;
+  e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400);
+
+  auto e_hit_test_region_r2 = mojom::HitTestRegion::New();
+  e_hit_test_region_r2->flags = mojom::kHitTestMine;
+  e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r1));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_r2));
+
+  // Submit mojom::HitTestRegionList.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  // Add Surfaces to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+  EXPECT_EQ(3, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(gfx::Rect(100, 100, 200, 400), region->rect);
+  EXPECT_EQ(0, region->child_count);
+
+  region = &regions[2];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(gfx::Rect(400, 100, 300, 400), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// One embedder with two children.
+//
+//  +e-------------+
+//  | +c1-+ +c2--+ |
+//  | |   | |    | |
+//  | |   | |    | |
+//  | +---+ +----+ |
+//  +--------------+
+//
+
+TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+  SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
+  e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c1->surface_id = c1_surface_id;
+  e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300);
+
+  auto e_hit_test_region_c2 = mojom::HitTestRegion::New();
+  e_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c2->surface_id = c2_surface_id;
+  e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c2));
+
+  auto c1_hit_test_data = mojom::HitTestRegionList::New();
+  c1_hit_test_data->surface_id = c1_surface_id;
+
+  auto c2_hit_test_data = mojom::HitTestRegionList::New();
+  c2_hit_test_data->surface_id = c2_surface_id;
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data));
+  EXPECT_EQ(3, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c2_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c1_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(3, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(3, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(mojom::kHitTestChildSurface, region->flags);
+  EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 200, 300), region->rect);
+  EXPECT_EQ(0, region->child_count);
+
+  region = &regions[2];
+  EXPECT_EQ(mojom::kHitTestChildSurface, region->flags);
+  EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(400, 100, 400, 300), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// Occluded child frame (OOPIF).
+//
+//  +e-----------+
+//  | +c--+      |
+//  | | +div-+   |
+//  | | |    |   |
+//  | | +----+   |
+//  | +---+      |
+//  +------------+
+//
+
+TEST_F(HitTestAggregatorTest, OccludedChildFrame) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_div = mojom::HitTestRegion::New();
+  e_hit_test_region_div->flags = mojom::kHitTestMine;
+  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+
+  auto e_hit_test_region_c = mojom::HitTestRegion::New();
+  e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+
+  auto c_hit_test_data = mojom::HitTestRegionList::New();
+  c_hit_test_data->surface_id = c_surface_id;
+  c_hit_test_data->flags = mojom::kHitTestMine;
+  c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(3, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
+  EXPECT_EQ(0, region->child_count);
+
+  region = &regions[2];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 200, 500), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// Foreground child frame (OOPIF).
+// Same as the previous test except the child is foreground.
+//
+//  +e-----------+
+//  | +c--+      |
+//  | |   |div-+ |
+//  | |   |    | |
+//  | |   |----+ |
+//  | +---+      |
+//  +------------+
+//
+
+TEST_F(HitTestAggregatorTest, ForegroundChildFrame) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_div = mojom::HitTestRegion::New();
+  e_hit_test_region_div->flags = mojom::kHitTestMine;
+  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+
+  auto e_hit_test_region_c = mojom::HitTestRegion::New();
+  e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+
+  auto c_hit_test_data = mojom::HitTestRegionList::New();
+  c_hit_test_data->surface_id = c_surface_id;
+  c_hit_test_data->flags = mojom::kHitTestMine;
+  c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(3, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 200, 500), region->rect);
+  EXPECT_EQ(0, region->child_count);
+
+  region = &regions[2];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// One embedder with a clipped child with a tab and transparent background.
+//
+//  +e-------------+
+//  |   +c---------|     Point   maps to
+//  | 1 |+a--+     |     -----   -------
+//  |   || 2 |  3  |       1        e
+//  |   |+b--------|       2        a
+//  |   ||         |       3        e (transparent area in c)
+//  |   ||   4     |       4        b
+//  +--------------+
+//
+
+TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+  SurfaceId a_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
+  SurfaceId b_surface_id = MakeSurfaceId(kDisplayFrameSink, 4);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_c = mojom::HitTestRegion::New();
+  e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->rect.SetRect(200, 100, 1600, 800);
+  e_hit_test_region_c->transform.Translate(200, 100);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+
+  auto c_hit_test_data = mojom::HitTestRegionList::New();
+  c_hit_test_data->surface_id = c_surface_id;
+  c_hit_test_data->flags = mojom::kHitTestIgnore;
+  c_hit_test_data->bounds.SetRect(0, 0, 1600, 800);
+
+  auto c_hit_test_region_a = mojom::HitTestRegion::New();
+  c_hit_test_region_a->flags = mojom::kHitTestChildSurface;
+  c_hit_test_region_a->surface_id = a_surface_id;
+  c_hit_test_region_a->rect.SetRect(0, 0, 200, 100);
+
+  auto c_hit_test_region_b = mojom::HitTestRegion::New();
+  c_hit_test_region_b->flags = mojom::kHitTestChildSurface;
+  c_hit_test_region_b->surface_id = b_surface_id;
+  c_hit_test_region_b->rect.SetRect(0, 100, 800, 600);
+
+  c_hit_test_data->regions.push_back(std::move(c_hit_test_region_a));
+  c_hit_test_data->regions.push_back(std::move(c_hit_test_region_b));
+
+  auto a_hit_test_data = mojom::HitTestRegionList::New();
+  a_hit_test_data->surface_id = a_surface_id;
+  a_hit_test_data->flags = mojom::kHitTestMine;
+  a_hit_test_data->bounds.SetRect(0, 0, 200, 100);
+
+  auto b_hit_test_data = mojom::HitTestRegionList::New();
+  b_hit_test_data->surface_id = b_surface_id;
+  b_hit_test_data->flags = mojom::kHitTestMine;
+  b_hit_test_data->bounds.SetRect(0, 100, 800, 600);
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(a_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(b_hit_test_data));
+  EXPECT_EQ(3, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(4, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(b_surface_id);
+  EXPECT_EQ(3, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(a_surface_id);
+  EXPECT_EQ(4, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(4, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(3, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestIgnore);
+  EXPECT_EQ(c_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(200, 100, 1600, 800), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  gfx::Point point(300, 300);
+  region->transform.TransformPointReverse(&point);
+  EXPECT_TRUE(point == gfx::Point(100, 200));
+
+  region = &regions[2];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(a_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 200, 100), region->rect);
+  EXPECT_EQ(0, region->child_count);
+
+  region = &regions[3];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(b_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 100, 800, 600), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// Three children deep.
+//
+//  +e------------+
+//  | +c1-------+ |
+//  | | +c2---+ | |
+//  | | | +c3-| | |
+//  | | | |   | | |
+//  | | | +---| | |
+//  | | +-----+ | |
+//  | +---------+ |
+//  +-------------+
+//
+
+TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c1_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+  SurfaceId c2_surface_id = MakeSurfaceId(kDisplayFrameSink, 3);
+  SurfaceId c3_surface_id = MakeSurfaceId(kDisplayFrameSink, 4);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
+  e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c1->surface_id = c1_surface_id;
+  e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c1));
+
+  auto c1_hit_test_data = mojom::HitTestRegionList::New();
+  c1_hit_test_data->surface_id = c1_surface_id;
+  c1_hit_test_data->flags = mojom::kHitTestMine;
+  c1_hit_test_data->bounds.SetRect(0, 0, 600, 600);
+
+  auto c1_hit_test_region_c2 = mojom::HitTestRegion::New();
+  c1_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
+  c1_hit_test_region_c2->surface_id = c2_surface_id;
+  c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500);
+
+  c1_hit_test_data->regions.push_back(std::move(c1_hit_test_region_c2));
+
+  auto c2_hit_test_data = mojom::HitTestRegionList::New();
+  c2_hit_test_data->surface_id = c2_surface_id;
+  c2_hit_test_data->flags = mojom::kHitTestMine;
+  c2_hit_test_data->bounds.SetRect(0, 0, 400, 400);
+
+  auto c2_hit_test_region_c3 = mojom::HitTestRegion::New();
+  c2_hit_test_region_c3->flags = mojom::kHitTestChildSurface;
+  c2_hit_test_region_c3->surface_id = c3_surface_id;
+  c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300);
+
+  c2_hit_test_data->regions.push_back(std::move(c2_hit_test_region_c3));
+
+  auto c3_hit_test_data = mojom::HitTestRegionList::New();
+  c3_hit_test_data->surface_id = c3_surface_id;
+  c3_hit_test_data->flags = mojom::kHitTestMine;
+  c3_hit_test_data->bounds.SetRect(0, 0, 200, 200);
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c1_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c3_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(3, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c2_hit_test_data));
+  EXPECT_EQ(4, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c2_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c1_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(3, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c3_surface_id);
+  EXPECT_EQ(4, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(4, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(3, region->child_count);
+
+  region = &regions[1];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(c1_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 700, 700), region->rect);
+  EXPECT_EQ(2, region->child_count);
+
+  region = &regions[2];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(c2_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 500, 500), region->rect);
+  EXPECT_EQ(1, region->child_count);
+
+  region = &regions[3];
+  EXPECT_EQ(region->flags, mojom::kHitTestChildSurface | mojom::kHitTestMine);
+  EXPECT_EQ(c3_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(100, 100, 300, 300), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// Missing / late child.
+//
+//  +e-----------+
+//  | +c--+      |
+//  | |   |div-+ |
+//  | |   |    | |
+//  | |   |----+ |
+//  | +---+      |
+//  +------------+
+//
+
+TEST_F(HitTestAggregatorTest, MissingChildFrame) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_div = mojom::HitTestRegion::New();
+  e_hit_test_region_div->flags = mojom::kHitTestMine;
+  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+
+  auto e_hit_test_region_c = mojom::HitTestRegion::New();
+  e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+
+  auto c_hit_test_data = mojom::HitTestRegionList::New();
+  c_hit_test_data->surface_id = c_surface_id;
+  c_hit_test_data->flags = mojom::kHitTestMine;
+  c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+
+  // Submit in unexpected order, but not the child.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(2, aggregator_.Count());
+
+  AggregatedHitTestRegion* regions = aggregator_.GetRegions();
+
+  AggregatedHitTestRegion* region = nullptr;
+
+  region = &regions[0];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(0, 0, 1024, 768), region->rect);
+  EXPECT_EQ(1, region->child_count);
+
+  // Child would exist here but it was not included in the Display Frame.
+
+  region = &regions[1];
+  EXPECT_EQ(mojom::kHitTestMine, region->flags);
+  EXPECT_EQ(e_surface_id.frame_sink_id(), region->frame_sink_id);
+  EXPECT_EQ(gfx::Rect(200, 200, 300, 200), region->rect);
+  EXPECT_EQ(0, region->child_count);
+}
+
+// Exceed limits to ensure that bounds and resize work.
+//
+// A tree of embedders each with 8 children and 4 levels deep = 4096 regions.
+// This will exceed initial allocation and force a resize.
+//
+//  +e--------------------------------------------------------+
+//  | +c1----------++c2----------++c3----------++c4----------+|
+//  | | +c1--------|| +c1--------|| +c1--------|| +c1--------||
+//  | | | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-||
+//  | | | |   ||   || | |   ||   || | |   ||   || | |   ||   ||
+//  | | | +---++---|| | +---++---|| | +---++---|| | +---++---||
+//  | +------------++------------++------------++------------+|
+//  | +c5----------++c6----------++c7----------++c8----------+|
+//  | | +c1--------|| +c1--------|| +c1--------|| +c1--------||
+//  | | | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-|| | +c1-++c2-||
+//  | | | |   ||   || | |   ||   || | |   ||   || | |   ||   ||
+//  | | | +---++---|| | +---++---|| | +---++---|| | +---++---||
+//  | +------------++------------++------------++------------+|
+//  +---------------------------------------------------------+
+//
+
+TEST_F(HitTestAggregatorTest, ExceedLimits) {
+  EXPECT_EQ(0, aggregator_.Count());
+
+  EXPECT_LT(aggregator_.GetHitTestRegionListSize(), 4096);
+
+  SurfaceId display_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+
+  int next_surface_id = CreateAndSubmitHitTestRegionListWith8Children(1, 3);
+  int surface_count = next_surface_id - 1;
+
+  EXPECT_EQ(surface_count, aggregator_.GetPendingCount());
+
+  // Mark Surfaces as added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  for (int i = 1; i <= surface_count; i++) {
+    SurfaceId surface_id = MakeSurfaceId(kDisplayFrameSink, i);
+    aggregator_.CallOnSurfaceWillDraw(surface_id);
+  }
+
+  EXPECT_EQ(surface_count, aggregator_.GetActiveCount());
+
+  // Aggregate and swap.
+  aggregator_.Aggregate(display_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+
+  aggregator_.Swap();
+
+  // Expect 4680 regions:
+  //  8 children 4 levels deep 8*8*8*8 is  4096
+  //  1 region for each embedder/surface +  584
+  //  1 root                             +    1
+  //                                      -----
+  //                                       4681.
+  EXPECT_EQ(4681, aggregator_.Count());
+
+  EXPECT_GE(aggregator_.GetHitTestRegionListSize(), 4681);
+}
+
+TEST_F(HitTestAggregatorTest, ActiveRegionCount) {
+  EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+
+  SurfaceId e_surface_id = MakeSurfaceId(kDisplayFrameSink, 1);
+  SurfaceId c_surface_id = MakeSurfaceId(kDisplayFrameSink, 2);
+
+  auto e_hit_test_data = mojom::HitTestRegionList::New();
+  e_hit_test_data->surface_id = e_surface_id;
+  e_hit_test_data->flags = mojom::kHitTestMine;
+  e_hit_test_data->bounds.SetRect(0, 0, 1024, 768);
+
+  auto e_hit_test_region_div = mojom::HitTestRegion::New();
+  e_hit_test_region_div->flags = mojom::kHitTestMine;
+  e_hit_test_region_div->surface_id = e_surface_id;
+  e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+
+  auto e_hit_test_region_c = mojom::HitTestRegion::New();
+  e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
+  e_hit_test_region_c->surface_id = c_surface_id;
+  e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_c));
+  e_hit_test_data->regions.push_back(std::move(e_hit_test_region_div));
+
+  auto c_hit_test_data = mojom::HitTestRegionList::New();
+  c_hit_test_data->surface_id = c_surface_id;
+  c_hit_test_data->flags = mojom::kHitTestMine;
+  c_hit_test_data->bounds.SetRect(0, 0, 200, 500);
+
+  EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+
+  // Submit in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(c_hit_test_data));
+  EXPECT_EQ(1, aggregator_.GetPendingCount());
+
+  aggregator_.SubmitHitTestRegionList(std::move(e_hit_test_data));
+  EXPECT_EQ(2, aggregator_.GetPendingCount());
+
+  EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+
+  // Surfaces added to DisplayFrame in unexpected order.
+
+  EXPECT_EQ(0, aggregator_.Count());
+  EXPECT_EQ(0, aggregator_.GetActiveCount());
+
+  aggregator_.CallOnSurfaceWillDraw(e_surface_id);
+  EXPECT_EQ(1, aggregator_.GetActiveCount());
+  EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+
+  aggregator_.CallOnSurfaceWillDraw(c_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveCount());
+  EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+
+  // Aggregate and swap.
+
+  aggregator_.Aggregate(e_surface_id);
+  EXPECT_EQ(0, aggregator_.Count());
+  EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+
+  aggregator_.Swap();
+
+  EXPECT_EQ(3, aggregator_.Count());
+  EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+
+  // Discard Surface and ensure active count goes down.
+
+  aggregator_.CallOnSurfaceDiscarded(c_surface_id);
+  EXPECT_EQ(2, aggregator_.GetActiveRegionCount());
+
+  aggregator_.CallOnSurfaceDiscarded(e_surface_id);
+  EXPECT_EQ(0, aggregator_.GetActiveRegionCount());
+}
+
+}  // namespace viz
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 152d6e4..ec3b745 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -113,7 +113,9 @@
     "//services/data_decoder/public/cpp",
     "//services/data_decoder/public/interfaces",
     "//services/device:lib",
+    "//services/device/public/cpp:device_features",
     "//services/device/public/interfaces",
+    "//services/device/public/interfaces:generic_sensor",
     "//services/file:lib",
     "//services/file/public/interfaces",
     "//services/metrics/public/cpp:metrics_cpp",
@@ -611,7 +613,6 @@
     "dom_storage/session_storage_database_adapter.h",
     "dom_storage/session_storage_namespace_impl.cc",
     "dom_storage/session_storage_namespace_impl.h",
-    "download/all_download_item_notifier.cc",
     "download/base_file.cc",
     "download/base_file.h",
     "download/base_file_posix.cc",
@@ -1465,6 +1466,7 @@
     "speech/speech_recognizer.h",
     "speech/speech_recognizer_impl_android.cc",
     "speech/speech_recognizer_impl_android.h",
+    "ssl/ignore_errors_cert_verifier.cc",
     "ssl/ssl_client_auth_handler.cc",
     "ssl/ssl_client_auth_handler.h",
     "ssl/ssl_error_handler.cc",
diff --git a/content/browser/download/all_download_item_notifier.cc b/content/browser/download/all_download_item_notifier.cc
deleted file mode 100644
index 9385e4f..0000000
--- a/content/browser/download/all_download_item_notifier.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/public/browser/all_download_item_notifier.h"
-
-namespace content {
-
-AllDownloadItemNotifier::AllDownloadItemNotifier(
-    DownloadManager* manager,
-    AllDownloadItemNotifier::Observer* observer)
-    : manager_(manager), observer_(observer) {
-  DCHECK(observer_);
-  manager_->AddObserver(this);
-  DownloadManager::DownloadVector items;
-  manager_->GetAllDownloads(&items);
-  for (DownloadManager::DownloadVector::const_iterator it = items.begin();
-       it != items.end(); ++it) {
-    (*it)->AddObserver(this);
-    observing_.insert(*it);
-  }
-}
-
-AllDownloadItemNotifier::~AllDownloadItemNotifier() {
-  if (manager_)
-    manager_->RemoveObserver(this);
-  for (std::set<DownloadItem*>::const_iterator it = observing_.begin();
-       it != observing_.end(); ++it) {
-    (*it)->RemoveObserver(this);
-  }
-  observing_.clear();
-}
-
-void AllDownloadItemNotifier::ManagerGoingDown(DownloadManager* manager) {
-  DCHECK_EQ(manager_, manager);
-  manager_->RemoveObserver(this);
-  manager_ = NULL;
-}
-
-void AllDownloadItemNotifier::OnDownloadCreated(DownloadManager* manager,
-                                                DownloadItem* item) {
-  item->AddObserver(this);
-  observing_.insert(item);
-  observer_->OnDownloadCreated(manager, item);
-}
-
-void AllDownloadItemNotifier::OnDownloadUpdated(DownloadItem* item) {
-  observer_->OnDownloadUpdated(manager_, item);
-}
-
-void AllDownloadItemNotifier::OnDownloadOpened(DownloadItem* item) {
-  observer_->OnDownloadOpened(manager_, item);
-}
-
-void AllDownloadItemNotifier::OnDownloadRemoved(DownloadItem* item) {
-  observer_->OnDownloadRemoved(manager_, item);
-}
-
-void AllDownloadItemNotifier::OnDownloadDestroyed(DownloadItem* item) {
-  item->RemoveObserver(this);
-  observing_.erase(item);
-}
-
-}  // namespace content
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index ac1b31f..459f3ca 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -26,11 +26,6 @@
 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
 #include "url/url_constants.h"
 
-// For fine-grained suppression on flaky tests.
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 namespace content {
 
 namespace {
@@ -168,11 +163,6 @@
 #define MAYBE_NavigateWithLeftoverFrames NavigateWithLeftoverFrames
 #endif
 IN_PROC_BROWSER_TEST_F(FrameTreeBrowserTest, MAYBE_NavigateWithLeftoverFrames) {
-#if defined(OS_WIN)
-  // Flaky on XP bot http://crbug.com/468713
-  if (base::win::GetVersion() <= base::win::VERSION_XP)
-    return;
-#endif
   GURL base_url = embedded_test_server()->GetURL("A.com", "/site_isolation/");
 
   NavigateToURL(shell(),
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 32b79dc7..fba3353 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -116,6 +116,9 @@
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
+#include "services/device/public/cpp/device_features.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/device/public/interfaces/sensor_provider.mojom.h"
 #include "services/device/public/interfaces/wake_lock.mojom.h"
 #include "services/device/public/interfaces/wake_lock_context.mojom.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
@@ -348,16 +351,15 @@
     *rfph = RenderFrameProxyHost::FromID(process_id, routing_id);
 }
 
-// Forwards service requests to Service Manager since the renderer cannot launch
-// out-of-process services on its own.
-template <typename R>
-void ForwardShapeDetectionRequest(const service_manager::BindSourceInfo&,
-                                  R request) {
+// Forwards service requests to Service Manager.
+template <typename Interface>
+void ForwardRequest(const char* service_name,
+                    const service_manager::BindSourceInfo&,
+                    mojo::InterfaceRequest<Interface> request) {
   // TODO(beng): This should really be using the per-profile connector.
   service_manager::Connector* connector =
       ServiceManagerConnection::GetForProcess()->GetConnector();
-  connector->BindInterface(shape_detection::mojom::kServiceName,
-                           std::move(request));
+  connector->BindInterface(service_name, std::move(request));
 }
 
 void CreatePaymentManager(RenderFrameHostImpl* rfh,
@@ -2944,14 +2946,14 @@
   GetInterfaceRegistry()->AddInterface(base::Bind(&ImageCaptureImpl::Create));
 
   GetInterfaceRegistry()->AddInterface(
-      base::Bind(&ForwardShapeDetectionRequest<
-                 shape_detection::mojom::BarcodeDetectionRequest>));
+      base::Bind(&ForwardRequest<shape_detection::mojom::BarcodeDetection>,
+                 shape_detection::mojom::kServiceName));
   GetInterfaceRegistry()->AddInterface(
-      base::Bind(&ForwardShapeDetectionRequest<
-                 shape_detection::mojom::FaceDetectionProviderRequest>));
+      base::Bind(&ForwardRequest<shape_detection::mojom::FaceDetectionProvider>,
+                 shape_detection::mojom::kServiceName));
   GetInterfaceRegistry()->AddInterface(
-      base::Bind(&ForwardShapeDetectionRequest<
-                 shape_detection::mojom::TextDetectionRequest>));
+      base::Bind(&ForwardRequest<shape_detection::mojom::TextDetection>,
+                 shape_detection::mojom::kServiceName));
 
   GetInterfaceRegistry()->AddInterface(
       base::Bind(&CreatePaymentManager, base::Unretained(this)));
@@ -2960,6 +2962,12 @@
     GetInterfaceRegistry()->AddInterface(
         base::Bind(&AuthenticatorImpl::Create, base::Unretained(this)));
   }
+
+  if (base::FeatureList::IsEnabled(features::kGenericSensor)) {
+    GetInterfaceRegistry()->AddInterface(
+        base::Bind(&ForwardRequest<device::mojom::SensorProvider>,
+                   device::mojom::kServiceName));
+  }
 }
 
 void RenderFrameHostImpl::ResetWaitingState() {
diff --git a/content/browser/gpu/gpu_client.cc b/content/browser/gpu/gpu_client.cc
index ccb775f..8963ea3c 100644
--- a/content/browser/gpu/gpu_client.cc
+++ b/content/browser/gpu/gpu_client.cc
@@ -43,6 +43,20 @@
     const IPC::ChannelHandle& channel,
     const gpu::GPUInfo& gpu_info,
     GpuProcessHost::EstablishChannelStatus status) {
+  if (status == GpuProcessHost::EstablishChannelStatus::GPU_ACCESS_DENIED) {
+    // GPU access is not allowed. Notify the client immediately.
+    DCHECK(!channel.mojo_handle.is_valid());
+    callback.Run(render_process_id_, mojo::ScopedMessagePipeHandle(), gpu_info);
+    return;
+  }
+
+  if (status == GpuProcessHost::EstablishChannelStatus::GPU_HOST_INVALID) {
+    // GPU process may have crashed or been killed. Try again.
+    DCHECK(!channel.mojo_handle.is_valid());
+    EstablishGpuChannel(callback);
+    return;
+  }
+  DCHECK(channel.mojo_handle.is_valid());
   mojo::ScopedMessagePipeHandle channel_handle;
   channel_handle.reset(channel.mojo_handle);
   callback.Run(render_process_id_, std::move(channel_handle), gpu_info);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index cfe6fab..8c1824b 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -78,7 +78,6 @@
 #endif
 
 #if defined(OS_WIN)
-#include "base/win/windows_version.h"
 #include "content/common/sandbox_win.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #include "ui/gfx/switches.h"
@@ -260,38 +259,31 @@
   // backend. Note that the GPU process is connected to the interactive
   // desktop.
   bool PreSpawnTarget(sandbox::TargetPolicy* policy) override {
-    if (base::win::GetVersion() > base::win::VERSION_XP) {
-      if (cmd_line_.GetSwitchValueASCII(switches::kUseGL) ==
-          gl::kGLImplementationDesktopName) {
-        // Open GL path.
-        policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                              sandbox::USER_LIMITED);
-        SetJobLevel(cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
-        policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
-      } else {
-        policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
-                              sandbox::USER_LIMITED);
-
-        // UI restrictions break when we access Windows from outside our job.
-        // However, we don't want a proxy window in this process because it can
-        // introduce deadlocks where the renderer blocks on the gpu, which in
-        // turn blocks on the browser UI thread. So, instead we forgo a window
-        // message pump entirely and just add job restrictions to prevent child
-        // processes.
-        SetJobLevel(cmd_line_,
-                    sandbox::JOB_LIMITED_USER,
-                    JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |
-                    JOB_OBJECT_UILIMIT_DESKTOP |
-                    JOB_OBJECT_UILIMIT_EXITWINDOWS |
-                    JOB_OBJECT_UILIMIT_DISPLAYSETTINGS,
-                    policy);
-
-        policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
-      }
-    } else {
-      SetJobLevel(cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
-      policy->SetTokenLevel(sandbox::USER_UNPROTECTED,
+    if (cmd_line_.GetSwitchValueASCII(switches::kUseGL) ==
+        gl::kGLImplementationDesktopName) {
+      // Open GL path.
+      policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                             sandbox::USER_LIMITED);
+      SetJobLevel(cmd_line_, sandbox::JOB_UNPROTECTED, 0, policy);
+      policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+    } else {
+      policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                            sandbox::USER_LIMITED);
+
+      // UI restrictions break when we access Windows from outside our job.
+      // However, we don't want a proxy window in this process because it can
+      // introduce deadlocks where the renderer blocks on the gpu, which in
+      // turn blocks on the browser UI thread. So, instead we forgo a window
+      // message pump entirely and just add job restrictions to prevent child
+      // processes.
+      SetJobLevel(cmd_line_, sandbox::JOB_LIMITED_USER,
+                  JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS |
+                      JOB_OBJECT_UILIMIT_DESKTOP |
+                      JOB_OBJECT_UILIMIT_EXITWINDOWS |
+                      JOB_OBJECT_UILIMIT_DISPLAYSETTINGS,
+                  policy);
+
+      policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
     }
 
     // Allow the server side of GPU sockets, which are pipes that have
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 298e085e7..661136c6 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -503,7 +503,7 @@
     int page_request_id,
     const StreamControls& controls,
     const url::Origin& security_origin,
-    const MediaRequestResponseCallback& callback) {
+    MediaRequestResponseCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   // TODO(perkj): The argument list with NULL parameters to DeviceRequest
@@ -516,7 +516,7 @@
 
   const std::string& label = AddRequest(request);
 
-  request->callback = callback;
+  request->callback = std::move(callback);
   // Post a task and handle the request asynchronously. The reason is that the
   // requester won't have a label for the request until this function returns
   // and thus can not handle a response. Using base::Unretained is safe since
@@ -1219,7 +1219,8 @@
 
   if (request->request_type == MEDIA_DEVICE_ACCESS &&
       !request->callback.is_null()) {
-    request->callback.Run(MediaStreamDevices(), std::move(request->ui_proxy));
+    std::move(request->callback)
+        .Run(MediaStreamDevices(), std::move(request->ui_proxy));
   }
 
   DeleteRequest(label);
@@ -1238,7 +1239,7 @@
     DeviceRequest* request,
     const MediaStreamDevices& devices) {
   if (!request->callback.is_null())
-    request->callback.Run(devices, std::move(request->ui_proxy));
+    std::move(request->callback).Run(devices, std::move(request->ui_proxy));
 
   // Delete the request since it is done.
   DeleteRequest(label);
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 3d4baa1..3594098 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -73,8 +73,8 @@
       public base::PowerObserver {
  public:
   // Callback to deliver the result of a media request.
-  typedef base::Callback<void(const MediaStreamDevices& devices,
-                              std::unique_ptr<MediaStreamUIProxy> ui)>
+  typedef base::OnceCallback<void(const MediaStreamDevices& devices,
+                                  std::unique_ptr<MediaStreamUIProxy> ui)>
       MediaRequestResponseCallback;
 
   // Callback for testing.
@@ -124,13 +124,12 @@
   // used to determine where the infobar will appear to the user. |callback| is
   // used to send the selected device to the clients. An empty list of device
   // will be returned if the users deny the access.
-  std::string MakeMediaAccessRequest(
-      int render_process_id,
-      int render_frame_id,
-      int page_request_id,
-      const StreamControls& controls,
-      const url::Origin& security_origin,
-      const MediaRequestResponseCallback& callback);
+  std::string MakeMediaAccessRequest(int render_process_id,
+                                     int render_frame_id,
+                                     int page_request_id,
+                                     const StreamControls& controls,
+                                     const url::Origin& security_origin,
+                                     MediaRequestResponseCallback callback);
 
   // GenerateStream opens new media devices according to |components|.  It
   // creates a new request which is identified by a unique string that's
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index 754c99d..f0e968a 100644
--- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -191,12 +191,12 @@
     const int page_request_id = 1;
     const url::Origin security_origin;
     MediaStreamManager::MediaRequestResponseCallback callback =
-        base::Bind(&MediaStreamManagerTest::ResponseCallback,
-                   base::Unretained(this), index);
+        base::BindOnce(&MediaStreamManagerTest::ResponseCallback,
+                       base::Unretained(this), index);
     StreamControls controls(true, true);
     return media_stream_manager_->MakeMediaAccessRequest(
         render_process_id, render_frame_id, page_request_id, controls,
-        security_origin, callback);
+        security_origin, std::move(callback));
   }
 
   // media_stream_manager_ needs to outlive thread_bundle_ because it is a
@@ -237,12 +237,11 @@
   int page_request_id = 2;
   url::Origin security_origin;
   StreamControls controls(true, true);
-  MediaStreamManager::MediaRequestResponseCallback callback =
-      base::Bind(&MediaStreamManagerTest::ResponseCallback,
-                 base::Unretained(this), 1);
+  MediaStreamManager::MediaRequestResponseCallback callback = base::BindOnce(
+      &MediaStreamManagerTest::ResponseCallback, base::Unretained(this), 1);
   std::string label2 = media_stream_manager_->MakeMediaAccessRequest(
       render_process_id, render_frame_id, page_request_id, controls,
-      security_origin, callback);
+      security_origin, std::move(callback));
 
   // Expecting the callbackS from requests will be triggered and quit the test.
   // Note, the callbacks might come in a different order depending on the
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index e0fc0f46..2a31b249 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -21,7 +21,6 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
-#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/cache_storage/cache_storage_cache.h"
@@ -129,8 +128,6 @@
                            arraysize(kFilteredMessageClasses)),
       BrowserAssociatedInterface<mojom::RenderMessageFilter>(this, this),
       resource_dispatcher_host_(ResourceDispatcherHostImpl::Get()),
-      shared_bitmap_allocation_notifier_impl_(
-          viz::ServerSharedBitmapManager::current()),
       request_context_(request_context),
       resource_context_(browser_context->GetResourceContext()),
       render_widget_helper_(render_widget_helper),
@@ -217,11 +214,6 @@
   std::move(callback).Run(route_id);
 }
 
-void RenderMessageFilter::GetSharedBitmapAllocationNotifier(
-    cc::mojom::SharedBitmapAllocationNotifierAssociatedRequest request) {
-  shared_bitmap_allocation_notifier_impl_.Bind(std::move(request));
-}
-
 #if defined(OS_MACOSX)
 
 void RenderMessageFilter::OnLoadFont(const FontDescriptor& font,
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index b6202cb3..d0e7c36 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -20,7 +20,6 @@
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "components/viz/common/resources/shared_bitmap_manager.h"
-#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "content/common/cache_storage/cache_storage_types.h"
 #include "content/common/render_message_filter.mojom.h"
 #include "content/public/browser/browser_associated_interface.h"
@@ -114,9 +113,6 @@
   void CreateFullscreenWidget(int opener_id,
                               mojom::WidgetPtr widget,
                               CreateFullscreenWidgetCallback callback) override;
-  void GetSharedBitmapAllocationNotifier(
-      cc::mojom::SharedBitmapAllocationNotifierAssociatedRequest request)
-      override;
 
   // Message handlers called on the browser IO thread:
   void OnHasGpuProcess(IPC::Message* reply);
@@ -158,9 +154,6 @@
   // than we do.
   ResourceDispatcherHostImpl* resource_dispatcher_host_;
 
-  viz::SharedBitmapAllocationNotifierImpl
-      shared_bitmap_allocation_notifier_impl_;
-
   // Contextual information to be used for requests created here.
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5f842b1..ff3ca79 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -56,6 +56,7 @@
 #include "components/metrics/single_sample_metrics.h"
 #include "components/tracing/common/tracing_switches.h"
 #include "components/viz/common/resources/buffer_to_texture_target_map.h"
+#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "content/browser/appcache/appcache_dispatcher_host.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/background_fetch/background_fetch_service_impl.h"
@@ -1084,6 +1085,8 @@
       instance_weak_factory_(
           new base::WeakPtrFactory<RenderProcessHostImpl>(this)),
       frame_sink_provider_(id_),
+      shared_bitmap_allocation_notifier_impl_(
+          viz::ServerSharedBitmapManager::current()),
       weak_factory_(this) {
   widget_helper_ = new RenderWidgetHelper();
 
@@ -1617,6 +1620,11 @@
 
   AddUIThreadInterface(
       registry.get(),
+      base::Bind(&RenderProcessHostImpl::BindSharedBitmapAllocationNotifier,
+                 base::Unretained(this)));
+
+  AddUIThreadInterface(
+      registry.get(),
       base::Bind(&BackgroundSyncContext::CreateService,
                  base::Unretained(
                      storage_partition_impl_->GetBackgroundSyncContext())));
@@ -1793,6 +1801,12 @@
   frame_sink_provider_.Bind(std::move(request));
 }
 
+void RenderProcessHostImpl::BindSharedBitmapAllocationNotifier(
+    const service_manager::BindSourceInfo& source_info,
+    cc::mojom::SharedBitmapAllocationNotifierRequest request) {
+  shared_bitmap_allocation_notifier_impl_.Bind(std::move(request));
+}
+
 void RenderProcessHostImpl::CreateStoragePartitionService(
     const service_manager::BindSourceInfo& source_info,
     mojom::StoragePartitionServiceRequest request) {
@@ -3410,6 +3424,8 @@
   // for that.
   frame_sink_provider_.Unbind();
 
+  shared_bitmap_allocation_notifier_impl_.ChildDied();
+
   // This object is not deleted at this point and might be reused later.
   // TODO(darin): clean this up
 }
@@ -3811,4 +3827,9 @@
                                   bad_message::RPH_MOJO_PROCESS_ERROR);
 }
 
+viz::SharedBitmapAllocationNotifierImpl*
+RenderProcessHostImpl::GetSharedBitmapAllocationNotifier() {
+  return &shared_bitmap_allocation_notifier_impl_;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 52320c0..078fe06 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -21,6 +21,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "build/build_config.h"
+#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "content/browser/child_process_launcher.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/renderer_host/frame_sink_provider_impl.h"
@@ -337,6 +338,9 @@
       RenderProcessHost* render_process_host,
       const GURL& site_url);
 
+  viz::SharedBitmapAllocationNotifierImpl* GetSharedBitmapAllocationNotifier()
+      override;
+
  protected:
   // A proxy for our IPC::Channel that lives on the IO thread.
   std::unique_ptr<IPC::ChannelProxy> channel_;
@@ -399,6 +403,9 @@
       blink::mojom::OffscreenCanvasProviderRequest request);
   void BindFrameSinkProvider(const service_manager::BindSourceInfo& source_info,
                              mojom::FrameSinkProviderRequest request);
+  void BindSharedBitmapAllocationNotifier(
+      const service_manager::BindSourceInfo& source_info,
+      cc::mojom::SharedBitmapAllocationNotifierRequest request);
   void CreateStoragePartitionService(
       const service_manager::BindSourceInfo& source_info,
       mojom::StoragePartitionServiceRequest request);
@@ -717,6 +724,9 @@
 
   FrameSinkProviderImpl frame_sink_provider_;
 
+  viz::SharedBitmapAllocationNotifierImpl
+      shared_bitmap_allocation_notifier_impl_;
+
   base::WeakPtrFactory<RenderProcessHostImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderProcessHostImpl);
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index a445f9c..5308d98c 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -327,6 +327,7 @@
   CHECK(result.second) << "Inserting a duplicate item!";
   process_->AddRoute(routing_id_, this);
   process_->AddWidget(this);
+  process_->GetSharedBitmapAllocationNotifier()->AddObserver(this);
 
   // If we're initially visible, tell the process host that we're alive.
   // Otherwise we'll notify the process host when we are first shown.
@@ -1790,6 +1791,7 @@
     view_.reset();
   }
 
+  process_->GetSharedBitmapAllocationNotifier()->RemoveObserver(this);
   process_->RemoveWidget(this);
   process_->RemoveRoute(routing_id_);
   g_routing_id_widget_map.Get().erase(
@@ -2588,6 +2590,28 @@
     return;
   }
 
+  uint32_t max_sequence_number = 0;
+  for (const auto& resource : frame.resource_list) {
+    max_sequence_number =
+        std::max(max_sequence_number, resource.shared_bitmap_sequence_number);
+  }
+
+  // If the CompositorFrame references SharedBitmaps that we are not aware of,
+  // defer the submission until they are registered.
+  uint32_t last_registered_sequence_number =
+      GetProcess()->GetSharedBitmapAllocationNotifier()->last_sequence_number();
+  if (max_sequence_number > last_registered_sequence_number) {
+    saved_frame_.frame = std::move(frame);
+    saved_frame_.local_surface_id = local_surface_id;
+    saved_frame_.max_shared_bitmap_sequence_number = max_sequence_number;
+    TRACE_EVENT_ASYNC_BEGIN2("renderer_host", "PauseCompositorFrameSink", this,
+                             "LastRegisteredSequenceNumber",
+                             last_registered_sequence_number,
+                             "RequiredSequenceNumber", max_sequence_number);
+    compositor_frame_sink_binding_.PauseIncomingMethodCallProcessing();
+    return;
+  }
+
   last_local_surface_id_ = local_surface_id;
   last_surface_properties_ = new_surface_properties;
 
@@ -2687,4 +2711,15 @@
 }
 #endif
 
+void RenderWidgetHostImpl::DidAllocateSharedBitmap(uint32_t sequence_number) {
+  if (saved_frame_.local_surface_id.is_valid() &&
+      sequence_number >= saved_frame_.max_shared_bitmap_sequence_number) {
+    SubmitCompositorFrame(saved_frame_.local_surface_id,
+                          std::move(saved_frame_.frame));
+    saved_frame_.local_surface_id = viz::LocalSurfaceId();
+    compositor_frame_sink_binding_.ResumeIncomingMethodCallProcessing();
+    TRACE_EVENT_ASYNC_END0("renderer_host", "PauseCompositorFrameSink", this);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 035b6b7..bdee193 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -28,6 +28,7 @@
 #include "cc/ipc/compositor_frame_sink.mojom.h"
 #include "components/viz/common/quads/shared_bitmap.h"
 #include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/browser/renderer_host/input/input_ack_handler.h"
 #include "content/browser/renderer_host/input/input_router_client.h"
@@ -105,6 +106,7 @@
       public TouchEmulatorClient,
       public NON_EXPORTED_BASE(SyntheticGestureController::Delegate),
       public NON_EXPORTED_BASE(cc::mojom::CompositorFrameSink),
+      public NON_EXPORTED_BASE(viz::SharedBitmapAllocationObserver),
       public IPC::Listener {
  public:
   // |routing_id| must not be MSG_ROUTING_NONE.
@@ -755,6 +757,10 @@
   // process the messages. Virtual for tests.
   virtual void ProcessSwapMessages(std::vector<IPC::Message> messages);
 
+  // viz::SharedBitmapAllocationObserver implementation.
+  void DidAllocateSharedBitmap(
+      uint32_t last_shared_bitmap_sequence_number) override;
+
 #if defined(OS_MACOSX)
   device::mojom::WakeLock* GetWakeLock();
 #endif
@@ -983,6 +989,14 @@
   // Sorted by frame token.
   std::queue<std::pair<uint32_t, std::vector<IPC::Message>>> queued_messages_;
 
+  // If a CompositorFrame is submitted that references SharedBitmaps that don't
+  // exist yet, we keep it here until they are available.
+  struct {
+    viz::LocalSurfaceId local_surface_id;
+    cc::CompositorFrame frame;
+    uint32_t max_shared_bitmap_sequence_number = 0;
+  } saved_frame_;
+
   std::unique_ptr<LegacyIPCWidgetInputHandler> legacy_widget_input_handler_;
 
   base::WeakPtrFactory<RenderWidgetHostImpl> weak_factory_;
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 740885a..135d5f6e 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -181,7 +181,7 @@
     context.label = media_stream_manager_->MakeMediaAccessRequest(
         context.render_process_id, context.render_frame_id, context.request_id,
         StreamControls(true, false), url::Origin(GURL(context.context_name)),
-        base::Bind(
+        base::BindOnce(
             &SpeechRecognitionManagerImpl::MediaRequestPermissionCallback,
             weak_factory_.GetWeakPtr(), session_id));
     return;
diff --git a/chrome/browser/ssl/ignore_errors_cert_verifier.cc b/content/browser/ssl/ignore_errors_cert_verifier.cc
similarity index 94%
rename from chrome/browser/ssl/ignore_errors_cert_verifier.cc
rename to content/browser/ssl/ignore_errors_cert_verifier.cc
index af0e370..7fe840b 100644
--- a/chrome/browser/ssl/ignore_errors_cert_verifier.cc
+++ b/content/browser/ssl/ignore_errors_cert_verifier.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ssl/ignore_errors_cert_verifier.h"
+#include "content/public/browser/ignore_errors_cert_verifier.h"
 
 #include <iterator>
 #include <utility>
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
-#include "chrome/common/chrome_switches.h"
+#include "content/public/common/content_switches.h"
 #include "crypto/sha2.h"
 #include "net/base/completion_callback.h"
 #include "net/base/hash_value.h"
@@ -29,11 +29,14 @@
 using ::net::SHA256HashValueLessThan;
 using ::net::X509Certificate;
 
+namespace content {
+
 // static
 std::unique_ptr<CertVerifier> IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
     const base::CommandLine& command_line,
+    const char* user_data_dir_switch,
     std::unique_ptr<CertVerifier> verifier) {
-  if (!command_line.HasSwitch(switches::kUserDataDir) ||
+  if (!command_line.HasSwitch(user_data_dir_switch) ||
       !command_line.HasSwitch(switches::kIgnoreCertificateErrorsSPKIList)) {
     return verifier;
   }
@@ -130,3 +133,5 @@
 void IgnoreErrorsCertVerifier::set_whitelist(const SPKIHashSet& whitelist) {
   whitelist_ = whitelist;
 }
+
+}  // namespace content
diff --git a/chrome/browser/ssl/ignore_errors_cert_verifier_unittest.cc b/content/browser/ssl/ignore_errors_cert_verifier_unittest.cc
similarity index 94%
rename from chrome/browser/ssl/ignore_errors_cert_verifier_unittest.cc
rename to content/browser/ssl/ignore_errors_cert_verifier_unittest.cc
index 1863367..29ea418e 100644
--- a/chrome/browser/ssl/ignore_errors_cert_verifier_unittest.cc
+++ b/content/browser/ssl/ignore_errors_cert_verifier_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ssl/ignore_errors_cert_verifier.h"
+#include "content/public/browser/ignore_errors_cert_verifier.h"
 
 #include "base/base64.h"
 #include "base/files/file_path.h"
@@ -10,8 +10,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/io_thread.h"
-#include "chrome/common/chrome_switches.h"
+#include "content/public/common/content_switches.h"
 #include "crypto/sha2.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
@@ -43,6 +42,10 @@
 using net::test::IsError;
 using net::test::IsOk;
 
+namespace content {
+
+static const char kTestUserDataDirSwitch[] = "test-user-data-dir";
+
 static std::vector<std::string> MakeWhitelist() {
   base::FilePath certs_dir = net::GetTestCertsDirectory();
   net::CertificateList certs = net::CreateCertificateListFromFile(
@@ -157,7 +160,7 @@
   IgnoreCertificateErrorsSPKIListFlagTest() {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
     if (GetParam()) {
-      command_line.AppendSwitchASCII(switches::kUserDataDir, "/foo/bar/baz");
+      command_line.AppendSwitchASCII(kTestUserDataDirSwitch, "/foo/bar/baz");
     }
     command_line.AppendSwitchASCII(switches::kIgnoreCertificateErrorsSPKIList,
                                    base::JoinString(MakeWhitelist(), ","));
@@ -165,7 +168,7 @@
     auto mock_verifier = base::MakeUnique<MockCertVerifier>();
     mock_verifier->set_default_result(ERR_CERT_INVALID);
     verifier_ = IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
-        command_line, std::move(mock_verifier));
+        command_line, kTestUserDataDirSwitch, std::move(mock_verifier));
   }
   ~IgnoreCertificateErrorsSPKIListFlagTest() override {}
 
@@ -198,3 +201,5 @@
 INSTANTIATE_TEST_CASE_P(WithUserDataDirSwitchPresent,
                         IgnoreCertificateErrorsSPKIListFlagTest,
                         ::testing::Bool());
+
+}  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index b85d291..e967a2f 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4812,7 +4812,8 @@
 
 void WebContentsImpl::DidStartLoading(FrameTreeNode* frame_tree_node,
                                       bool to_different_document) {
-  LoadingStateChanged(to_different_document, false, nullptr);
+  LoadingStateChanged(frame_tree_node->IsMainFrame() && to_different_document,
+                      false, nullptr);
 
   // Notify accessibility that the user is navigating away from the
   // current document.
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 9c837588..569ae3d 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -1361,7 +1361,7 @@
   // Data for loading state ----------------------------------------------------
 
   // Indicates whether the current load is to a different document. Only valid
-  // if is_loading_ is true.
+  // if |is_loading_| is true and only tracks loads in the main frame.
   bool is_load_to_different_document_;
 
   // Indicates if the tab is considered crashed.
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 378075df..31e4ebf 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3245,6 +3245,58 @@
   EXPECT_FALSE(observer.is_loading());
 }
 
+// Tests that WebContentsImpl::IsLoadingToDifferentDocument only reports main
+// frame loads. Browser-initiated navigation of subframes is only possible in
+// --site-per-process mode within unit tests.
+TEST_F(WebContentsImplTestWithSiteIsolation, IsLoadingToDifferentDocument) {
+  const GURL main_url("http://www.chromium.org");
+  TestRenderFrameHost* orig_rfh = main_test_rfh();
+
+  // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
+  // The frame should still be loading.
+  controller().LoadURL(main_url, Referrer(), ui::PAGE_TRANSITION_TYPED,
+                       std::string());
+  int entry_id = controller().GetPendingEntry()->GetUniqueID();
+
+  // PlzNavigate: the RenderFrameHost does not expect to receive
+  // DidStartLoading IPCs for navigations to different documents.
+  if (!IsBrowserSideNavigationEnabled()) {
+    orig_rfh->OnMessageReceived(
+        FrameHostMsg_DidStartLoading(orig_rfh->GetRoutingID(), false));
+  }
+  main_test_rfh()->PrepareForCommit();
+  contents()->TestDidNavigate(orig_rfh, entry_id, true, main_url,
+                              ui::PAGE_TRANSITION_TYPED);
+  EXPECT_FALSE(contents()->CrossProcessNavigationPending());
+  EXPECT_EQ(orig_rfh, main_test_rfh());
+  EXPECT_TRUE(contents()->IsLoading());
+  EXPECT_TRUE(contents()->IsLoadingToDifferentDocument());
+
+  // Send the DidStopLoading for the main frame and ensure it isn't loading
+  // anymore.
+  orig_rfh->OnMessageReceived(
+      FrameHostMsg_DidStopLoading(orig_rfh->GetRoutingID()));
+  EXPECT_FALSE(contents()->IsLoading());
+  EXPECT_FALSE(contents()->IsLoadingToDifferentDocument());
+
+  // Create a child frame to navigate.
+  TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
+
+  // Navigate the child frame to about:blank, make sure the web contents is
+  // marked as "loading" but not "loading to different document".
+  if (!IsBrowserSideNavigationEnabled()) {
+    subframe->OnMessageReceived(
+        FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
+  }
+  subframe->SendNavigateWithTransition(0, false, GURL("about:blank"),
+                                       ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+  EXPECT_TRUE(contents()->IsLoading());
+  EXPECT_FALSE(contents()->IsLoadingToDifferentDocument());
+  subframe->OnMessageReceived(
+      FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
+  EXPECT_FALSE(contents()->IsLoading());
+}
+
 // Ensure that WebContentsImpl does not stop loading too early when there still
 // is a pending renderer. This can happen if a same-process non user-initiated
 // navigation completes while there is an ongoing cross-process navigation.
diff --git a/content/browser/web_contents/web_contents_view_aura_browsertest.cc b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
index 3167829..99c5e17 100644
--- a/content/browser/web_contents/web_contents_view_aura_browsertest.cc
+++ b/content/browser/web_contents/web_contents_view_aura_browsertest.cc
@@ -49,10 +49,6 @@
 #include "ui/events/event_utils.h"
 #include "ui/events/test/event_generator.h"
 
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 namespace {
 
 // TODO(tdresser): Find a way to avoid sleeping like this. See crbug.com/405282
@@ -639,14 +635,6 @@
 #define MAYBE_OverscrollScreenshot OverscrollScreenshot
 #endif
 IN_PROC_BROWSER_TEST_F(WebContentsViewAuraTest, MAYBE_OverscrollScreenshot) {
-  // Disable the test for WinXP.  See http://crbug/294116.
-#if defined(OS_WIN)
-  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
-    LOG(WARNING) << "Test disabled due to unknown bug on WinXP.";
-    return;
-  }
-#endif
-
   ASSERT_NO_FATAL_FAILURE(StartTestWithPage("/overscroll_navigation.html"));
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(shell()->web_contents());
diff --git a/content/common/render_message_filter.mojom b/content/common/render_message_filter.mojom
index 720032d..e51d3dc 100644
--- a/content/common/render_message_filter.mojom
+++ b/content/common/render_message_filter.mojom
@@ -21,7 +21,4 @@
   // Similar to CreateWidget except the widget is a full screen window.
   [Sync] CreateFullscreenWidget(int32 opener_id, Widget widget)
       => (int32 route_id);
-
-  GetSharedBitmapAllocationNotifier(
-      associated cc.mojom.SharedBitmapAllocationNotifier& notifier);
 };
diff --git a/content/common/sandbox_win.cc b/content/common/sandbox_win.cc
index 323e57e..54e31d3 100644
--- a/content/common/sandbox_win.cc
+++ b/content/common/sandbox_win.cc
@@ -409,22 +409,10 @@
   if (result != sandbox::SBOX_ALL_OK)
     return result;
 
-  // Close the proxy settings on XP.
-  if (base::win::GetVersion() <= base::win::VERSION_SERVER_2003)
-    result = policy->AddKernelObjectToClose(L"Key",
-                 L"HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\" \
-                     L"CurrentVersion\\Internet Settings");
-  if (result != sandbox::SBOX_ALL_OK)
-    return result;
-
-  sandbox::TokenLevel initial_token = sandbox::USER_UNPROTECTED;
-  if (base::win::GetVersion() > base::win::VERSION_XP) {
-    // On 2003/Vista the initial token has to be restricted if the main
-    // token is restricted.
-    initial_token = sandbox::USER_RESTRICTED_SAME_ACCESS;
-  }
-
-  result = policy->SetTokenLevel(initial_token, sandbox::USER_LOCKDOWN);
+  // On 2003/Vista+ the initial token has to be restricted if the main
+  // token is restricted.
+  result = policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
+                                 sandbox::USER_LOCKDOWN);
   if (result != sandbox::SBOX_ALL_OK)
     return result;
   // Prevents the renderers from manipulating low-integrity processes.
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index d4af7a5..8b32c13 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -1126,6 +1126,9 @@
     private void onTouchDown(MotionEvent event) {
         if (mShouldRequestUnbufferedDispatch) requestUnbufferedDispatch(event);
         cancelRequestToScrollFocusedEditableNodeIntoView();
+        for (mGestureStateListenersIterator.rewind(); mGestureStateListenersIterator.hasNext();) {
+            mGestureStateListenersIterator.next().onTouchDown();
+        }
     }
 
     private void updateAfterSizeChanged() {
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
index 2854b35..4b7f89c 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/GestureStateListener.java
@@ -37,33 +37,39 @@
      */
     public void onScrollUpdateGestureConsumed() {}
 
-    /*
+    /**
      * Called when a scroll gesture has started.
      */
     public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {}
 
-    /*
+    /**
      * Called when a scroll gesture has stopped.
      */
     public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {}
 
-    /*
+    /**
      * Called when the min or max scale factor may have been changed.
      */
     public void onScaleLimitsChanged(float minPageScaleFactor, float maxPageScaleFactor) {}
 
-    /*
+    /**
      * Called when the scroll offsets or extents may have changed.
      */
     public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {}
 
-    /*
+    /**
+     * Called at the beginning of any kind of touch event when the user's finger first touches down
+     * onto the screen.  The resulting gesture may be a single tap, long-press, or scroll.
+     */
+    public void onTouchDown() {}
+
+    /**
      * Called after a single-tap gesture event was dispatched to the renderer,
      * indicating whether or not the gesture was consumed.
      */
     public void onSingleTap(boolean consumed) {}
 
-    /*
+    /**
      * Called after a single-tap gesture event was processed by the renderer,
      * but was not handled.
      */
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 124d48e..77bf554 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -25,6 +25,7 @@
           "blink::mojom::OffscreenCanvasProvider",
           "blink::mojom::PermissionService",
           "blink::mojom::WebSocket",
+	  "cc::mojom::SharedBitmapAllocationNotifier",
           "content::mojom::FieldTrialRecorder",
           "content::mojom::FrameSinkProvider",
           "content::mojom::MemoryCoordinatorHandle",
@@ -72,7 +73,7 @@
         "content_renderer": [ "browser" ],
         "content_utility": [ "browser" ],
         "data_decoder": [ "image_decoder" ],
-        "device": [ "device:nfc", "device:wake_lock" ],
+        "device": [ "device:generic_sensor", "device:nfc", "device:wake_lock" ],
         "file": [ "file:filesystem", "file:leveldb" ],
         "media": [ "media:media" ],
         "network": [
@@ -92,7 +93,7 @@
           "face_detection",
           "text_detection"
         ],
-        "resource_coordinator": [ "coordination_unit", "service_callbacks" ],
+        "resource_coordinator": [ "coordination_unit", "service_callbacks", "tab_signal" ],
         "video_capture": [ "capture", "tests" ]
       }
     },
@@ -111,12 +112,15 @@
           "blink::mojom::SensitiveInputVisibilityService",
           "blink::mojom::WebBluetoothService",
           "blink::mojom::WebSocket",
+
           // TODO(beng): figure out how to overlay test interfaces like this.
           "content::mojom::BrowserTarget",
+
           "content::mojom::RendererAudioOutputStreamFactory",
           "device::mojom::VRService",
           "device::mojom::Geolocation",
           "device::mojom::NFC",
+          "device::mojom::SensorProvider",
           "device::mojom::WakeLock",
           "device::usb::DeviceManager",
           "discardable_memory::mojom::DiscardableSharedMemoryManager",
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 52a453ba..a850e12 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -22,7 +22,6 @@
         "content_browser": [ "memory_instrumentation", "renderer" ],
         "device": [
           "device:battery_monitor",
-          "device:generic_sensor",
           "device:power_monitor",
           "device:screen_orientation",
           "device:sensors",
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 2cf71897..c5467c7 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -22,7 +22,6 @@
   visibility = [ "//content/*" ]
 
   sources = [
-    "all_download_item_notifier.h",
     "android/android_overlay_provider.h",
     "android/browser_media_player_manager_register.cc",
     "android/browser_media_player_manager_register.h",
@@ -131,6 +130,7 @@
     "guest_mode.cc",
     "guest_mode.h",
     "histogram_fetcher.h",
+    "ignore_errors_cert_verifier.h",
     "indexed_db_context.h",
     "indexed_db_info.h",
     "interstitial_page.h",
diff --git a/content/public/browser/all_download_item_notifier.h b/content/public/browser/all_download_item_notifier.h
deleted file mode 100644
index 4f07a28..0000000
--- a/content/public/browser/all_download_item_notifier.h
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_PUBLIC_BROWSER_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
-#define CONTENT_PUBLIC_BROWSER_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "content/common/content_export.h"
-#include "content/public/browser/download_item.h"
-#include "content/public/browser/download_manager.h"
-
-// AllDownloadItemNotifier observes ALL the DownloadItems on a given
-// DownloadManager.
-// Clients should use GetManager() instead of storing their own pointer to the
-// manager so that they can be sensitive to managers that have gone down.
-
-// Example Usage:
-// class DownloadSystemConsumer : public AllDownloadItemNotifier::Observer {
-//  public:
-//   DownloadSystemConsumer(DownloadManager* original_manager,
-//            DownloadManager* incognito_manager)
-//     : original_notifier_(original_manager, this),
-//       incognito_notifier_(incognito_manager, this) {
-//   }
-//
-//   virtual void OnDownloadUpdated(
-//     DownloadManager* manager, DownloadItem* item) { ... }
-//
-//  private:
-//   AllDownloadItemNotifier original_notifier_;
-//   AllDownloadItemNotifier incognito_notifier_;
-// };
-
-namespace content {
-
-class CONTENT_EXPORT AllDownloadItemNotifier : public DownloadManager::Observer,
-                                               public DownloadItem::Observer {
- public:
-  // All of the methods take the DownloadManager so that subclasses can observe
-  // multiple managers at once and easily distinguish which manager a given item
-  // belongs to.
-  class Observer {
-   public:
-    Observer() {}
-    virtual ~Observer() {}
-
-    virtual void OnDownloadCreated(DownloadManager* manager,
-                                   DownloadItem* item) {}
-    virtual void OnDownloadUpdated(DownloadManager* manager,
-                                   DownloadItem* item) {}
-    virtual void OnDownloadOpened(DownloadManager* manager,
-                                  DownloadItem* item) {}
-    virtual void OnDownloadRemoved(DownloadManager* manager,
-                                   DownloadItem* item) {}
-
-   private:
-    DISALLOW_COPY_AND_ASSIGN(Observer);
-  };
-
-  AllDownloadItemNotifier(DownloadManager* manager, Observer* observer);
-
-  ~AllDownloadItemNotifier() override;
-
-  // Returns NULL if the manager has gone down.
-  DownloadManager* GetManager() const { return manager_; }
-
- private:
-  // DownloadManager::Observer
-  void ManagerGoingDown(DownloadManager* manager) override;
-  void OnDownloadCreated(DownloadManager* manager, DownloadItem* item) override;
-
-  // DownloadItem::Observer
-  void OnDownloadUpdated(DownloadItem* item) override;
-  void OnDownloadOpened(DownloadItem* item) override;
-  void OnDownloadRemoved(DownloadItem* item) override;
-  void OnDownloadDestroyed(DownloadItem* item) override;
-
-  DownloadManager* manager_;
-  AllDownloadItemNotifier::Observer* observer_;
-  std::set<DownloadItem*> observing_;
-
-  DISALLOW_COPY_AND_ASSIGN(AllDownloadItemNotifier);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_PUBLIC_BROWSER_ALL_DOWNLOAD_ITEM_NOTIFIER_H_
diff --git a/chrome/browser/ssl/ignore_errors_cert_verifier.h b/content/public/browser/ignore_errors_cert_verifier.h
similarity index 81%
rename from chrome/browser/ssl/ignore_errors_cert_verifier.h
rename to content/public/browser/ignore_errors_cert_verifier.h
index 2b163904..28625b4e 100644
--- a/chrome/browser/ssl/ignore_errors_cert_verifier.h
+++ b/content/public/browser/ignore_errors_cert_verifier.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_SSL_IGNORE_ERRORS_CERT_VERIFIER_H_
-#define CHROME_BROWSER_SSL_IGNORE_ERRORS_CERT_VERIFIER_H_
+#ifndef CONTENT_PUBLIC_BROWSER_IGNORE_ERRORS_CERT_VERIFIER_H_
+#define CONTENT_PUBLIC_BROWSER_IGNORE_ERRORS_CERT_VERIFIER_H_
 
 #include <memory>
 #include <string>
@@ -11,6 +11,7 @@
 
 #include "base/command_line.h"
 #include "base/containers/flat_set.h"
+#include "content/common/content_export.h"
 #include "net/cert/cert_verifier.h"
 
 namespace net {
@@ -18,10 +19,12 @@
 class SHA256HashValueLessThan;
 }  // namespace net
 
+namespace content {
+
 // IgnoreErrorsCertVerifier wraps another CertVerifier in order to ignore
 // verification errors from certificate chains that match a whitelist of SPKI
 // fingerprints.
-class IgnoreErrorsCertVerifier : public net::CertVerifier {
+class CONTENT_EXPORT IgnoreErrorsCertVerifier : public net::CertVerifier {
  public:
   // SPKIHashSet is a set of SHA-256 SPKI fingerprints (RFC 7469, Section 2.4).
   using SPKIHashSet =
@@ -32,8 +35,11 @@
   // --ignore-certificate-errors-spki-list flag of the command line if the
   // --user-data-dir flag is also present. If either of these flags are missing,
   // it returns the supplied verifier.
+  // As the --user-data-dir flag is embedder defined, the flag to check for
+  // needs to be passed in.
   static std::unique_ptr<net::CertVerifier> MaybeWrapCertVerifier(
       const base::CommandLine& command_line,
+      const char* user_data_dir_switch,
       std::unique_ptr<net::CertVerifier> verifier);
 
   // MakeWhitelist converts a vector of Base64-encoded SHA-256 SPKI fingerprints
@@ -63,6 +69,10 @@
 
   std::unique_ptr<net::CertVerifier> verifier_;
   SPKIHashSet whitelist_;
+
+  DISALLOW_COPY_AND_ASSIGN(IgnoreErrorsCertVerifier);
 };
 
-#endif  // CHROME_BROWSER_SSL_IGNORE_ERRORS_CERT_VERIFIER_H_
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_IGNORE_ERRORS_CERT_VERIFIER_H_
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index e42a39f9..d047a98 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -37,6 +37,10 @@
 class ResourceCoordinatorInterface;
 }
 
+namespace viz {
+class SharedBitmapAllocationNotifierImpl;
+}
+
 namespace content {
 class BrowserContext;
 class BrowserMessageFilter;
@@ -389,6 +393,12 @@
   // be posted back on the UI thread).
   void PostTaskWhenProcessIsReady(base::OnceClosure task);
 
+  // Returns the SharedBitmapAllocationNotifier associated with this process.
+  // SharedBitmapAllocationNotifier manages viz::SharedBitmaps created by this
+  // process and can notify observers when a new SharedBitmap is allocated.
+  virtual viz::SharedBitmapAllocationNotifierImpl*
+  GetSharedBitmapAllocationNotifier() = 0;
+
   // Static management functions -----------------------------------------------
 
   // Flag to run the renderer in process.  This is primarily
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 993bf7a..0a3d303 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -373,7 +373,8 @@
 
   // Returns whether this WebContents is loading and and the load is to a
   // different top-level document (rather than being a navigation within the
-  // same document). This being true implies that IsLoading() is also true.
+  // same document) in the main frame. This being true implies that IsLoading()
+  // is also true.
   virtual bool IsLoadingToDifferentDocument() const = 0;
 
   // Returns whether this WebContents is waiting for a first-response for the
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 1e56d09..32b513f7 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -575,6 +575,20 @@
 // These mappings only apply to the host resolver.
 const char kHostResolverRules[]             = "host-resolver-rules";
 
+// A set of public key hashes for which to ignore certificate-related errors.
+//
+// If the certificate chain presented by the server does not validate, and one
+// or more certificates have public key hashes that match a key from this list,
+// the error is ignored.
+//
+// The switch value must a be a comma-separated list of Base64-encoded SHA-256
+// SPKI Fingerprints (RFC 7469, Section 2.4).
+//
+// This switch has no effect unless --user-data-dir (as defined by the content
+// embedder) is also present.
+const char kIgnoreCertificateErrorsSPKIList[] =
+    "ignore-certificate-errors-spki-list";
+
 // Makes all APIs reflect the layout viewport.
 const char kInertVisualViewport[]           = "inert-visual-viewport";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index cf2af3a..987e5db3 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -175,6 +175,7 @@
 CONTENT_EXPORT extern const char kGpuStartupDialog[];
 CONTENT_EXPORT extern const char kHistoryEntryRequiresUserGesture[];
 CONTENT_EXPORT extern const char kHostResolverRules[];
+CONTENT_EXPORT extern const char kIgnoreCertificateErrorsSPKIList[];
 CONTENT_EXPORT extern const char kInertVisualViewport[];
 CONTENT_EXPORT extern const char kInProcessGPU[];
 CONTENT_EXPORT extern const char kIPCConnectionTimeout[];
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index efabfce4..37715d1 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -15,6 +15,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -48,6 +49,8 @@
       is_process_backgrounded_(false),
       is_unused_(true),
       worker_ref_count_(0),
+      shared_bitmap_allocation_notifier_impl_(
+          viz::ServerSharedBitmapManager::current()),
       weak_ptr_factory_(this) {
   // Child process security operations can't be unit tested unless we add
   // ourselves as an existing child process.
@@ -449,4 +452,9 @@
   }
 }
 
+viz::SharedBitmapAllocationNotifierImpl*
+MockRenderProcessHost::GetSharedBitmapAllocationNotifier() {
+  return &shared_bitmap_allocation_notifier_impl_;
+}
+
 }  // namespace content
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index f2802c9..d93ccc69 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -15,6 +15,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/metrics/persistent_memory_allocator.h"
 #include "base/observer_list.h"
+#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_process_host_factory.h"
 #include "ipc/ipc_test_sink.h"
@@ -130,6 +131,8 @@
   bool MayReuseHost() override;
   bool IsUnused() override;
   void SetIsUsed() override;
+  viz::SharedBitmapAllocationNotifierImpl* GetSharedBitmapAllocationNotifier()
+      override;
 
   // IPC::Sender via RenderProcessHost.
   bool Send(IPC::Message* msg) override;
@@ -182,6 +185,8 @@
       renderer_interface_;
   std::map<std::string, InterfaceBinder> binder_overrides_;
   service_manager::Identity child_identity_;
+  viz::SharedBitmapAllocationNotifierImpl
+      shared_bitmap_allocation_notifier_impl_;
   base::WeakPtrFactory<MockRenderProcessHost> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MockRenderProcessHost);
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 8d49131..2bc7194 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -61,12 +61,6 @@
     NOTREACHED();
   }
 
-  void GetSharedBitmapAllocationNotifier(
-      cc::mojom::SharedBitmapAllocationNotifierAssociatedRequest request)
-      override {
-    NOTREACHED();
-  }
-
  private:
   MockRenderThread* const thread_;
 };
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index e5522c4..fd27299 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -259,8 +259,7 @@
 RenderWidgetCompositor::RenderWidgetCompositor(
     RenderWidgetCompositorDelegate* delegate,
     CompositorDependencies* compositor_deps)
-    : num_failed_recreate_attempts_(0),
-      delegate_(delegate),
+    : delegate_(delegate),
       compositor_deps_(compositor_deps),
       threaded_(!!compositor_deps_->GetCompositorImplThreadTaskRunner()),
       never_visible_(false),
@@ -572,10 +571,18 @@
   size_t dalvik_mb = base::SysInfo::DalvikHeapSizeMB();
   size_t physical_mb = base::SysInfo::AmountOfPhysicalMemoryMB();
   size_t physical_memory_mb = 0;
-  if (dalvik_mb >= 256)
+  if (base::SysInfo::IsLowEndDevice()) {
+    // TODO(crbug.com/742534): The code below appears to no longer work.
+    // |dalvik_mb| no longer follows the expected heuristic pattern, causing us
+    // to over-estimate memory on low-end devices. This entire section probably
+    // needs to be re-written, but for now we can address the low-end Android
+    // issues by ignoring |dalvik_mb|.
+    physical_memory_mb = physical_mb;
+  } else if (dalvik_mb >= 256) {
     physical_memory_mb = dalvik_mb * 4;
-  else
+  } else {
     physical_memory_mb = std::max(dalvik_mb * 4, (physical_mb * 4) / 3);
+  }
 
   // Now we take a default of 1/8th of memory on high-memory devices,
   // and gradually scale that back for low-memory devices (to be nicer
@@ -1154,30 +1161,26 @@
   if (delegate_->IsClosing())
     return;
 
-  bool fallback = num_failed_recreate_attempts_ >=
-                  LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK;
-
 #ifdef OS_ANDROID
-  LOG_IF(FATAL, fallback) << "Android does not support fallback frame sinks.";
+  LOG_IF(FATAL, attempt_software_fallback_)
+      << "Android does not support fallback frame sinks.";
 #endif
 
   delegate_->RequestNewLayerTreeFrameSink(
-      fallback, base::Bind(&RenderWidgetCompositor::SetLayerTreeFrameSink,
-                           weak_factory_.GetWeakPtr()));
+      attempt_software_fallback_,
+      base::Bind(&RenderWidgetCompositor::SetLayerTreeFrameSink,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void RenderWidgetCompositor::DidInitializeLayerTreeFrameSink() {
-  num_failed_recreate_attempts_ = 0;
+  attempt_software_fallback_ = false;
 }
 
 void RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink() {
-  ++num_failed_recreate_attempts_;
-  // Tolerate a certain number of recreation failures to work around races
-  // in the output-surface-lost machinery.
-  LOG_IF(FATAL,
-         (num_failed_recreate_attempts_ >= MAX_LAYER_TREE_FRAME_SINK_RETRIES))
+  LOG_IF(FATAL, attempt_software_fallback_)
       << "Failed to create a fallback LayerTreeFrameSink.";
 
+  attempt_software_fallback_ = true;
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(&RenderWidgetCompositor::RequestNewLayerTreeFrameSink,
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index 1743a5a40..bf36242d 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -210,11 +210,6 @@
   void DidLoseLayerTreeFrameSink() override;
   void RequestBeginMainFrameNotExpected(bool new_state) override;
 
-  enum {
-    LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK = 4,
-    MAX_LAYER_TREE_FRAME_SINK_RETRIES = 5,
-  };
-
  protected:
   friend class RenderViewImplScaleFactorTest;
 
@@ -231,7 +226,7 @@
   bool CompositeIsSynchronous() const;
   void SynchronouslyComposite();
 
-  int num_failed_recreate_attempts_;
+  bool attempt_software_fallback_ = false;
   RenderWidgetCompositorDelegate* const delegate_;
   CompositorDependencies* const compositor_deps_;
   const bool threaded_;
diff --git a/content/renderer/gpu/render_widget_compositor_unittest.cc b/content/renderer/gpu/render_widget_compositor_unittest.cc
index 007194b..05192682 100644
--- a/content/renderer/gpu/render_widget_compositor_unittest.cc
+++ b/content/renderer/gpu/render_widget_compositor_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
 #include "cc/animation/animation_host.h"
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/copy_output_request.h"
@@ -34,6 +35,11 @@
 namespace content {
 namespace {
 
+enum FailureMode {
+  NO_FAILURE,
+  GPU_CHANNEL_FAILURE,
+};
+
 class StubRenderWidgetCompositorDelegate
     : public RenderWidgetCompositorDelegate {
  public:
@@ -73,10 +79,6 @@
   void RequestNewLayerTreeFrameSink(
       bool fallback,
       const LayerTreeFrameSinkCallback& callback) override {
-    EXPECT_EQ(num_requests_since_last_success_ >
-                  RenderWidgetCompositor::
-                      LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
-              fallback);
     last_create_was_fallback_ = fallback;
 
     bool success = num_failures_ >= num_failures_before_success_;
@@ -94,6 +96,15 @@
         cc::FakeLayerTreeFrameSink::Create3d(std::move(context_provider)));
   }
 
+  void Reset() {
+    num_requests_ = 0;
+    num_requests_since_last_success_ = 0;
+    num_failures_ = 0;
+    num_failures_before_success_ = 0;
+    num_fallback_successes_ = 0;
+    num_successes_ = 0;
+  }
+
   void add_success() {
     if (last_create_was_fallback_)
       ++num_fallback_successes_;
@@ -123,9 +134,6 @@
   void set_use_null_layer_tree_frame_sink(bool u) {
     use_null_layer_tree_frame_sink_ = u;
   }
-  bool use_null_layer_tree_frame_sink() const {
-    return use_null_layer_tree_frame_sink_;
-  }
 
  private:
   int num_requests_ = 0;
@@ -171,11 +179,11 @@
   }
 
   void DidInitializeLayerTreeFrameSink() override {
+    RenderWidgetCompositor::DidInitializeLayerTreeFrameSink();
     delegate_->add_success();
     if (delegate_->num_requests() == expected_requests_) {
       EndTest();
     } else {
-      RenderWidgetCompositor::DidInitializeLayerTreeFrameSink();
       // Post the synchronous composite task so that it is not called
       // reentrantly as a part of RequestNewLayerTreeFrameSink.
       base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -186,38 +194,48 @@
   }
 
   void DidFailToInitializeLayerTreeFrameSink() override {
+    RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink();
     delegate_->add_failure();
     if (delegate_->num_requests() == expected_requests_) {
       EndTest();
       return;
     }
-
-    RenderWidgetCompositor::DidFailToInitializeLayerTreeFrameSink();
   }
 
-  void SetUp(int expected_successes, int expected_fallback_succeses) {
+  void SetUp(int expected_successes, FailureMode failure_mode) {
+    failure_mode_ = failure_mode;
+    switch (failure_mode_) {
+      case NO_FAILURE:
+        expected_requests_ = 1;
+        break;
+      case GPU_CHANNEL_FAILURE:
+        expected_requests_ = 2;
+        break;
+    }
     expected_successes_ = expected_successes;
-    expected_fallback_successes_ = expected_fallback_succeses;
-    expected_requests_ = delegate_->num_failures_before_success() +
-                         expected_successes_ + expected_fallback_successes_;
+    expected_requests_ += (expected_successes - 1);
   }
 
   void EndTest() { base::MessageLoop::current()->QuitWhenIdle(); }
 
   void AfterTest() {
-    EXPECT_EQ(delegate_->num_failures_before_success(),
-              delegate_->num_failures());
-    EXPECT_EQ(expected_successes_, delegate_->num_successes());
-    EXPECT_EQ(expected_fallback_successes_,
-              delegate_->num_fallback_successes());
+    if (failure_mode_ == NO_FAILURE) {
+      EXPECT_EQ(expected_successes_, delegate_->num_successes());
+      EXPECT_EQ(0, delegate_->num_fallback_successes());
+    } else if (failure_mode_ == GPU_CHANNEL_FAILURE) {
+      EXPECT_EQ(0, delegate_->num_successes());
+      EXPECT_EQ(1, delegate_->num_fallback_successes());
+    } else {
+      NOTREACHED();
+    }
     EXPECT_EQ(expected_requests_, delegate_->num_requests());
   }
 
  private:
   FakeRenderWidgetCompositorDelegate* delegate_;
   int expected_successes_ = 0;
-  int expected_fallback_successes_ = 0;
   int expected_requests_ = 0;
+  FailureMode failure_mode_ = NO_FAILURE;
 
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetLayerTreeFrameSink);
 };
@@ -240,15 +258,14 @@
   }
 
   void RunTest(bool use_null_layer_tree_frame_sink,
-               int num_failures_before_success,
                int expected_successes,
-               int expected_fallback_succeses) {
+               FailureMode failure_mode) {
+    compositor_delegate_.Reset();
     compositor_delegate_.set_use_null_layer_tree_frame_sink(
         use_null_layer_tree_frame_sink);
     compositor_delegate_.set_num_failures_before_success(
-        num_failures_before_success);
-    render_widget_compositor_.SetUp(expected_successes,
-                                    expected_fallback_succeses);
+        failure_mode == NO_FAILURE ? 0 : 1);
+    render_widget_compositor_.SetUp(expected_successes, failure_mode);
     render_widget_compositor_.SetVisible(true);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE,
@@ -270,48 +287,31 @@
 };
 
 TEST_F(RenderWidgetLayerTreeFrameSinkTest, SucceedOnce) {
-  RunTest(false, 0, 1, 0);
+  RunTest(false, 1, NO_FAILURE);
 }
 
 TEST_F(RenderWidgetLayerTreeFrameSinkTest, SucceedTwice) {
-  RunTest(false, 0, 2, 0);
+  RunTest(false, 2, NO_FAILURE);
 }
 
 TEST_F(RenderWidgetLayerTreeFrameSinkTest, FailOnceNull) {
-  static_assert(
-      RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK >=
-          2,
-      "Adjust the values of this test if this fails");
-  RunTest(true, 1, 1, 0);
-}
-
-TEST_F(RenderWidgetLayerTreeFrameSinkTest, FailOnceBind) {
-  static_assert(
-      RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK >=
-          2,
-      "Adjust the values of this test if this fails");
-  RunTest(false, 1, 1, 0);
+  RunTest(true, 1, NO_FAILURE);
 }
 
 // Android doesn't support fallback frame sinks. (crbug.com/721102)
-#ifndef OS_ANDROID
-TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNull) {
-  RunTest(true,
-          RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
-          0, 1);
+#if !defined(OS_ANDROID)
+TEST_F(RenderWidgetLayerTreeFrameSinkTest, SoftwareFallbackSucceed) {
+  RunTest(false, 1, GPU_CHANNEL_FAILURE);
 }
 
-TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessBind) {
-  RunTest(false,
-          RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
-          0, 1);
+TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNull) {
+  RunTest(true, 1, GPU_CHANNEL_FAILURE);
 }
 
 TEST_F(RenderWidgetLayerTreeFrameSinkTest, FallbackSuccessNormalSuccess) {
   // The first success is a fallback, but the next should not be a fallback.
-  RunTest(false,
-          RenderWidgetCompositor::LAYER_TREE_FRAME_SINK_RETRIES_BEFORE_FALLBACK,
-          1, 1);
+  RunTest(false, 1, GPU_CHANNEL_FAILURE);
+  RunTest(false, 1, NO_FAILURE);
 }
 #endif
 
diff --git a/content/renderer/pepper/pepper_plugin_instance_metrics.cc b/content/renderer/pepper/pepper_plugin_instance_metrics.cc
index b0736e7c..2df79b7 100644
--- a/content/renderer/pepper/pepper_plugin_instance_metrics.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_metrics.cc
@@ -11,10 +11,6 @@
 #include "build/build_config.h"
 #include "ppapi/shared_impl/ppapi_preferences.h"
 
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 #define UMA_HISTOGRAM_ASPECT_RATIO(name, width, height) \
   UMA_HISTOGRAM_SPARSE_SLOWLY(                          \
       name, (height) ? ((width)*100) / (height) : kInfiniteRatio);
@@ -84,7 +80,6 @@
 // run Stage3D content on machines that have it blacklisted.
 #if defined(OS_WIN)
   bool needs_gpu = false;
-  bool is_xp = base::win::GetVersion() <= base::win::VERSION_XP;
 
   for (size_t i = 0; i < arg_names.size(); i++) {
     if (arg_names[i] == "wmode") {
@@ -99,12 +94,8 @@
   // 1 : No 3D content and GPU is not blacklisted
   // 2 : 3D content but GPU is blacklisted
   // 3 : 3D content and GPU is not blacklisted
-  // 4 : No 3D content and GPU is blacklisted on XP
-  // 5 : No 3D content and GPU is not blacklisted on XP
-  // 6 : 3D content but GPU is blacklisted on XP
-  // 7 : 3D content and GPU is not blacklisted on XP
-  UMA_HISTOGRAM_ENUMERATION(
-      "Flash.UsesGPU", is_xp * 4 + needs_gpu * 2 + prefs.is_webgl_supported, 8);
+  UMA_HISTOGRAM_ENUMERATION("Flash.UsesGPU",
+                            needs_gpu * 2 + prefs.is_webgl_supported, 8);
 #endif
 }
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 388367820..e22d4f20 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -670,12 +670,13 @@
       IsRunningInMash() ? ui::mojom::kServiceName : mojom::kBrowserServiceName,
       GetIOTaskRunner());
 
-  cc::mojom::SharedBitmapAllocationNotifierAssociatedPtr
+  cc::mojom::SharedBitmapAllocationNotifierPtr
       shared_bitmap_allocation_notifier_ptr;
-  render_message_filter()->GetSharedBitmapAllocationNotifier(
+  GetConnector()->BindInterface(
+      mojom::kBrowserServiceName,
       mojo::MakeRequest(&shared_bitmap_allocation_notifier_ptr));
   shared_bitmap_manager_ = base::MakeUnique<viz::ClientSharedBitmapManager>(
-      cc::mojom::ThreadSafeSharedBitmapAllocationNotifierAssociatedPtr::Create(
+      cc::mojom::ThreadSafeSharedBitmapAllocationNotifierPtr::Create(
           shared_bitmap_allocation_notifier_ptr.PassInterface(),
           GetChannel()->ipc_task_runner_refptr()));
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 934b624..0a7da2c 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -1178,7 +1178,7 @@
     const wchar_t* result;
   };
   static const ImeMessage kImeMessages[] = {
-      // Scenario 1: input a Chinese word with Microsoft IME (on Vista).
+      // Scenario 1: input a Chinese word with Microsoft IME.
       {IME_INITIALIZE, true, 0, 0, NULL, NULL},
       {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
       {IME_SETFOCUS, true, 0, 0, NULL, NULL},
@@ -1188,7 +1188,7 @@
       {IME_SETCOMPOSITION, false, 4, 4, L"niha", L"niha"},
       {IME_SETCOMPOSITION, false, 5, 5, L"nihao", L"nihao"},
       {IME_COMMITTEXT, false, -1, -1, L"\x4F60\x597D", L"\x4F60\x597D"},
-      // Scenario 2: input a Japanese word with Microsoft IME (on Vista).
+      // Scenario 2: input a Japanese word with Microsoft IME.
       {IME_INITIALIZE, true, 0, 0, NULL, NULL},
       {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
       {IME_SETFOCUS, true, 0, 0, NULL, NULL},
@@ -1203,7 +1203,7 @@
       {IME_SETCOMPOSITION, false, 0, 2, L"\x6F22\x5B57", L"\x6F22\x5B57"},
       {IME_FINISHCOMPOSINGTEXT, false, -1, -1, L"", L"\x6F22\x5B57"},
       {IME_CANCELCOMPOSITION, false, -1, -1, L"", L"\x6F22\x5B57"},
-      // Scenario 3: input a Korean word with Microsot IME (on Vista).
+      // Scenario 3: input a Korean word with Microsot IME.
       {IME_INITIALIZE, true, 0, 0, NULL, NULL},
       {IME_SETINPUTMODE, true, 0, 0, NULL, NULL},
       {IME_SETFOCUS, true, 0, 0, NULL, NULL},
@@ -1498,12 +1498,6 @@
 
 #if defined(OS_MACOSX) || defined(USE_AURA)
 TEST_F(RenderViewImplTest, GetCompositionCharacterBoundsTest) {
-#if defined(OS_WIN)
-  // http://crbug.com/304193
-  if (base::win::GetVersion() < base::win::VERSION_VISTA)
-    return;
-#endif
-
   LoadHTML("<textarea id=\"test\" cols=\"100\"></textarea>");
   ExecuteJavaScriptForTests("document.getElementById('test').focus();");
 
diff --git a/content/shell/browser/layout_test/layout_test_url_request_context_getter.cc b/content/shell/browser/layout_test/layout_test_url_request_context_getter.cc
index 0421518..b739b6f0 100644
--- a/content/shell/browser/layout_test/layout_test_url_request_context_getter.cc
+++ b/content/shell/browser/layout_test/layout_test_url_request_context_getter.cc
@@ -10,7 +10,10 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/ignore_errors_cert_verifier.h"
 #include "content/shell/browser/shell_network_delegate.h"
+#include "content/shell/common/layout_test/layout_test_switches.h"
+#include "net/cert/cert_verifier.h"
 #include "net/proxy/proxy_service.h"
 
 namespace content {
@@ -41,6 +44,13 @@
   return base::WrapUnique(new ShellNetworkDelegate);
 }
 
+std::unique_ptr<net::CertVerifier>
+LayoutTestURLRequestContextGetter::GetCertVerifier() {
+  return IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+      *base::CommandLine::ForCurrentProcess(), switches::kRunLayoutTest,
+      net::CertVerifier::CreateDefault());
+}
+
 std::unique_ptr<net::ProxyConfigService>
 LayoutTestURLRequestContextGetter::GetProxyConfigService() {
   return nullptr;
diff --git a/content/shell/browser/layout_test/layout_test_url_request_context_getter.h b/content/shell/browser/layout_test/layout_test_url_request_context_getter.h
index 1fc56da..342eb0f 100644
--- a/content/shell/browser/layout_test/layout_test_url_request_context_getter.h
+++ b/content/shell/browser/layout_test/layout_test_url_request_context_getter.h
@@ -39,6 +39,7 @@
 
   // ShellURLRequestContextGetter implementation.
   std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate() override;
+  std::unique_ptr<net::CertVerifier> GetCertVerifier() override;
   std::unique_ptr<net::ProxyConfigService> GetProxyConfigService() override;
   std::unique_ptr<net::ProxyService> GetProxyService() override;
 
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
index d161f06..a425e2b 100644
--- a/content/shell/browser/shell_url_request_context_getter.cc
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -115,6 +115,11 @@
   return base::WrapUnique(new ShellNetworkDelegate);
 }
 
+std::unique_ptr<net::CertVerifier>
+ShellURLRequestContextGetter::GetCertVerifier() {
+  return net::CertVerifier::CreateDefault();
+}
+
 std::unique_ptr<net::ProxyConfigService>
 ShellURLRequestContextGetter::GetProxyConfigService() {
   return net::ProxyService::CreateSystemProxyConfigService(io_task_runner_);
@@ -153,7 +158,7 @@
         net::HostResolver::CreateDefaultResolver(
             url_request_context_->net_log()));
 
-    storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
+    storage_->set_cert_verifier(GetCertVerifier());
     storage_->set_transport_security_state(
         base::WrapUnique(new net::TransportSecurityState));
     storage_->set_cert_transparency_verifier(
diff --git a/content/shell/browser/shell_url_request_context_getter.h b/content/shell/browser/shell_url_request_context_getter.h
index fdfdac2..fbeb854 100644
--- a/content/shell/browser/shell_url_request_context_getter.h
+++ b/content/shell/browser/shell_url_request_context_getter.h
@@ -18,6 +18,7 @@
 #include "net/url_request/url_request_job_factory.h"
 
 namespace net {
+class CertVerifier;
 class HostResolver;
 class NetworkDelegate;
 class NetLog;
@@ -51,6 +52,7 @@
   // Used by subclasses to create their own implementation of NetworkDelegate
   // and net::ProxyService.
   virtual std::unique_ptr<net::NetworkDelegate> CreateNetworkDelegate();
+  virtual std::unique_ptr<net::CertVerifier> GetCertVerifier();
   virtual std::unique_ptr<net::ProxyConfigService> GetProxyConfigService();
   virtual std::unique_ptr<net::ProxyService> GetProxyService();
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ac1e5a06..21739d7 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1127,7 +1127,6 @@
     "../browser/dom_storage/dom_storage_database_unittest.cc",
     "../browser/dom_storage/local_storage_context_mojo_unittest.cc",
     "../browser/dom_storage/session_storage_database_unittest.cc",
-    "../browser/download/all_download_item_notifier_unittest.cc",
     "../browser/download/base_file_unittest.cc",
     "../browser/download/base_file_win_unittest.cc",
     "../browser/download/download_file_unittest.cc",
@@ -1329,6 +1328,7 @@
     "../browser/shared_worker/shared_worker_instance_unittest.cc",
     "../browser/shared_worker/shared_worker_service_impl_unittest.cc",
     "../browser/site_instance_impl_unittest.cc",
+    "../browser/ssl/ignore_errors_cert_verifier_unittest.cc",
     "../browser/ssl/ssl_manager_unittest.cc",
     "../browser/startup_task_runner_unittest.cc",
     "../browser/storage_partition_impl_map_unittest.cc",
diff --git a/content/test/content_browser_test_test.cc b/content/test/content_browser_test_test.cc
index 446349da..f9799b6d 100644
--- a/content/test/content_browser_test_test.cc
+++ b/content/test/content_browser_test_test.cc
@@ -25,10 +25,6 @@
 #include "content/shell/common/shell_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
 namespace content {
 
 // Disabled on official builds because symbolization in sandboxes processes
@@ -73,13 +69,6 @@
 
 // Tests that browser tests print the callstack when a child process crashes.
 IN_PROC_BROWSER_TEST_F(ContentBrowserTest, RendererCrashCallStack) {
-#if defined(OS_WIN)
-  // Matches the same condition in RouteStdioToConsole, which makes this test
-  // fail on XP.
-  if (base::win::GetVersion() < base::win::VERSION_VISTA)
-    return;
-#endif
-
   base::ThreadRestrictions::ScopedAllowIO allow_io_for_temp_dir;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 935ae4d..9d982ee 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -63,6 +63,8 @@
         bug=1966) # angle bug ID
 
     # Windows only.
+    self.Fail('conformance/glsl/bugs/sampler-struct-function-arg.html',
+        ['win'], bug=2103) # angle bug ID
     self.Fail('conformance2/rendering/blitframebuffer-outside-readbuffer.html',
         ['win', 'd3d11'], bug=644740)
     self.Fail('conformance2/textures/misc/tex-base-level-bug.html',
@@ -70,6 +72,8 @@
     self.Flaky('conformance2/textures/svg_image/' +
         'tex-2d-rgb565-rgb-unsigned_short_5_6_5.html',
         ['win'], bug=736926)
+    self.Fail('conformance2/uniforms/uniform-blocks-with-arrays.html',
+        ['win'], bug=2103) # angle bug ID
 
     # Win / NVidia
     self.Flaky('deqp/functional/gles3/fbomultisample*',
@@ -382,6 +386,10 @@
         ['mac', ('nvidia', 0xfe9)], bug=654187)
 
     # Mac AMD
+    self.Fail('conformance/rendering/texture-switch-performance.html',
+        ['mac', 'amd'], bug=735483)
+    self.Fail('conformance2/rendering/texture-switch-performance.html',
+        ['mac', 'amd'], bug=735483)
     self.Fail('deqp/functional/gles3/transformfeedback/' +
         'array_interleaved_lines.html',
         ['mac', 'amd'], bug=483282)
@@ -587,6 +595,8 @@
         ['linux', 'nvidia'], bug=679677)
     self.Fail('conformance2/rendering/framebuffer-texture-level1.html',
         ['linux', 'nvidia', 'opengl'], bug=680278)
+    self.Fail('conformance2/rendering/multisampling-fragment-evaluation.html',
+        ['linux', 'nvidia', 'no_passthrough'], bug=682815)
     self.Fail('conformance2/textures/image/' +
         'tex-3d-rg8ui-rg_integer-unsigned_byte.html',
         ['linux', ('nvidia', 0xf02)], bug=680282)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index bdde5f75..ecfb0f4 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -195,6 +195,9 @@
         ['win', 'nvidia', 'passthrough', 'd3d11'], bug=737016)
 
     # Win failures
+    # TODO(kbr): re-enable suppression for same test below once fixed.
+    self.Fail('conformance/glsl/bugs/sampler-struct-function-arg.html',
+        ['win'], bug=2103) # angle bug ID
     # Note that the following test seems to pass, but it may still be flaky.
     self.Fail('conformance/glsl/constructors/' +
               'glsl-construct-vec-mat-index.html',
@@ -314,8 +317,8 @@
         ['win', 'intel', 'opengl'], bug=1007) # angle bug ID
     self.Fail('conformance/uniforms/uniform-default-values.html',
         ['win', 'intel', 'opengl'], bug=1007) # angle bug ID
-    self.Fail('conformance/glsl/bugs/sampler-struct-function-arg.html',
-        ['win10', 'intel', 'opengl'], bug=1007) # angle bug ID
+    # self.Fail('conformance/glsl/bugs/sampler-struct-function-arg.html',
+    #     ['win10', 'intel', 'opengl'], bug=1007) # angle bug ID
     self.Fail('conformance/glsl/variables/gl-pointcoord.html',
         ['win10', 'intel', 'opengl'], bug=1007) # angle bug ID
 
@@ -376,6 +379,8 @@
         ['mac', 'amd', 'no_passthrough'], bug=625365)
     self.Fail('conformance/rendering/clipping-wide-points.html',
         ['mac', 'amd'], bug=642822)
+    self.Fail('conformance/rendering/texture-switch-performance.html',
+        ['mac', 'amd'], bug=735483)
 
     # Mac Retina NVidia failures
     self.Fail('conformance/attribs/gl-disabled-vertex-attrib.html',
@@ -468,6 +473,16 @@
     self.Skip('conformance/textures/misc/texture-npot-video.html',
         ['android', 'android-webview-instrumentation', 'no_passthrough'],
               bug=352645)
+    # New video-to-luminance-alpha tests are failing on Android right now.
+    self.Fail('conformance/textures/video/' +
+        'tex-2d-alpha-alpha-unsigned_byte.html',
+        ['android'], bug=733599)
+    self.Fail('conformance/textures/video/' +
+        'tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html',
+        ['android'], bug=733599)
+    self.Fail('conformance/textures/video/' +
+        'tex-2d-luminance-luminance-unsigned_byte.html',
+        ['android'], bug=733599)
     # This crashes in Android WebView on the Nexus 6, preventing the
     # suite from running further. Rather than add multiple
     # suppressions, skip it until it's passing at least in content
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index ef76714..223e1a0 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 5e57726d6fe2833c957b5a33cd0aed19d67a4fa9
+Current webgl revision 72eda82d069da578af04e5c4e8e411ae006b6a18
diff --git a/docs/callback.md b/docs/callback.md
index 5f93ad6a..3c5fec5d 100644
--- a/docs/callback.md
+++ b/docs/callback.md
@@ -76,7 +76,9 @@
 When you pass a `Callback` object to a function parameter, use `std::move()` if
 you don't need to keep a reference to it, otherwise, pass the object directly.
 You may see a compile error when the function requires the exclusive ownership,
-and you didn't pass the callback by move.
+and you didn't pass the callback by move. Note that the moved-from `Callback`
+becomes null, as if its `Reset()` method had been called, and its `is_null()`
+method will return true.
 
 ## Quick reference for basic stuff
 
diff --git a/docs/speed/README.md b/docs/speed/README.md
index 7421f550..967349e 100644
--- a/docs/speed/README.md
+++ b/docs/speed/README.md
@@ -17,7 +17,6 @@
   * [I want Chrome to have better performance](help_improve_performance.md)
   * [Perf sheriffing documentation](perf_regression_sheriffing.md)
   * [I want to add tests or platforms to the perf waterfall](adding_tests_bots.md)
-  * [I'm looking for more information on the Speed Progam](speed_program.md)
 
 ## Core Teams and Work
 
diff --git a/docs/testing/web_platform_tests.md b/docs/testing/web_platform_tests.md
index acdf2cc..36f2dae 100644
--- a/docs/testing/web_platform_tests.md
+++ b/docs/testing/web_platform_tests.md
@@ -63,20 +63,38 @@
 
 ### Automatic export process
 
-If a commit to Chromium master changes any files in the
-[third_party/WebKit/LayoutTests/external/wpt](../../third_party/WebKit/LayoutTests/external/wpt)
-directory, the WPT Exporter will create a Pull Request on GitHub for it.
-All PRs use the `chromium-export` label: see
-[all of them here](https://github.com/w3c/web-platform-tests/pulls?utf8=%E2%9C%93&q=is%3Apr%20label%3Achromium-export).
-The exporter runs continuously under the chromium.infra.cron master:
-see [all recent builds](https://build.chromium.org/p/chromium.infra.cron/builders/wpt-exporter).
-The source for the exporter lives in
-[third_party/WebKit/Tools/Scripts/wpt-exporter](../../third_party/WebKit/Tools/Scripts/wpt-exporter).
+If you upload a CL with any changes in
+[third_party/WebKit/LayoutTests/external/wpt](../../third_party/WebKit/LayoutTests/external/wpt),
+once you add reviewers the exporter will create a provisional pull request with
+those changes in the [upstream WPT GitHub repository](https://github.com/w3c/web-platform-tests/).
 
-In the unlikely event that the exporter starts misbehaving -- for example,
-creating the same PR over and over again -- **all you need to do to disable the
-exporter is [land this CL](https://chromium-review.googlesource.com/c/462381/)**,
-which will put it in "dry run" mode.
+Once you're ready to land your CL, please check the Travis CI status on the
+upstream PR (link at the bottom of the page). If it's green, go ahead and land your CL
+and the exporter will automatically remove the "do not merge yet" label and merge the PR.
+
+If Travis CI is red on the upstream PR, please try to resolve the failures before
+merging. If you run into Travis CI issues, or if you have a CL with WPT changes that
+the exporter did not pick up, please reach out to ecosystem-infra@chromium.org.
+
+Additional things to note:
+
+-   CLs that change over 1000 files will not be exported.
+-   All PRs use the
+    [`chromium-export`](https://github.com/w3c/web-platform-tests/pulls?utf8=%E2%9C%93&q=is%3Apr%20label%3Achromium-export) label.
+-   All PRs for CLs that haven't yet been landed in Chromium also use the
+    [`do not merge yet`](https://github.com/w3c/web-platform-tests/pulls?q=is%3Apr+is%3Aopen+label%3A%22do+not+merge+yet%22) label.
+-   The exporter cannot create upstream PRs for in-flight CLs with binary files (e.g. webm files).
+    An export PR will still be made after the CL lands.
+
+For maintainers:
+
+-   The exporter runs continuously under the
+    [chromium.infra.cron master](https://build.chromium.org/p/chromium.infra.cron/builders/wpt-exporter).
+-   The source lives in
+    [third_party/WebKit/Tools/Scripts/wpt-exporter](../../third_party/WebKit/Tools/Scripts/wpt-exporter).
+-   If the exporter starts misbehaving
+    (for example, creating the same PR over and over again)
+    put it in "dry run" mode by landing [this CL](https://crrev.com/c/462381/).
 
 ### Skipped tests
 
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.cc b/extensions/browser/api/cast_channel/cast_channel_api.cc
index 811b681d..94f90eb 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_api.cc
@@ -22,7 +22,6 @@
 #include "components/cast_channel/cast_message_util.h"
 #include "components/cast_channel/cast_socket.h"
 #include "components/cast_channel/cast_socket_service.h"
-#include "components/cast_channel/cast_socket_service_factory.h"
 #include "components/cast_channel/keep_alive_delegate.h"
 #include "components/cast_channel/logger.h"
 #include "components/cast_channel/proto/cast_channel.pb.h"
@@ -137,6 +136,18 @@
   }
 }
 
+cast_channel::CastSocket::Observer* CastChannelAPI::GetObserver(
+    const std::string& extension_id,
+    scoped_refptr<cast_channel::Logger> logger) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  if (!observer_) {
+    observer_.reset(new CastMessageHandler(
+        base::Bind(&CastChannelAPI::SendEvent, this->AsWeakPtr(), extension_id),
+        logger));
+  }
+  return observer_.get();
+}
+
 static base::LazyInstance<
     BrowserContextKeyedAPIFactory<CastChannelAPI>>::DestructorAtExit g_factory =
     LAZY_INSTANCE_INITIALIZER;
@@ -168,9 +179,7 @@
 CastChannelAsyncApiFunction::~CastChannelAsyncApiFunction() { }
 
 bool CastChannelAsyncApiFunction::PrePrepare() {
-  cast_socket_service_ =
-      cast_channel::CastSocketServiceFactory::GetForBrowserContext(
-          browser_context());
+  cast_socket_service_ = cast_channel::CastSocketService::GetInstance();
   DCHECK(cast_socket_service_);
   return true;
 }
@@ -277,14 +286,8 @@
   if (test_socket.get())
     cast_socket_service_->SetSocketForTest(std::move(test_socket));
 
-  auto* observer = cast_socket_service_->GetObserver(extension_->id());
-  if (!observer) {
-    observer = cast_socket_service_->AddObserver(
-        extension_->id(), base::MakeUnique<CastMessageHandler>(
-                              base::Bind(&CastChannelAPI::SendEvent,
-                                         api_->AsWeakPtr(), extension_->id()),
-                              cast_socket_service_->GetLogger()));
-  }
+  auto* observer =
+      api_->GetObserver(extension_->id(), cast_socket_service_->GetLogger());
 
   cast_socket_service_->OpenSocket(
       *ip_endpoint_, ExtensionsBrowserClient::Get()->GetNetLog(),
@@ -422,20 +425,23 @@
   AsyncWorkCompleted();
 }
 
-CastChannelOpenFunction::CastMessageHandler::CastMessageHandler(
+CastChannelAPI::CastMessageHandler::CastMessageHandler(
     const EventDispatchCallback& ui_dispatch_cb,
     scoped_refptr<Logger> logger)
     : ui_dispatch_cb_(ui_dispatch_cb), logger_(logger) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(logger_);
 }
 
-CastChannelOpenFunction::CastMessageHandler::~CastMessageHandler() {
+CastChannelAPI::CastMessageHandler::~CastMessageHandler() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  cast_channel::CastSocketService::GetInstance()->RemoveObserver(this);
 }
 
-void CastChannelOpenFunction::CastMessageHandler::OnError(
+void CastChannelAPI::CastMessageHandler::OnError(
     const cast_channel::CastSocket& socket,
     ChannelError error_state) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   ChannelInfo channel_info;
   FillChannelInfo(socket, &channel_info);
@@ -453,10 +459,10 @@
       base::Bind(ui_dispatch_cb_, base::Passed(std::move(event))));
 }
 
-void CastChannelOpenFunction::CastMessageHandler::OnMessage(
+void CastChannelAPI::CastMessageHandler::OnMessage(
     const cast_channel::CastSocket& socket,
     const CastMessage& message) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   MessageInfo message_info;
   CastMessageToMessageInfo(message, &message_info);
diff --git a/extensions/browser/api/cast_channel/cast_channel_api.h b/extensions/browser/api/cast_channel/cast_channel_api.h
index c65af793..69c2a74 100644
--- a/extensions/browser/api/cast_channel/cast_channel_api.h
+++ b/extensions/browser/api/cast_channel/cast_channel_api.h
@@ -60,11 +60,49 @@
   // Sends an event to the extension's EventRouter, if it exists.
   void SendEvent(const std::string& extension_id, std::unique_ptr<Event> event);
 
+  // Registers |extension_id| with |observer_| and returns |observer_|.
+  cast_channel::CastSocket::Observer* GetObserver(
+      const std::string& extension_id,
+      scoped_refptr<cast_channel::Logger> logger);
+
  private:
   friend class BrowserContextKeyedAPIFactory<CastChannelAPI>;
   friend class ::CastChannelAPITest;
   friend class CastTransportDelegate;
 
+  // Defines a callback used to send events to the extension's
+  // EventRouter.
+  //     Parameter #0 is a unique pointer to the event payload.
+  using EventDispatchCallback = base::Callback<void(std::unique_ptr<Event>)>;
+
+  // Receives incoming messages and errors and provides additional API context.
+  class CastMessageHandler : public cast_channel::CastSocket::Observer {
+   public:
+    CastMessageHandler(const EventDispatchCallback& ui_dispatch_cb,
+                       scoped_refptr<cast_channel::Logger> logger);
+    ~CastMessageHandler() override;
+
+    // CastSocket::Observer implementation.
+    void OnError(const cast_channel::CastSocket& socket,
+                 cast_channel::ChannelError error_state) override;
+    void OnMessage(const cast_channel::CastSocket& socket,
+                   const cast_channel::CastMessage& message) override;
+
+    void RegisterExtensionId(const std::string& extension_id);
+
+   private:
+    // Callback for sending events to the extension.
+    // Should be bound to a weak pointer, to prevent any use-after-free
+    // conditions.
+    EventDispatchCallback const ui_dispatch_cb_;
+    // Logger object for reporting error details.
+    scoped_refptr<cast_channel::Logger> logger_;
+
+    THREAD_CHECKER(thread_checker_);
+
+    DISALLOW_COPY_AND_ASSIGN(CastMessageHandler);
+  };
+
   ~CastChannelAPI() override;
 
   // BrowserContextKeyedAPI implementation.
@@ -72,6 +110,9 @@
 
   content::BrowserContext* const browser_context_;
   std::unique_ptr<cast_channel::CastSocket> socket_for_test_;
+  // Created and destroyed on the IO thread.
+  std::unique_ptr<CastMessageHandler, content::BrowserThread::DeleteOnIOThread>
+      observer_;
 
   DISALLOW_COPY_AND_ASSIGN(CastChannelAPI);
 };
@@ -96,8 +137,9 @@
   void SetResultFromError(int channel_id,
                           api::cast_channel::ChannelError error);
 
-  // Manages creating and removing Cast sockets.
-  scoped_refptr<cast_channel::CastSocketService> cast_socket_service_;
+  // Raw pointer of leaky singleton CastSocketService, which manages creating
+  // and removing Cast sockets.
+  cast_channel::CastSocketService* cast_socket_service_;
 
  private:
   // Sets the function result from |channel_info|.
@@ -120,35 +162,6 @@
  private:
   DECLARE_EXTENSION_FUNCTION("cast.channel.open", CAST_CHANNEL_OPEN)
 
-  // Defines a callback used to send events to the extension's
-  // EventRouter.
-  //     Parameter #0 is a scoped pointer to the event payload.
-  using EventDispatchCallback = base::Callback<void(std::unique_ptr<Event>)>;
-
-  // Receives incoming messages and errors and provides additional API context.
-  class CastMessageHandler : public cast_channel::CastSocket::Observer {
-   public:
-    CastMessageHandler(const EventDispatchCallback& ui_dispatch_cb,
-                       scoped_refptr<cast_channel::Logger> logger);
-    ~CastMessageHandler() override;
-
-    // CastSocket::Observer implementation.
-    void OnError(const cast_channel::CastSocket& socket,
-                 cast_channel::ChannelError error_state) override;
-    void OnMessage(const cast_channel::CastSocket& socket,
-                   const cast_channel::CastMessage& message) override;
-
-   private:
-    // Callback for sending events to the extension.
-    // Should be bound to a weak pointer, to prevent any use-after-free
-    // conditions.
-    EventDispatchCallback const ui_dispatch_cb_;
-    // Logger object for reporting error details.
-    scoped_refptr<cast_channel::Logger> logger_;
-
-    DISALLOW_COPY_AND_ASSIGN(CastMessageHandler);
-  };
-
   // Validates that |connect_info| represents a valid IP end point and returns a
   // new IPEndPoint if so.  Otherwise returns nullptr.
   static net::IPEndPoint* ParseConnectInfo(
diff --git a/extensions/browser/api/cast_channel/cast_channel_apitest.cc b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
index b3d76cb..a93e7b54 100644
--- a/extensions/browser/api/cast_channel/cast_channel_apitest.cc
+++ b/extensions/browser/api/cast_channel/cast_channel_apitest.cc
@@ -14,7 +14,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "components/cast_channel/cast_socket.h"
 #include "components/cast_channel/cast_socket_service.h"
-#include "components/cast_channel/cast_socket_service_factory.h"
 #include "components/cast_channel/cast_test_util.h"
 #include "components/cast_channel/logger.h"
 #include "components/cast_channel/proto/cast_channel.pb.h"
@@ -145,8 +144,11 @@
           .WillOnce(Return(ReadyState::OPEN))
           .RetiresOnSaturation();
       EXPECT_CALL(*mock_cast_socket_, ready_state())
-          .WillOnce(Return(ReadyState::CLOSED));
+          .Times(2)
+          .WillRepeatedly(Return(ReadyState::CLOSED));
     }
+    EXPECT_CALL(*mock_cast_socket_, Close(_))
+        .WillOnce(InvokeCompletionCallback<0>(net::OK));
   }
 
   extensions::CastChannelAPI* GetApi() {
@@ -154,9 +156,7 @@
   }
 
   cast_channel::CastSocketService* GetCastSocketService() {
-    return cast_channel::CastSocketServiceFactory::GetForBrowserContext(
-               profile())
-        .get();
+    return cast_channel::CastSocketService::GetInstance();
   }
 
   // Logs some bogus error details and calls the OnError handler.
@@ -224,7 +224,7 @@
   content::BrowserThread::PostTask(
       content::BrowserThread::IO, FROM_HERE,
       base::Bind(&CastChannelAPITest::DoCallOnError, base::Unretained(api_test),
-                 base::RetainedRef(cast_socket_service)));
+                 base::Unretained(cast_socket_service)));
 }
 
 // TODO(kmarshall): Win Dbg has a workaround that makes RunExtensionSubtest
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 5ce0945..e40ca95 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -214,8 +215,8 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedExtensionPrefUpdate);
 };
 
-std::string JoinPrefs(const std::string& parent, const char* child) {
-  return parent + "." + child;
+std::string JoinPrefs(base::StringPiece parent, base::StringPiece child) {
+  return base::JoinString({parent, child}, ".");
 }
 
 // Checks if kPrefBlacklist is set to true in the base::DictionaryValue.
@@ -435,7 +436,7 @@
 
 void ExtensionPrefs::UpdateExtensionPref(
     const std::string& extension_id,
-    const std::string& key,
+    base::StringPiece key,
     std::unique_ptr<base::Value> data_value) {
   if (!crx_file::id_util::IdIsValid(extension_id)) {
     NOTREACHED() << "Invalid extension_id " << extension_id;
@@ -457,7 +458,7 @@
 }
 
 bool ExtensionPrefs::ReadPrefAsBoolean(const std::string& extension_id,
-                                       const std::string& pref_key,
+                                       base::StringPiece pref_key,
                                        bool* out_value) const {
   const base::DictionaryValue* ext = GetExtensionPref(extension_id);
   if (!ext || !ext->GetBoolean(pref_key, out_value))
@@ -467,7 +468,7 @@
 }
 
 bool ExtensionPrefs::ReadPrefAsInteger(const std::string& extension_id,
-                                       const std::string& pref_key,
+                                       base::StringPiece pref_key,
                                        int* out_value) const {
   const base::DictionaryValue* ext = GetExtensionPref(extension_id);
   if (!ext || !ext->GetInteger(pref_key, out_value))
@@ -477,7 +478,7 @@
 }
 
 bool ExtensionPrefs::ReadPrefAsString(const std::string& extension_id,
-                                      const std::string& pref_key,
+                                      base::StringPiece pref_key,
                                       std::string* out_value) const {
   const base::DictionaryValue* ext = GetExtensionPref(extension_id);
   if (!ext || !ext->GetString(pref_key, out_value))
@@ -487,7 +488,7 @@
 }
 
 bool ExtensionPrefs::ReadPrefAsList(const std::string& extension_id,
-                                    const std::string& pref_key,
+                                    base::StringPiece pref_key,
                                     const base::ListValue** out_value) const {
   const base::DictionaryValue* ext = GetExtensionPref(extension_id);
   const base::ListValue* out = NULL;
@@ -501,7 +502,7 @@
 
 bool ExtensionPrefs::ReadPrefAsDictionary(
     const std::string& extension_id,
-    const std::string& pref_key,
+    base::StringPiece pref_key,
     const base::DictionaryValue** out_value) const {
   const base::DictionaryValue* ext = GetExtensionPref(extension_id);
   const base::DictionaryValue* out = NULL;
@@ -519,7 +520,7 @@
 }
 
 bool ExtensionPrefs::ReadPrefAsURLPatternSet(const std::string& extension_id,
-                                             const std::string& pref_key,
+                                             base::StringPiece pref_key,
                                              URLPatternSet* result,
                                              int valid_schemes) const {
   const base::ListValue* value = NULL;
@@ -540,21 +541,21 @@
 
 void ExtensionPrefs::SetExtensionPrefURLPatternSet(
     const std::string& extension_id,
-    const std::string& pref_key,
+    base::StringPiece pref_key,
     const URLPatternSet& new_value) {
   UpdateExtensionPref(extension_id, pref_key, new_value.ToValue());
 }
 
 bool ExtensionPrefs::ReadPrefAsBooleanAndReturn(
     const std::string& extension_id,
-    const std::string& pref_key) const {
+    base::StringPiece pref_key) const {
   bool out_value = false;
   return ReadPrefAsBoolean(extension_id, pref_key, &out_value) && out_value;
 }
 
 std::unique_ptr<const PermissionSet> ExtensionPrefs::ReadPrefAsPermissionSet(
     const std::string& extension_id,
-    const std::string& pref_key) const {
+    base::StringPiece pref_key) const {
   if (!GetExtensionPref(extension_id))
     return nullptr;
 
@@ -625,7 +626,7 @@
 
 void ExtensionPrefs::SetExtensionPrefPermissionSet(
     const std::string& extension_id,
-    const std::string& pref_key,
+    base::StringPiece pref_key,
     const PermissionSet& new_value) {
   std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
   UpdateExtensionPref(extension_id, api_pref,
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index b4395f93..9e2f4f10 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -12,6 +12,7 @@
 
 #include "base/macros.h"
 #include "base/observer_list.h"
+#include "base/strings/string_piece_forward.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -247,30 +248,30 @@
 
   // ExtensionScopedPrefs methods:
   void UpdateExtensionPref(const std::string& id,
-                           const std::string& key,
+                           base::StringPiece key,
                            std::unique_ptr<base::Value> value) override;
 
   void DeleteExtensionPrefs(const std::string& id) override;
 
   bool ReadPrefAsBoolean(const std::string& extension_id,
-                         const std::string& pref_key,
+                         base::StringPiece pref_key,
                          bool* out_value) const override;
 
   bool ReadPrefAsInteger(const std::string& extension_id,
-                         const std::string& pref_key,
+                         base::StringPiece pref_key,
                          int* out_value) const override;
 
   bool ReadPrefAsString(const std::string& extension_id,
-                        const std::string& pref_key,
+                        base::StringPiece pref_key,
                         std::string* out_value) const override;
 
   bool ReadPrefAsList(const std::string& extension_id,
-                      const std::string& pref_key,
+                      base::StringPiece pref_key,
                       const base::ListValue** out_value) const override;
 
   bool ReadPrefAsDictionary(
       const std::string& extension_id,
-      const std::string& pref_key,
+      base::StringPiece pref_key,
       const base::DictionaryValue** out_value) const override;
 
   bool HasPrefForExtension(const std::string& extension_id) const override;
@@ -601,7 +602,7 @@
   // Interprets the list pref, |pref_key| in |extension_id|'s preferences, as a
   // URLPatternSet. The |valid_schemes| specify how to parse the URLPatterns.
   bool ReadPrefAsURLPatternSet(const std::string& extension_id,
-                               const std::string& pref_key,
+                               base::StringPiece pref_key,
                                URLPatternSet* result,
                                int valid_schemes) const;
 
@@ -614,24 +615,24 @@
   // Converts |new_value| to a list of strings and sets the |pref_key| pref
   // belonging to |extension_id|.
   void SetExtensionPrefURLPatternSet(const std::string& extension_id,
-                                     const std::string& pref_key,
+                                     base::StringPiece pref_key,
                                      const URLPatternSet& new_value);
 
   // Read the boolean preference entry and return true if the preference exists
   // and the preference's value is true; false otherwise.
   bool ReadPrefAsBooleanAndReturn(const std::string& extension_id,
-                                  const std::string& key) const;
+                                  base::StringPiece pref_key) const;
 
   // Interprets |pref_key| in |extension_id|'s preferences as an
   // PermissionSet, and passes ownership of the set to the caller.
   std::unique_ptr<const PermissionSet> ReadPrefAsPermissionSet(
       const std::string& extension_id,
-      const std::string& pref_key) const;
+      base::StringPiece pref_key) const;
 
   // Converts the |new_value| to its value and sets the |pref_key| pref
   // belonging to |extension_id|.
   void SetExtensionPrefPermissionSet(const std::string& extension_id,
-                                     const std::string& pref_key,
+                                     base::StringPiece pref_key,
                                      const PermissionSet& new_value);
 
   // Returns an immutable dictionary for extension |id|'s prefs, or NULL if it
diff --git a/extensions/browser/extension_scoped_prefs.h b/extensions/browser/extension_scoped_prefs.h
index f814db7..2e988d8 100644
--- a/extensions/browser/extension_scoped_prefs.h
+++ b/extensions/browser/extension_scoped_prefs.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 
+#include "base/strings/string_piece_forward.h"
+
 namespace base {
 class DictionaryValue;
 class ListValue;
@@ -23,7 +25,7 @@
 
   // Sets the pref |key| for extension |id| to |value|.
   virtual void UpdateExtensionPref(const std::string& id,
-                                   const std::string& key,
+                                   base::StringPiece key,
                                    std::unique_ptr<base::Value> value) = 0;
 
   // Deletes the pref dictionary for extension |id|.
@@ -31,28 +33,28 @@
 
   // Reads a boolean pref |pref_key| from extension with id |extension_id|.
   virtual bool ReadPrefAsBoolean(const std::string& extension_id,
-                                 const std::string& pref_key,
+                                 base::StringPiece pref_key,
                                  bool* out_value) const = 0;
 
   // Reads an integer pref |pref_key| from extension with id |extension_id|.
   virtual bool ReadPrefAsInteger(const std::string& extension_id,
-                                 const std::string& pref_key,
+                                 base::StringPiece pref_key,
                                  int* out_value) const = 0;
 
   // Reads a string pref |pref_key| from extension with id |extension_id|.
   virtual bool ReadPrefAsString(const std::string& extension_id,
-                                const std::string& pref_key,
+                                base::StringPiece pref_key,
                                 std::string* out_value) const = 0;
 
   // Reads a list pref |pref_key| from extension with id |extension_id|.
   virtual bool ReadPrefAsList(const std::string& extension_id,
-                              const std::string& pref_key,
+                              base::StringPiece pref_key,
                               const base::ListValue** out_value) const = 0;
 
   // Reads a dictionary pref |pref_key| from extension with id |extension_id|.
   virtual bool ReadPrefAsDictionary(
       const std::string& extension_id,
-      const std::string& pref_key,
+      base::StringPiece pref_key,
       const base::DictionaryValue** out_value) const = 0;
 
   // Returns true if the prefs contain an entry for an extension with id
diff --git a/extensions/renderer/user_script_set.cc b/extensions/renderer/user_script_set.cc
index b4ed9cc..6288a37 100644
--- a/extensions/renderer/user_script_set.cc
+++ b/extensions/renderer/user_script_set.cc
@@ -8,6 +8,7 @@
 
 #include <utility>
 
+#include "base/debug/alias.h"
 #include "base/memory/ref_counted.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/renderer/render_frame.h"
@@ -35,6 +36,11 @@
 // user script to wrap it in an anonymous scope.
 const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
 const char kUserScriptTail[] = "\n})(window);";
+// Maximum number of total content scripts we allow (across all extensions).
+// The limit exists to diagnose https://crbug.com/723381. The number is
+// arbitrarily chosen.
+// TODO(lazyboy): Remove when the bug is fixed.
+const uint32_t kNumScriptsArbitraryMax = 100000u;
 
 GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
   GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
@@ -115,8 +121,14 @@
   base::Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
                       pickle_size);
   base::PickleIterator iter(pickle);
+  base::debug::Alias(&pickle_size);
   CHECK(iter.ReadUInt32(&num_scripts));
 
+  // Sometimes the shared memory contents seem to be corrupted
+  // (https://crbug.com/723381). Set an arbitrary max limit to the number of
+  // scripts so that we don't add OOM noise to crash reports.
+  CHECK_LT(num_scripts, kNumScriptsArbitraryMax);
+
   scripts_.clear();
   script_sources_.clear();
   scripts_.reserve(num_scripts);
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.h b/ios/public/provider/chrome/browser/chrome_browser_provider.h
index 5a0c81a4..5792a70 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.h
@@ -157,6 +157,9 @@
   // Returns an instance of the spotlight provider.
   virtual SpotlightProvider* GetSpotlightProvider() const;
 
+  // Checks for native iOS apps that are installed.
+  virtual void CheckForFirstPartyApps() const;
+
   // Adds and removes observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/ios/public/provider/chrome/browser/chrome_browser_provider.mm b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
index 8f9a57c..a6628c9 100644
--- a/ios/public/provider/chrome/browser/chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/chrome_browser_provider.mm
@@ -108,6 +108,8 @@
   return nullptr;
 }
 
+void ChromeBrowserProvider::CheckForFirstPartyApps() const {}
+
 BrandedImageProvider* ChromeBrowserProvider::GetBrandedImageProvider() const {
   return nullptr;
 }
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
index 7fdc76b..d7f95ea 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.h
@@ -33,6 +33,7 @@
   OmahaServiceProvider* GetOmahaServiceProvider() const override;
   UserFeedbackProvider* GetUserFeedbackProvider() const override;
   SpotlightProvider* GetSpotlightProvider() const override;
+  void CheckForFirstPartyApps() const override;
   BrandedImageProvider* GetBrandedImageProvider() const override;
   id<NativeAppWhitelistManager> GetNativeAppWhitelistManager() const override;
 
diff --git a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
index b61186e..c4c9b6a 100644
--- a/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
+++ b/ios/public/provider/chrome/browser/test_chrome_browser_provider.mm
@@ -90,6 +90,8 @@
   return spotlight_provider_.get();
 }
 
+void TestChromeBrowserProvider::CheckForFirstPartyApps() const {}
+
 BrandedImageProvider* TestChromeBrowserProvider::GetBrandedImageProvider()
     const {
   return branded_image_provider_.get();
diff --git a/ios/testing/perf/startupLoggers.mm b/ios/testing/perf/startupLoggers.mm
index 389e919..38bd2ec 100644
--- a/ios/testing/perf/startupLoggers.mm
+++ b/ios/testing/perf/startupLoggers.mm
@@ -28,7 +28,6 @@
 
 void RegisterAppDidBecomeActiveTime() {
   DCHECK(g_start_time);
-  DCHECK(!g_become_active_time);
   g_become_active_time = new base::Time(base::Time::Now());
 }
 
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index cd97490..ae7e467 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -27,6 +27,7 @@
   "public/cwv_html_element.h",
   "public/cwv_navigation_action.h",
   "public/cwv_navigation_delegate.h",
+  "public/cwv_preferences.h",
   "public/cwv_scroll_view.h",
   "public/cwv_scroll_view_delegate.h",
   "public/cwv_translation_controller.h",
@@ -49,6 +50,8 @@
   "internal/cwv_html_element_internal.h",
   "internal/cwv_navigation_action.mm",
   "internal/cwv_navigation_action_internal.h",
+  "internal/cwv_preferences.mm",
+  "internal/cwv_preferences_internal.h",
   "internal/cwv_scroll_view.mm",
   "internal/cwv_scroll_view_internal.h",
   "internal/cwv_user_content_controller.mm",
diff --git a/ios/web_view/internal/cwv_preferences.mm b/ios/web_view/internal/cwv_preferences.mm
new file mode 100644
index 0000000..7ebd2ed
--- /dev/null
+++ b/ios/web_view/internal/cwv_preferences.mm
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web_view/internal/cwv_preferences_internal.h"
+
+#include "components/prefs/pref_service.h"
+#include "components/translate/core/browser/translate_pref_names.h"
+#include "components/translate/core/browser/translate_prefs.h"
+#include "ios/web_view/internal/pref_names.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation CWVPreferences {
+  PrefService* _prefService;
+}
+
+- (instancetype)initWithPrefService:(PrefService*)prefService {
+  self = [super init];
+  if (self) {
+    _prefService = prefService;
+  }
+  return self;
+}
+
+#pragma mark - Public Methods
+
+- (void)setTranslationEnabled:(BOOL)enabled {
+  _prefService->SetBoolean(prefs::kEnableTranslate, enabled);
+}
+
+- (BOOL)isTranslationEnabled {
+  return _prefService->GetBoolean(prefs::kEnableTranslate);
+}
+
+- (void)resetTranslationSettings {
+  translate::TranslatePrefs translatePrefs(
+      _prefService, prefs::kAcceptLanguages,
+      /*preferred_languages_pref=*/nullptr);
+  translatePrefs.ResetToDefaults();
+}
+
+@end
diff --git a/ios/web_view/internal/cwv_preferences_internal.h b/ios/web_view/internal/cwv_preferences_internal.h
new file mode 100644
index 0000000..fa6681a
--- /dev/null
+++ b/ios/web_view/internal/cwv_preferences_internal.h
@@ -0,0 +1,21 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_INTERNAL_CWV_PREFERENCES_INTERNAL_H_
+#define IOS_WEB_VIEW_INTERNAL_CWV_PREFERENCES_INTERNAL_H_
+
+#import "ios/web_view/public/cwv_preferences.h"
+
+class PrefService;
+
+@interface CWVPreferences ()
+
+// Takes a PrefService object used to modify settings.
+// Caller must ensure |prefService| outlives this instance.
+- (instancetype)initWithPrefService:(PrefService*)prefService
+    NS_DESIGNATED_INITIALIZER;
+
+@end
+
+#endif  // IOS_WEB_VIEW_INTERNAL_CWV_PREFERENCES_INTERNAL_H_
diff --git a/ios/web_view/internal/cwv_web_view_configuration.mm b/ios/web_view/internal/cwv_web_view_configuration.mm
index 736dfbb..3669671 100644
--- a/ios/web_view/internal/cwv_web_view_configuration.mm
+++ b/ios/web_view/internal/cwv_web_view_configuration.mm
@@ -8,6 +8,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "ios/web_view/internal/app/application_context.h"
+#import "ios/web_view/internal/cwv_preferences_internal.h"
 #import "ios/web_view/internal/cwv_user_content_controller_internal.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 #include "ios/web_view/internal/web_view_global_state_util.h"
@@ -28,6 +29,7 @@
 
 @implementation CWVWebViewConfiguration
 
+@synthesize preferences = _preferences;
 @synthesize userContentController = _userContentController;
 
 + (instancetype)defaultConfiguration {
@@ -68,6 +70,9 @@
   if (self) {
     _browserState = std::move(browserState);
 
+    _preferences =
+        [[CWVPreferences alloc] initWithPrefService:_browserState->GetPrefs()];
+
     _userContentController =
         [[CWVUserContentController alloc] initWithConfiguration:self];
   }
diff --git a/ios/web_view/internal/translate/cwv_translation_controller.mm b/ios/web_view/internal/translate/cwv_translation_controller.mm
index 17ed9e9..a5c03fd 100644
--- a/ios/web_view/internal/translate/cwv_translation_controller.mm
+++ b/ios/web_view/internal/translate/cwv_translation_controller.mm
@@ -12,10 +12,8 @@
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/translate/core/browser/translate_manager.h"
 #import "ios/web_view/internal/cwv_web_view_configuration_internal.h"
-#include "ios/web_view/internal/pref_names.h"
 #import "ios/web_view/internal/translate/cwv_translation_language_internal.h"
 #import "ios/web_view/internal/translate/web_view_translate_client.h"
-#include "ios/web_view/internal/web_view_browser_state.h"
 #import "ios/web_view/public/cwv_translation_controller_delegate.h"
 #import "ios/web_view/public/cwv_translation_policy.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -68,17 +66,6 @@
 @synthesize supportedLanguagesByCode = _supportedLanguagesByCode;
 @synthesize webState = _webState;
 
-#pragma mark - Class Methods
-
-+ (void)resetTranslationPolicies {
-  CWVWebViewConfiguration* configuration =
-      [CWVWebViewConfiguration defaultConfiguration];
-  PrefService* prefService = configuration.browserState->GetPrefs();
-  translate::TranslatePrefs translatePrefs(prefService, prefs::kAcceptLanguages,
-                                           nullptr);
-  translatePrefs.ResetToDefaults();
-}
-
 #pragma mark - Internal Methods
 
 - (void)setWebState:(web::WebState*)webState {
@@ -169,7 +156,6 @@
 
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
              forPageLanguage:(CWVTranslationLanguage*)pageLanguage {
-  DCHECK(!_webState->GetBrowserState()->IsOffTheRecord());
   std::string languageCode = base::SysNSStringToUTF8(pageLanguage.languageCode);
   switch (policy.type) {
     case CWVTranslationPolicyAsk: {
@@ -213,7 +199,6 @@
 
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
                  forPageHost:(NSString*)pageHost {
-  DCHECK(!_webState->GetBrowserState()->IsOffTheRecord());
   DCHECK(pageHost.length);
   switch (policy.type) {
     case CWVTranslationPolicyAsk: {
diff --git a/ios/web_view/internal/web_view_web_main_delegate.mm b/ios/web_view/internal/web_view_web_main_delegate.mm
index 40b0be9..4e2454e 100644
--- a/ios/web_view/internal/web_view_web_main_delegate.mm
+++ b/ios/web_view/internal/web_view_web_main_delegate.mm
@@ -5,12 +5,18 @@
 #import "ios/web_view/internal/web_view_web_main_delegate.h"
 
 #import "base/mac/bundle_locations.h"
-#import "ios/web_view/public/cwv_html_element.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+// Dummy class used to locate the containing NSBundle.
+@interface CWVBundleLocator : NSObject
+@end
+
+@implementation CWVBundleLocator
+@end
+
 namespace ios_web_view {
 
 WebViewWebMainDelegate::WebViewWebMainDelegate() {}
@@ -18,11 +24,8 @@
 WebViewWebMainDelegate::~WebViewWebMainDelegate() = default;
 
 void WebViewWebMainDelegate::BasicStartupComplete() {
-  // Use CWVHTMLElement instead of CWVWebView and CWVWebViewConfiguration
-  // because the latter two classes' +intialize calls in to this method and may
-  // cause a deadlock.
   base::mac::SetOverrideFrameworkBundle(
-      [NSBundle bundleForClass:[CWVHTMLElement class]]);
+      [NSBundle bundleForClass:[CWVBundleLocator class]]);
 }
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/public/ChromeWebView.h b/ios/web_view/public/ChromeWebView.h
index 19de1a4..ca3e8d2 100644
--- a/ios/web_view/public/ChromeWebView.h
+++ b/ios/web_view/public/ChromeWebView.h
@@ -13,6 +13,7 @@
 #import "cwv_html_element.h"
 #import "cwv_navigation_action.h"
 #import "cwv_navigation_delegate.h"
+#import "cwv_preferences.h"
 #import "cwv_scroll_view.h"
 #import "cwv_scroll_view_delegate.h"
 #import "cwv_translation_controller.h"
diff --git a/ios/web_view/public/cwv_preferences.h b/ios/web_view/public/cwv_preferences.h
new file mode 100644
index 0000000..194df0d
--- /dev/null
+++ b/ios/web_view/public/cwv_preferences.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_VIEW_PUBLIC_CWV_PREFERENCES_H_
+#define IOS_WEB_VIEW_PUBLIC_CWV_PREFERENCES_H_
+
+#import <Foundation/Foundation.h>
+
+#import "cwv_export.h"
+
+// Preferences for user settings.
+CWV_EXPORT
+@interface CWVPreferences : NSObject
+
+// Whether or not translation as a feature is turned on.
+@property(nonatomic, assign, getter=isTranslationEnabled)
+    BOOL translationEnabled;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+// Resets all translation settings back to default. In particular, this will
+// change all translation policies back to CWVTranslationPolicyAsk.
+- (void)resetTranslationSettings;
+
+@end
+
+#endif  // IOS_WEB_VIEW_PUBLIC_CWV_PREFERENCES_H_
diff --git a/ios/web_view/public/cwv_translation_controller.h b/ios/web_view/public/cwv_translation_controller.h
index 6e9476d..ee31066 100644
--- a/ios/web_view/public/cwv_translation_controller.h
+++ b/ios/web_view/public/cwv_translation_controller.h
@@ -52,10 +52,6 @@
 @property(nonatomic, readonly)
     NSSet<CWVTranslationLanguage*>* supportedLanguages;
 
-// Resets all translation policies to default (CWVTranslationPolicyAsk).
-// Only resets non-incognito settings.
-+ (void)resetTranslationPolicies;
-
 // Begins translation on the current page from |sourceLanguage| to
 // |targetLanguage|. These language parameters must be chosen from
 // |supportedLanguages|. Set |userInitiated| to YES if translation
@@ -74,7 +70,6 @@
 
 // Sets or retrieves translation policies associated with a specified language.
 // |pageLanguage| should be the language code of the language.
-// Not supported in incognito mode.
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
              forPageLanguage:(CWVTranslationLanguage*)pageLanguage;
 - (CWVTranslationPolicy*)translationPolicyForPageLanguage:
@@ -82,7 +77,6 @@
 
 // Sets or retrieves translation policies associated with a specified page.
 // |pageHost| should be the hostname of the website. Must not be empty.
-// Not supported in incognito mode.
 - (void)setTranslationPolicy:(CWVTranslationPolicy*)policy
                  forPageHost:(NSString*)pageHost;
 - (CWVTranslationPolicy*)translationPolicyForPageHost:(NSString*)pageHost;
diff --git a/ios/web_view/public/cwv_web_view_configuration.h b/ios/web_view/public/cwv_web_view_configuration.h
index e1de098..881e051 100644
--- a/ios/web_view/public/cwv_web_view_configuration.h
+++ b/ios/web_view/public/cwv_web_view_configuration.h
@@ -9,6 +9,7 @@
 
 #import "cwv_export.h"
 
+@class CWVPreferences;
 @class CWVUserContentController;
 @class CWVWebsiteDataStore;
 
@@ -24,6 +25,9 @@
 
 - (instancetype)init NS_UNAVAILABLE;
 
+// The preferences object associated with this web view configuration.
+@property(nonatomic, readonly) CWVPreferences* preferences;
+
 // The user content controller to associate with web views created using this
 // configuration.
 @property(nonatomic, readonly) CWVUserContentController* userContentController;
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index 66483948..3837820 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/stl_util.h"
@@ -75,8 +76,9 @@
   cdm_->GetStatusForPolicy(min_hdcp_version, std::move(promise));
 }
 
-WebContentDecryptionModuleSessionImpl* CdmSessionAdapter::CreateSession() {
-  return new WebContentDecryptionModuleSessionImpl(this);
+std::unique_ptr<WebContentDecryptionModuleSessionImpl>
+CdmSessionAdapter::CreateSession() {
+  return base::MakeUnique<WebContentDecryptionModuleSessionImpl>(this);
 }
 
 bool CdmSessionAdapter::RegisterSession(
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index 4fdecc9b..1c7aefa 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -54,10 +54,9 @@
   void GetStatusForPolicy(HdcpVersion min_hdcp_version,
                           std::unique_ptr<KeyStatusCdmPromise> promise);
 
-  // Creates a new session and adds it to the internal map. The caller owns the
-  // created session. RemoveSession() must be called when destroying it, if
-  // RegisterSession() was called.
-  WebContentDecryptionModuleSessionImpl* CreateSession();
+  // Creates a new session and adds it to the internal map. RemoveSession()
+  // must be called when destroying it, if RegisterSession() was called.
+  std::unique_ptr<WebContentDecryptionModuleSessionImpl> CreateSession();
 
   // Adds a session to the internal map. Called once the session is successfully
   // initialized. Returns true if the session was registered, false if there is
diff --git a/media/blink/webcontentdecryptionmodule_impl.cc b/media/blink/webcontentdecryptionmodule_impl.cc
index 8a0aa48..d2c56c3a 100644
--- a/media/blink/webcontentdecryptionmodule_impl.cc
+++ b/media/blink/webcontentdecryptionmodule_impl.cc
@@ -120,8 +120,7 @@
 WebContentDecryptionModuleImpl::~WebContentDecryptionModuleImpl() {
 }
 
-// The caller owns the created session.
-blink::WebContentDecryptionModuleSession*
+std::unique_ptr<blink::WebContentDecryptionModuleSession>
 WebContentDecryptionModuleImpl::CreateSession() {
   return adapter_->CreateSession();
 }
diff --git a/media/blink/webcontentdecryptionmodule_impl.h b/media/blink/webcontentdecryptionmodule_impl.h
index 28c62ea9..ec436ba 100644
--- a/media/blink/webcontentdecryptionmodule_impl.h
+++ b/media/blink/webcontentdecryptionmodule_impl.h
@@ -41,7 +41,8 @@
   ~WebContentDecryptionModuleImpl() override;
 
   // blink::WebContentDecryptionModule implementation.
-  blink::WebContentDecryptionModuleSession* CreateSession() override;
+  std::unique_ptr<blink::WebContentDecryptionModuleSession> CreateSession()
+      override;
 
   void SetServerCertificate(
       const uint8_t* server_certificate,
diff --git a/media/gpu/vaapi_drm_picture.cc b/media/gpu/vaapi_drm_picture.cc
index b6e1f13..5fc1cc5 100644
--- a/media/gpu/vaapi_drm_picture.cc
+++ b/media/gpu/vaapi_drm_picture.cc
@@ -65,9 +65,6 @@
     return false;
   }
 
-  pixmap_->SetProcessingCallback(
-      base::Bind(&VaapiWrapper::ProcessPixmap, vaapi_wrapper_));
-
   if (texture_id_ != 0 && !make_context_current_cb_.is_null()) {
     if (!make_context_current_cb_.Run())
       return false;
diff --git a/media/gpu/vaapi_wrapper.cc b/media/gpu/vaapi_wrapper.cc
index 5146f43..0df3cbb 100644
--- a/media/gpu/vaapi_wrapper.cc
+++ b/media/gpu/vaapi_wrapper.cc
@@ -666,31 +666,6 @@
 
   return va_surface;
 }
-
-bool VaapiWrapper::ProcessPixmap(
-    const scoped_refptr<gfx::NativePixmap>& source_pixmap,
-    scoped_refptr<gfx::NativePixmap> target_pixmap) {
-  scoped_refptr<VASurface> va_surface = CreateVASurfaceForPixmap(source_pixmap);
-  if (!va_surface) {
-    LOG(ERROR) << "Failed creating VA Surface for source_pixmap";
-    return false;
-  }
-
-  scoped_refptr<VASurface> processed_va_surface =
-      CreateVASurfaceForPixmap(target_pixmap);
-  if (!processed_va_surface) {
-    LOG(ERROR) << "Failed creating processed VA Surface for pixmap";
-    return false;
-  }
-
-  if (!BlitSurface(va_surface, processed_va_surface)) {
-    LOG(ERROR) << "Failed scaling NativePixmap";
-    return false;
-  }
-
-  return true;
-}
-
 #endif
 
 void VaapiWrapper::DestroyUnownedSurface(VASurfaceID va_surface_id) {
diff --git a/media/gpu/vaapi_wrapper.h b/media/gpu/vaapi_wrapper.h
index e3f9006..948f4fb 100644
--- a/media/gpu/vaapi_wrapper.h
+++ b/media/gpu/vaapi_wrapper.h
@@ -119,12 +119,6 @@
   // CreateSurfaces(), where VaapiWrapper is the owner of the surfaces.
   scoped_refptr<VASurface> CreateVASurfaceForPixmap(
       const scoped_refptr<gfx::NativePixmap>& pixmap);
-
-  // Use VPP to process |source_pixmap| to |target_pixmap| with scaling and
-  // color space conversion.
-  bool ProcessPixmap(const scoped_refptr<gfx::NativePixmap>& source_pixmap,
-                     scoped_refptr<gfx::NativePixmap> target_pixmap);
-
 #endif
 
   // Submit parameters or slice data of |va_buffer_type|, copying them from
diff --git a/mojo/edk/system/ports/message_queue.h b/mojo/edk/system/ports/message_queue.h
index 724f0bb..3dc6226 100644
--- a/mojo/edk/system/ports/message_queue.h
+++ b/mojo/edk/system/ports/message_queue.h
@@ -18,8 +18,8 @@
 namespace edk {
 namespace ports {
 
-const uint64_t kInitialSequenceNum = 1;
-const uint64_t kInvalidSequenceNum = std::numeric_limits<uint64_t>::max();
+constexpr uint64_t kInitialSequenceNum = 1;
+constexpr uint64_t kInvalidSequenceNum = std::numeric_limits<uint64_t>::max();
 
 class MessageFilter;
 
diff --git a/net/http/http_cache.h b/net/http/http_cache.h
index c2221cc..12e072a 100644
--- a/net/http/http_cache.h
+++ b/net/http/http_cache.h
@@ -341,7 +341,9 @@
 
   // Dooms the entry selected by |key|. |trans| will be notified via its IO
   // callback if this method returns ERR_IO_PENDING. The entry can be
-  // currently in use or not.
+  // currently in use or not. If entry is in use and the invoking transaction
+  // is associated with this entry and this entry is already doomed, this API
+  // should not be invoked.
   int DoomEntry(const std::string& key, Transaction* trans);
 
   // Dooms the entry selected by |key|. |trans| will be notified via its IO
diff --git a/net/http/http_cache_transaction.cc b/net/http/http_cache_transaction.cc
index 10b6d91..68640aab 100644
--- a/net/http/http_cache_transaction.cc
+++ b/net/http/http_cache_transaction.cc
@@ -1609,7 +1609,8 @@
 
   // Invalidate any cached GET with a successful PUT or DELETE.
   if (mode_ == WRITE && (method_ == "PUT" || method_ == "DELETE")) {
-    if (NonErrorResponse(new_response->headers->response_code())) {
+    if (NonErrorResponse(new_response->headers->response_code()) &&
+        (entry_ && !entry_->doomed)) {
       int ret = cache_->DoomEntry(cache_key_, NULL);
       DCHECK_EQ(OK, ret);
     }
@@ -2902,8 +2903,10 @@
 
 void HttpCache::Transaction::DoomPartialEntry(bool delete_object) {
   DVLOG(2) << "DoomPartialEntry";
-  int rv = cache_->DoomEntry(cache_key_, NULL);
-  DCHECK_EQ(OK, rv);
+  if (entry_ && !entry_->doomed) {
+    int rv = cache_->DoomEntry(cache_key_, NULL);
+    DCHECK_EQ(OK, rv);
+  }
   cache_->DoneWithEntry(entry_, this, false /* process_cancel */,
                         partial_ != nullptr);
   entry_ = NULL;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 1c05602a..db03ce6 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -147,7 +147,7 @@
   EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
 }
 
-void DeferNetworkStart(bool* defer) {
+void DeferCallback(bool* defer) {
   *defer = true;
 }
 
@@ -1478,6 +1478,184 @@
   EXPECT_EQ(5, cache.disk_cache()->create_count());
 }
 
+// Tests that if a transaction is dooming the entry and the entry was doomed by
+// another transaction that was not part of the entry and created a new entry,
+// the new entry should not be incorrectly doomed. (crbug.com/736993)
+TEST(HttpCache, RangeGET_ParallelValidationNoMatchDoomEntry) {
+  MockHttpCache cache;
+
+  ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+  MockHttpRequest request(transaction);
+
+  MockTransaction dooming_transaction(kRangeGET_TransactionOK);
+  dooming_transaction.load_flags |= LOAD_BYPASS_CACHE;
+  MockHttpRequest dooming_request(dooming_transaction);
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 3;
+
+  scoped_refptr<MockDiskEntry> first_entry;
+  scoped_refptr<MockDiskEntry> second_entry;
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    MockHttpRequest* this_request = &request;
+
+    if (i == 2)
+      this_request = &dooming_request;
+
+    if (i == 1) {
+      ASSERT_TRUE(first_entry);
+      first_entry->SetDefer(MockDiskEntry::DEFER_READ);
+    }
+
+    c->result = c->trans->Start(this_request, c->callback.callback(),
+                                NetLogWithSource());
+
+    // Continue the transactions. 2nd will pause at the cache reading state and
+    // 3rd transaction will doom the entry.
+    base::RunLoop().RunUntilIdle();
+
+    // Check status of the first and second entries after every transaction.
+    switch (i) {
+      case 0:
+        first_entry =
+            cache.disk_cache()->GetDiskEntryRef(kRangeGET_TransactionOK.url);
+        break;
+      case 1:
+        EXPECT_FALSE(first_entry->is_doomed());
+        break;
+      case 2:
+        EXPECT_TRUE(first_entry->is_doomed());
+        second_entry =
+            cache.disk_cache()->GetDiskEntryRef(kRangeGET_TransactionOK.url);
+        EXPECT_FALSE(second_entry->is_doomed());
+        break;
+    }
+  }
+  // Resume cache read by 1st transaction which will lead to dooming the entry
+  // as well since the entry cannot be validated. This double dooming should not
+  // lead to an assertion.
+  first_entry->ResumeDiskEntryOperation();
+  base::RunLoop().RunUntilIdle();
+
+  // Since second_entry is already created, when 1st transaction goes on to
+  // create an entry, it will get ERR_CACHE_RACE leading to dooming of
+  // second_entry and creation of a third entry.
+  EXPECT_TRUE(second_entry->is_doomed());
+
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(3, cache.disk_cache()->create_count());
+
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  }
+
+  for (auto& c : context_list) {
+    ReadAndVerifyTransaction(c->trans.get(), kRangeGET_TransactionOK);
+  }
+
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(3, cache.disk_cache()->create_count());
+}
+
+// Same as above but tests that the 2nd transaction does not do anything if
+// there is nothing to doom. (crbug.com/736993)
+TEST(HttpCache, RangeGET_ParallelValidationNoMatchDoomEntry1) {
+  MockHttpCache cache;
+
+  ScopedMockTransaction transaction(kRangeGET_TransactionOK);
+  MockHttpRequest request(transaction);
+
+  MockTransaction dooming_transaction(kRangeGET_TransactionOK);
+  dooming_transaction.load_flags |= LOAD_BYPASS_CACHE;
+  MockHttpRequest dooming_request(dooming_transaction);
+
+  std::vector<std::unique_ptr<Context>> context_list;
+  const int kNumTransactions = 3;
+
+  scoped_refptr<MockDiskEntry> first_entry;
+  for (int i = 0; i < kNumTransactions; ++i) {
+    context_list.push_back(base::MakeUnique<Context>());
+    auto& c = context_list[i];
+
+    c->result = cache.CreateTransaction(&c->trans);
+    ASSERT_THAT(c->result, IsOk());
+    EXPECT_EQ(LOAD_STATE_IDLE, c->trans->GetLoadState());
+
+    MockHttpRequest* this_request = &request;
+
+    if (i == 2) {
+      this_request = &dooming_request;
+      cache.disk_cache()->SetDefer(MockDiskEntry::DEFER_CREATE);
+    }
+
+    if (i == 1) {
+      ASSERT_TRUE(first_entry);
+      first_entry->SetDefer(MockDiskEntry::DEFER_READ);
+    }
+
+    c->result = c->trans->Start(this_request, c->callback.callback(),
+                                NetLogWithSource());
+
+    // Continue the transactions. 2nd will pause at the cache reading state and
+    // 3rd transaction will doom the entry and pause before creating a new
+    // entry.
+    base::RunLoop().RunUntilIdle();
+
+    // Check status of the entry after every transaction.
+    switch (i) {
+      case 0:
+        first_entry =
+            cache.disk_cache()->GetDiskEntryRef(kRangeGET_TransactionOK.url);
+        break;
+      case 1:
+        EXPECT_FALSE(first_entry->is_doomed());
+        break;
+      case 2:
+        EXPECT_TRUE(first_entry->is_doomed());
+        break;
+    }
+  }
+  // Resume cache read by 2nd transaction which will lead to dooming the entry
+  // as well since the entry cannot be validated. This double dooming should not
+  // lead to an assertion.
+  first_entry->ResumeDiskEntryOperation();
+  base::RunLoop().RunUntilIdle();
+
+  // Resume creation of entry by 3rd transaction.
+  cache.disk_cache()->ResumeCacheOperation();
+  base::RunLoop().RunUntilIdle();
+
+  // Note that since 3rd transaction's entry is already created but its
+  // callback is deferred, MockDiskCache's implementation returns
+  // ERR_CACHE_CREATE_FAILURE when 2nd transaction tries to create an entry
+  // during that time, leading to it switching over to pass-through mode.
+  // Thus the number of entries is 2 below.
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+
+  for (auto& context : context_list) {
+    EXPECT_EQ(LOAD_STATE_IDLE, context->trans->GetLoadState());
+  }
+
+  for (auto& c : context_list) {
+    ReadAndVerifyTransaction(c->trans.get(), kRangeGET_TransactionOK);
+  }
+
+  EXPECT_EQ(3, cache.network_layer()->transaction_count());
+  EXPECT_EQ(0, cache.disk_cache()->open_count());
+  EXPECT_EQ(2, cache.disk_cache()->create_count());
+}
+
 // Tests parallel validation on range requests with non-overlapping ranges.
 TEST(HttpCache, RangeGET_ParallelValidationDifferentRanges) {
   MockHttpCache cache;
@@ -2159,7 +2337,7 @@
     MockHttpRequest* this_request = &request;
     if (i == 3) {
       this_request = &validate_request;
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferCallback));
     }
 
     c->result = c->trans->Start(this_request, c->callback.callback(),
@@ -2257,7 +2435,7 @@
     MockHttpRequest* this_request = &request;
     if (i == 2) {
       this_request = &validate_request;
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferCallback));
     }
 
     c->result = c->trans->Start(this_request, c->callback.callback(),
@@ -2395,7 +2573,7 @@
     MockHttpRequest* this_request = &request;
     if (i == 2) {
       this_request = &validate_request;
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferCallback));
     }
 
     c->result = c->trans->Start(this_request, c->callback.callback(),
@@ -2461,7 +2639,7 @@
     ASSERT_THAT(c->result, IsOk());
 
     if (i == 0)
-      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferNetworkStart));
+      c->trans->SetBeforeNetworkStartCallback(base::Bind(&DeferCallback));
 
     c->result =
         c->trans->Start(&request, c->callback.callback(), NetLogWithSource());
diff --git a/net/http/mock_http_cache.cc b/net/http/mock_http_cache.cc
index 514cc42..bf81c4ee 100644
--- a/net/http/mock_http_cache.cc
+++ b/net/http/mock_http_cache.cc
@@ -74,7 +74,9 @@
       fail_sparse_requests_(false),
       busy_(false),
       delayed_(false),
-      cancel_(false) {
+      cancel_(false),
+      defer_op_(DEFER_NONE),
+      resume_return_code_(0) {
   test_mode_ = GetTestModeForEntry(key);
 }
 
@@ -125,10 +127,25 @@
   if (MockHttpCache::GetTestMode(test_mode_) & TEST_MODE_SYNC_CACHE_READ)
     return num;
 
+  // Pause and resume.
+  if (defer_op_ == DEFER_READ) {
+    defer_op_ = DEFER_NONE;
+    resume_callback_ = callback;
+    resume_return_code_ = num;
+    return ERR_IO_PENDING;
+  }
+
   CallbackLater(callback, num);
   return ERR_IO_PENDING;
 }
 
+void MockDiskEntry::ResumeDiskEntryOperation() {
+  DCHECK(!resume_callback_.is_null());
+  CallbackLater(resume_callback_, resume_return_code_);
+  resume_callback_.Reset();
+  resume_return_code_ = 0;
+}
+
 int MockDiskEntry::WriteData(int index,
                              int offset,
                              IOBuffer* buf,
@@ -376,7 +393,9 @@
       fail_requests_(false),
       soft_failures_(false),
       double_create_check_(true),
-      fail_sparse_requests_(false) {}
+      fail_sparse_requests_(false),
+      defer_op_(MockDiskEntry::DEFER_NONE),
+      resume_return_code_(0) {}
 
 MockDiskCache::~MockDiskCache() {
   ReleaseAll();
@@ -460,6 +479,14 @@
   if (GetTestModeForEntry(key) & TEST_MODE_SYNC_CACHE_START)
     return OK;
 
+  // Pause and resume.
+  if (defer_op_ == MockDiskEntry::DEFER_CREATE) {
+    defer_op_ = MockDiskEntry::DEFER_NONE;
+    resume_callback_ = callback;
+    resume_return_code_ = OK;
+    return ERR_IO_PENDING;
+  }
+
   CallbackLater(callback, OK);
   return ERR_IO_PENDING;
 }
@@ -526,9 +553,8 @@
 }
 
 void MockDiskCache::ReleaseAll() {
-  EntryMap::iterator it = entries_.begin();
-  for (; it != entries_.end(); ++it)
-    it->second->Release();
+  for (auto entry : entries_)
+    entry.second->Release();
   entries_.clear();
 }
 
@@ -540,9 +566,25 @@
 
 bool MockDiskCache::IsDiskEntryDoomed(const std::string& key) {
   auto it = entries_.find(key);
+  if (it != entries_.end())
+    return it->second->is_doomed();
+
+  return false;
+}
+
+void MockDiskCache::ResumeCacheOperation() {
+  DCHECK(!resume_callback_.is_null());
+  CallbackLater(resume_callback_, resume_return_code_);
+  resume_callback_.Reset();
+  resume_return_code_ = 0;
+}
+
+scoped_refptr<MockDiskEntry> MockDiskCache::GetDiskEntryRef(
+    const std::string& key) {
+  auto it = entries_.find(key);
   if (it == entries_.end())
-    return false;
-  return it->second->is_doomed();
+    return nullptr;
+  return it->second;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/net/http/mock_http_cache.h b/net/http/mock_http_cache.h
index d568c64..bc7847b 100644
--- a/net/http/mock_http_cache.h
+++ b/net/http/mock_http_cache.h
@@ -27,6 +27,12 @@
 class MockDiskEntry : public disk_cache::Entry,
                       public base::RefCounted<MockDiskEntry> {
  public:
+  enum DeferOp {
+    DEFER_NONE,
+    DEFER_CREATE,
+    DEFER_READ,
+  };
+
   explicit MockDiskEntry(const std::string& key);
 
   bool is_doomed() const { return doomed_; }
@@ -74,6 +80,14 @@
   // again or all subsequent tests will fail.
   static void IgnoreCallbacks(bool value);
 
+  // Defers invoking the callback for the given operation. Calling code should
+  // invoke ResumeDiskEntryOperation to resume.
+  void SetDefer(DeferOp defer_op) { defer_op_ = defer_op; }
+
+  // Resumes deferred cache operation by posting |resume_callback_| with
+  // |resume_return_code_|.
+  void ResumeDiskEntryOperation();
+
  private:
   friend class base::RefCounted<MockDiskEntry>;
   struct CallbackInfo;
@@ -106,6 +120,12 @@
   bool busy_;
   bool delayed_;
   bool cancel_;
+
+  // Used for pause and restart.
+  DeferOp defer_op_;
+  CompletionCallback resume_callback_;
+  int resume_return_code_;
+
   static bool ignore_callbacks_;
 };
 
@@ -161,8 +181,20 @@
 
   void ReleaseAll();
 
+  // Returns true if a doomed entry exists with this key.
   bool IsDiskEntryDoomed(const std::string& key);
 
+  // Defers invoking the callback for the given operation. Calling code should
+  // invoke ResumeCacheOperation to resume.
+  void SetDefer(MockDiskEntry::DeferOp defer_op) { defer_op_ = defer_op; }
+
+  // Resume deferred cache operation by posting |resume_callback_| with
+  // |resume_return_code_|.
+  void ResumeCacheOperation();
+
+  // Returns a reference to the disk entry with the given |key|.
+  scoped_refptr<MockDiskEntry> GetDiskEntryRef(const std::string& key);
+
  private:
   using EntryMap = std::unordered_map<std::string, MockDiskEntry*>;
   class NotImplementedIterator;
@@ -177,6 +209,11 @@
   bool soft_failures_;
   bool double_create_check_;
   bool fail_sparse_requests_;
+
+  // Used for pause and restart.
+  MockDiskEntry::DeferOp defer_op_;
+  CompletionCallback resume_callback_;
+  int resume_return_code_;
 };
 
 class MockBackendFactory : public HttpCache::BackendFactory {
@@ -244,7 +281,6 @@
   static void SetTestMode(int test_mode);
 
   // Functions to test the state of ActiveEntry.
-
   bool IsWriterPresent(const std::string& key);
   bool IsHeadersTransactionPresent(const std::string& key);
   int GetCountReaders(const std::string& key);
diff --git a/pdf/pdf.cc b/pdf/pdf.cc
index 03f6d72..8d3a2d5 100644
--- a/pdf/pdf.cc
+++ b/pdf/pdf.cc
@@ -122,8 +122,8 @@
   PDFEngineExports::Get()->SetPDFUseGDIPrinting(enable);
 }
 
-void SetPDFPostscriptPrintingLevel(int postscript_level) {
-  PDFEngineExports::Get()->SetPDFPostscriptPrintingLevel(postscript_level);
+void SetPDFUsePrintMode(int mode) {
+  PDFEngineExports::Get()->SetPDFUsePrintMode(mode);
 }
 #endif  // defined(OS_WIN)
 
diff --git a/pdf/pdf.h b/pdf/pdf.h
index d18489d..6f69bdb3d 100644
--- a/pdf/pdf.h
+++ b/pdf/pdf.h
@@ -36,6 +36,14 @@
 const void* PPP_GetInterface(const char* interface_name);
 
 #if defined(OS_WIN)
+// Printing modes - type to convert PDF to for printing
+enum PrintingMode {
+  kEmf = 0,
+  kTextOnly = 1,
+  kPostScript2 = 2,
+  kPostScript3 = 3,
+};
+
 // |pdf_buffer| is the buffer that contains the entire PDF document to be
 //     rendered.
 // |buffer_size| is the size of |pdf_buffer| in bytes.
@@ -83,7 +91,7 @@
 
 void SetPDFUseGDIPrinting(bool enable);
 
-void SetPDFPostscriptPrintingLevel(int postscript_level);
+void SetPDFUsePrintMode(int mode);
 #endif  // defined(OS_WIN)
 
 // |page_count| and |max_page_width| are optional and can be NULL.
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index ac18b5e..1556e51 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -347,8 +347,7 @@
       PDFEnsureTypefaceCharactersAccessible func) = 0;
 
   virtual void SetPDFUseGDIPrinting(bool enable) = 0;
-
-  virtual void SetPDFPostscriptPrintingLevel(int postscript_level) = 0;
+  virtual void SetPDFUsePrintMode(int mode) = 0;
 #endif  // defined(OS_WIN)
 
   // See the definition of RenderPDFPageToBitmap in pdf.cc for details.
diff --git a/pdf/pdfium/pdfium_assert_matching_enums.cc b/pdf/pdfium/pdfium_assert_matching_enums.cc
index b173a32..e89225af 100644
--- a/pdf/pdfium/pdfium_assert_matching_enums.cc
+++ b/pdf/pdfium/pdfium_assert_matching_enums.cc
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "build/build_config.h"
+#include "pdf/pdf.h"
 #include "ppapi/c/pp_input_event.h"
 #include "ppapi/c/private/ppb_pdf.h"
 #include "ppapi/c/private/ppp_pdf.h"
+#include "third_party/pdfium/public/fpdf_edit.h"
 #include "third_party/pdfium/public/fpdf_fwlevent.h"
 #include "third_party/pdfium/public/fpdf_sysfontinfo.h"
 #include "ui/events/keycodes/keyboard_codes.h"
@@ -210,3 +213,10 @@
 STATIC_ASSERT_ENUM(PP_PRIVATEDUPLEXMODE_SIMPLEX, Simplex);
 STATIC_ASSERT_ENUM(PP_PRIVATEDUPLEXMODE_SHORT_EDGE, DuplexFlipShortEdge);
 STATIC_ASSERT_ENUM(PP_PRIVATEDUPLEXMODE_LONG_EDGE, DuplexFlipLongEdge);
+
+#if defined(OS_WIN)
+STATIC_ASSERT_ENUM(chrome_pdf::kEmf, FPDF_PRINTMODE_EMF);
+STATIC_ASSERT_ENUM(chrome_pdf::kTextOnly, FPDF_PRINTMODE_TEXTONLY);
+STATIC_ASSERT_ENUM(chrome_pdf::kPostScript2, FPDF_PRINTMODE_POSTSCRIPT2);
+STATIC_ASSERT_ENUM(chrome_pdf::kPostScript3, FPDF_PRINTMODE_POSTSCRIPT3);
+#endif
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 37fef306..22cff050 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4154,10 +4154,9 @@
   FPDF_SetPrintTextWithGDI(enable);
 }
 
-void PDFiumEngineExports::SetPDFPostscriptPrintingLevel(int postscript_level) {
-  FPDF_SetPrintPostscriptLevel(postscript_level);
+void PDFiumEngineExports::SetPDFUsePrintMode(int mode) {
+  FPDF_SetPrintMode(mode);
 }
-
 #endif  // defined(OS_WIN)
 
 bool PDFiumEngineExports::RenderPDFPageToBitmap(
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index e19570d..3953c745 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -808,8 +808,7 @@
       PDFEnsureTypefaceCharactersAccessible func) override;
 
   void SetPDFUseGDIPrinting(bool enable) override;
-
-  void SetPDFPostscriptPrintingLevel(int postscript_level) override;
+  void SetPDFUsePrintMode(int mode) override;
 #endif  // defined(OS_WIN)
   bool RenderPDFPageToBitmap(const void* pdf_buffer,
                              int pdf_buffer_size,
diff --git a/printing/pdf_render_settings.h b/printing/pdf_render_settings.h
index 059f73d..1bb205d 100644
--- a/printing/pdf_render_settings.h
+++ b/printing/pdf_render_settings.h
@@ -16,6 +16,7 @@
   enum Mode {
     NORMAL = 0,
 #if defined(OS_WIN)
+    TEXTONLY,
     GDI_TEXT,
     POSTSCRIPT_LEVEL2,
     POSTSCRIPT_LEVEL3,
diff --git a/printing/print_settings.h b/printing/print_settings.h
index 2158737..f55efc4 100644
--- a/printing/print_settings.h
+++ b/printing/print_settings.h
@@ -37,6 +37,7 @@
 #if defined(OS_WIN)
   enum PrinterType {
     TYPE_NONE = 0,
+    TYPE_TEXTONLY,
     TYPE_XPS,
     TYPE_POSTSCRIPT_LEVEL2,
     TYPE_POSTSCRIPT_LEVEL3
@@ -171,6 +172,9 @@
   bool print_text_with_gdi() const { return print_text_with_gdi_; }
 
   void set_printer_type(PrinterType type) { printer_type_ = type; }
+  bool printer_is_textonly() const {
+    return printer_type_ == PrinterType::TYPE_TEXTONLY;
+  }
   bool printer_is_xps() const { return printer_type_ == PrinterType::TYPE_XPS;}
   bool printer_is_ps2() const {
     return printer_type_ == PrinterType::TYPE_POSTSCRIPT_LEVEL2;
diff --git a/printing/print_settings_initializer_win.cc b/printing/print_settings_initializer_win.cc
index e611e84..fd243fe 100644
--- a/printing/print_settings_initializer_win.cc
+++ b/printing/print_settings_initializer_win.cc
@@ -92,6 +92,9 @@
   return IsTechnology(hdc, kXPSDriver);
 }
 
+bool IsPrinterTextOnly(HDC hdc) {
+  return ::GetDeviceCaps(hdc, TECHNOLOGY) == DT_CHARSTREAM;
+}
 }  // namespace
 
 // static
@@ -153,6 +156,11 @@
         PrintSettings::PrinterType::TYPE_POSTSCRIPT_LEVEL3);
     return;
   }
+  // Detects the generic / text only driver.
+  if (IsPrinterTextOnly(hdc)) {
+    print_settings->set_printer_type(PrintSettings::PrinterType::TYPE_TEXTONLY);
+    return;
+  }
   if (IsPrinterXPS(hdc)) {
     print_settings->set_printer_type(PrintSettings::PrinterType::TYPE_XPS);
     return;
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm
index a9cdc9f1..3892b2c 100644
--- a/remoting/ios/app/client_connection_view_controller.mm
+++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -58,6 +58,7 @@
   RemotingClient* _client;
   SessionErrorCode _lastError;
   HostInfo* _hostInfo;
+  BOOL _hasViewAppeared;
 }
 
 @property(nonatomic, assign) SessionErrorCode lastError;
@@ -74,6 +75,7 @@
   if (self) {
     _hostInfo = hostInfo;
     _remoteHostName = hostInfo.hostName;
+    _hasViewAppeared = NO;
 
     // TODO(yuweih): This logic may be reused by other views.
     UIButton* cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
@@ -107,8 +109,6 @@
           constraintEqualToAnchor:[self.view trailingAnchor]],
       [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight],
     ]];
-
-    [self attemptConnectionToHost];
   }
   return self;
 }
@@ -174,6 +174,22 @@
          selector:@selector(hostSessionStatusChanged:)
              name:kHostSessionStatusChanged
            object:nil];
+
+  [self attemptConnectionToHost];
+
+  // Although keyboard listeners are registered here, they won't work properly
+  // if the keyboard shows/hides before the view appears.
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(keyboardWillShow:)
+             name:UIKeyboardWillShowNotification
+           object:nil];
+
+  [[NSNotificationCenter defaultCenter]
+      addObserver:self
+         selector:@selector(keyboardWillHide:)
+             name:UIKeyboardWillHideNotification
+           object:nil];
 }
 
 - (void)initializeLayoutConstraintsWithViews:(NSDictionary*)views {
@@ -280,19 +296,11 @@
 
 - (void)viewDidAppear:(BOOL)animated {
   [super viewDidAppear:animated];
-  [[NSNotificationCenter defaultCenter]
-      addObserver:self
-         selector:@selector(keyboardWillShow:)
-             name:UIKeyboardWillShowNotification
-           object:nil];
-
-  [[NSNotificationCenter defaultCenter]
-      addObserver:self
-         selector:@selector(keyboardWillHide:)
-             name:UIKeyboardWillHideNotification
-           object:nil];
-
   [_activityIndicator startAnimating];
+
+  _hasViewAppeared = YES;
+
+  self.state = _state;
 }
 
 - (void)viewWillDisappear:(BOOL)animated {
@@ -306,9 +314,6 @@
 
 #pragma mark - Keyboard
 
-// TODO(nicholss): We need to listen to screen rotation and re-adjust the
-// topAnchor.
-
 - (void)keyboardWillShow:(NSNotification*)notification {
   CGSize keyboardSize =
       [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey]
@@ -324,7 +329,7 @@
   _activityIndicatorTopConstraintKeyboard.active = NO;
   _activityIndicatorTopConstraintKeyboard = [_activityIndicator.topAnchor
       constraintEqualToAnchor:self.view.topAnchor
-                     constant:kTopPadding + overlap];
+                     constant:_activityIndicator.frame.origin.y + overlap];
   _activityIndicatorTopConstraintFull.active = NO;
   _activityIndicatorTopConstraintKeyboard.active = YES;
   [UIView animateWithDuration:kKeyboardAnimationTime
@@ -346,6 +351,11 @@
 
 - (void)setState:(ClientConnectionViewState)state {
   _state = state;
+  if (!_hasViewAppeared) {
+    // Showing different state will re-layout the view, which will be broken if
+    // the view is not shown yet.
+    return;
+  }
   switch (_state) {
     case ClientViewConnecting:
       [self showConnectingState];
diff --git a/services/device/public/cpp/generic_sensor/BUILD.gn b/services/device/public/cpp/generic_sensor/BUILD.gn
index 351ea5c..bee8552 100644
--- a/services/device/public/cpp/generic_sensor/BUILD.gn
+++ b/services/device/public/cpp/generic_sensor/BUILD.gn
@@ -8,6 +8,8 @@
     "platform_sensor_configuration.h",
     "sensor_reading.cc",
     "sensor_reading.h",
+    "sensor_reading_shared_buffer_reader.cc",
+    "sensor_reading_shared_buffer_reader.h",
   ]
 
   public_deps = [
diff --git a/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.cc b/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.cc
new file mode 100644
index 0000000..836234c
--- /dev/null
+++ b/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.cc
@@ -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.
+
+#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
+
+#include "device/base/synchronization/shared_memory_seqlock_buffer.h"
+
+namespace {
+
+constexpr int kMaxReadAttemptsCount = 10;
+
+}  // namespace
+
+namespace device {
+
+SensorReadingSharedBufferReader::SensorReadingSharedBufferReader(
+    const SensorReadingSharedBuffer* buffer)
+    : buffer_(buffer) {}
+
+SensorReadingSharedBufferReader::~SensorReadingSharedBufferReader() = default;
+
+bool SensorReadingSharedBufferReader::GetReading(SensorReading* result) {
+  int read_attempts = 0;
+  while (!TryReadFromBuffer(result)) {
+    // Only try to read this many times before failing to avoid waiting here
+    // very long in case of contention with the writer.
+    if (++read_attempts == kMaxReadAttemptsCount) {
+      // Failed to successfully read, presumably because the hardware
+      // thread was taking unusually long. Data in |result| was not updated
+      // and was simply left what was there before.
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SensorReadingSharedBufferReader::TryReadFromBuffer(SensorReading* result) {
+  auto version = buffer_->seqlock.value().ReadBegin();
+  temp_reading_data_ = buffer_->reading;
+  if (buffer_->seqlock.value().ReadRetry(version))
+    return false;
+  *result = temp_reading_data_;
+  return true;
+}
+
+}  // namespace device
diff --git a/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h b/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h
new file mode 100644
index 0000000..354f8a3
--- /dev/null
+++ b/services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h
@@ -0,0 +1,36 @@
+// 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 SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_READING_SHARED_BUFFER_READER_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_READING_SHARED_BUFFER_READER_H_
+
+#include "base/macros.h"
+#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
+
+namespace device {
+
+class SensorReadingSharedBufferReader {
+ public:
+  // TODO(juncai): Maybe pass a mojo::ScopedSharedBufferHandle to the
+  // constructor.
+  // https://crbug.com/742408
+  explicit SensorReadingSharedBufferReader(
+      const SensorReadingSharedBuffer* buffer);
+  ~SensorReadingSharedBufferReader();
+
+  // Get sensor reading from shared buffer.
+  bool GetReading(SensorReading* result);
+
+ private:
+  bool TryReadFromBuffer(SensorReading* result);
+
+  const SensorReadingSharedBuffer* buffer_;
+  SensorReading temp_reading_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(SensorReadingSharedBufferReader);
+};
+
+}  // namespace device
+
+#endif  // SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_READING_SHARED_BUFFER_READER_H_
diff --git a/services/device/public/interfaces/BUILD.gn b/services/device/public/interfaces/BUILD.gn
index bd47483..db32b96 100644
--- a/services/device/public/interfaces/BUILD.gn
+++ b/services/device/public/interfaces/BUILD.gn
@@ -36,9 +36,6 @@
   public_deps = [
     ":constants",
   ]
-
-  # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
 }
 
 mojom("constants") {
@@ -47,5 +44,5 @@
   ]
 
   # TODO(crbug.com/699569): Convert to use the new JS bindings.
-  use_new_js_bindings = false
+  js_bindings_mode = "both"
 }
diff --git a/services/resource_coordinator/BUILD.gn b/services/resource_coordinator/BUILD.gn
index 179b6d5..4a59a5b 100644
--- a/services/resource_coordinator/BUILD.gn
+++ b/services/resource_coordinator/BUILD.gn
@@ -26,8 +26,8 @@
     "coordination_unit/frame_coordination_unit_impl.h",
     "coordination_unit/process_coordination_unit_impl.cc",
     "coordination_unit/process_coordination_unit_impl.h",
-    "coordination_unit/tab_signal_generator.cc",
-    "coordination_unit/tab_signal_generator.h",
+    "coordination_unit/tab_signal_generator_impl.cc",
+    "coordination_unit/tab_signal_generator_impl.h",
     "coordination_unit/web_contents_coordination_unit_impl.cc",
     "coordination_unit/web_contents_coordination_unit_impl.h",
     "memory_instrumentation/coordinator_impl.cc",
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
index f5f79a7..b6f7587 100644
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h"
+#include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
 #include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
 
 namespace resource_coordinator {
@@ -29,6 +30,13 @@
 
 }  // namespace
 
+// static
+const FrameCoordinationUnitImpl* CoordinationUnitImpl::ToFrameCoordinationUnit(
+    const CoordinationUnitImpl* coordination_unit) {
+  DCHECK(coordination_unit->id().type == CoordinationUnitType::kFrame);
+  return static_cast<const FrameCoordinationUnitImpl*>(coordination_unit);
+}
+
 CoordinationUnitImpl::CoordinationUnitImpl(
     const CoordinationUnitID& id,
     std::unique_ptr<service_manager::ServiceContextRef> service_ref)
@@ -99,6 +107,7 @@
 }
 
 void CoordinationUnitImpl::SendEvent(mojom::EventPtr event) {
+  // TODO(crbug.com/691886) Consider removing the following code.
   switch (event->type) {
     case mojom::EventType::kOnWebContentsShown:
       state_flags_[kTabVisible] = true;
@@ -112,9 +121,6 @@
     case mojom::EventType::kOnProcessAudioStopped:
       state_flags_[kAudioPlaying] = false;
       break;
-    case mojom::EventType::kOnLocalFrameNetworkIdle:
-      state_flags_[kNetworkIdle] = true;
-      break;
     case mojom::EventType::kTestEvent:
       state_flags_[kTestState] = true;
       break;
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
index 4dd1894d..c740f930 100644
--- a/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_impl.h
@@ -23,6 +23,7 @@
 namespace resource_coordinator {
 
 class CoordinationUnitGraphObserver;
+class FrameCoordinationUnitImpl;
 
 class CoordinationUnitImpl : public mojom::CoordinationUnit {
  public:
@@ -31,6 +32,9 @@
       std::unique_ptr<service_manager::ServiceContextRef> service_ref);
   ~CoordinationUnitImpl() override;
 
+  static const FrameCoordinationUnitImpl* ToFrameCoordinationUnit(
+      const CoordinationUnitImpl* coordination_unit);
+
   // Overridden from mojom::CoordinationUnit:
   void SendEvent(mojom::EventPtr event) override;
   void GetID(const GetIDCallback& callback) override;
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
index a788ba8..110f506bf 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
@@ -37,4 +37,12 @@
   }
 }
 
+bool FrameCoordinationUnitImpl::IsMainFrame() const {
+  for (auto* parent : parents_) {
+    if (parent->id().type == CoordinationUnitType::kFrame)
+      return false;
+  }
+  return true;
+}
+
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
index 39d3fae..c66501c 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h
@@ -12,8 +12,6 @@
 
 namespace resource_coordinator {
 
-struct CoordinationUnitID;
-
 class FrameCoordinationUnitImpl : public CoordinationUnitImpl {
  public:
   FrameCoordinationUnitImpl(
@@ -25,6 +23,8 @@
   std::set<CoordinationUnitImpl*> GetAssociatedCoordinationUnitsOfType(
       CoordinationUnitType type) override;
 
+  bool IsMainFrame() const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(FrameCoordinationUnitImpl);
 };
diff --git a/services/resource_coordinator/coordination_unit/tab_signal_generator.cc b/services/resource_coordinator/coordination_unit/tab_signal_generator.cc
deleted file mode 100644
index 7cc179e6..0000000
--- a/services/resource_coordinator/coordination_unit/tab_signal_generator.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/resource_coordinator/coordination_unit/tab_signal_generator.h"
-
-#include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h"
-
-namespace resource_coordinator {
-
-TabSignalGenerator::TabSignalGenerator() = default;
-
-TabSignalGenerator::~TabSignalGenerator() = default;
-
-bool TabSignalGenerator::ShouldObserve(
-    const CoordinationUnitImpl* coordination_unit) {
-  return coordination_unit->id().type == CoordinationUnitType::kWebContents;
-}
-
-}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/tab_signal_generator.h b/services/resource_coordinator/coordination_unit/tab_signal_generator.h
deleted file mode 100644
index 5c5980d7..0000000
--- a/services/resource_coordinator/coordination_unit/tab_signal_generator.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_H_
-#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_H_
-
-#include "base/macros.h"
-#include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h"
-
-namespace resource_coordinator {
-
-class CoordinationUnitImpl;
-
-// The TabSignalGenerator is a unified |CoordinationUnitGraphObserver| for
-// calculating and emitting tab-scoped signals. Nonetheless, the observer
-// has access to the whole coordination unit graph and thus can utilize
-// the information contained within the entire graph to generate the signals.
-class TabSignalGenerator : public CoordinationUnitGraphObserver {
- public:
-  TabSignalGenerator();
-  ~TabSignalGenerator() override;
-
-  bool ShouldObserve(const CoordinationUnitImpl* coordination_unit) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TabSignalGenerator);
-};
-
-}  // namespace resource_coordinator
-
-#endif  // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_H_
diff --git a/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.cc b/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.cc
new file mode 100644
index 0000000..a7d8eddf
--- /dev/null
+++ b/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.cc
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/resource_coordinator/coordination_unit/tab_signal_generator_impl.h"
+
+#include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h"
+#include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
+#include "services/resource_coordinator/coordination_unit/web_contents_coordination_unit_impl.h"
+
+namespace resource_coordinator {
+
+#define DISPATCH_TAB_SIGNAL(observers, METHOD, cu, ...)           \
+  observers.ForAllPtrs([cu](mojom::TabSignalObserver* observer) { \
+    observer->METHOD(cu->id(), __VA_ARGS__);                      \
+  });
+
+TabSignalGeneratorImpl::TabSignalGeneratorImpl() = default;
+
+TabSignalGeneratorImpl::~TabSignalGeneratorImpl() = default;
+
+void TabSignalGeneratorImpl::AddObserver(mojom::TabSignalObserverPtr observer) {
+  observers_.AddPtr(std::move(observer));
+}
+
+bool TabSignalGeneratorImpl::ShouldObserve(
+    const CoordinationUnitImpl* coordination_unit) {
+  auto coordination_unit_type = coordination_unit->id().type;
+  return coordination_unit_type == CoordinationUnitType::kWebContents ||
+         coordination_unit_type == CoordinationUnitType::kFrame;
+}
+
+void TabSignalGeneratorImpl::OnPropertyChanged(
+    const CoordinationUnitImpl* coordination_unit,
+    const mojom::PropertyType property_type,
+    const base::Value& value) {
+  if (coordination_unit->id().type == CoordinationUnitType::kFrame) {
+    OnFramePropertyChanged(
+        CoordinationUnitImpl::ToFrameCoordinationUnit(coordination_unit),
+        property_type, value);
+  }
+}
+
+void TabSignalGeneratorImpl::BindToInterface(
+    const service_manager::BindSourceInfo& source_info,
+    resource_coordinator::mojom::TabSignalGeneratorRequest request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
+void TabSignalGeneratorImpl::OnFramePropertyChanged(
+    const FrameCoordinationUnitImpl* coordination_unit,
+    const mojom::PropertyType property_type,
+    const base::Value& value) {
+  if (property_type == mojom::PropertyType::kNetworkIdle) {
+    // Ignore when the signal doesn't come from main frame.
+    if (!coordination_unit->IsMainFrame())
+      return;
+    // TODO(lpy) Combine CPU usage or long task idleness signal.
+    for (auto* parent : coordination_unit->parents()) {
+      if (parent->id().type != CoordinationUnitType::kWebContents)
+        continue;
+      DISPATCH_TAB_SIGNAL(observers_, OnEventReceived, parent,
+                          mojom::TabEvent::kDoneLoading);
+      break;
+    }
+  }
+}
+
+}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.h b/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.h
new file mode 100644
index 0000000..495e25d
--- /dev/null
+++ b/services/resource_coordinator/coordination_unit/tab_signal_generator_impl.h
@@ -0,0 +1,56 @@
+// 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 SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_IMPL_H_
+#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_IMPL_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_ptr_set.h"
+#include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h"
+#include "services/resource_coordinator/public/interfaces/tab_signal.mojom.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
+
+namespace resource_coordinator {
+
+class CoordinationUnitImpl;
+class FrameCoordinationUnitImpl;
+
+// The TabSignalGenerator is a dedicated |CoordinationUnitGraphObserver| for
+// calculating and emitting tab-scoped signals. This observer observes Tab
+// CoordinationUnits and Frame CoordinationUnits, utilize information from the
+// graph and generate tab level signals.
+class TabSignalGeneratorImpl : public CoordinationUnitGraphObserver,
+                               public mojom::TabSignalGenerator {
+ public:
+  TabSignalGeneratorImpl();
+  ~TabSignalGeneratorImpl() override;
+
+  // mojom::SignalGenerator implementation.
+  void AddObserver(mojom::TabSignalObserverPtr observer) override;
+
+  // CoordinationUnitGraphObserver implementation.
+  bool ShouldObserve(const CoordinationUnitImpl* coordination_unit) override;
+  void OnPropertyChanged(const CoordinationUnitImpl* coordination_unit,
+                         const mojom::PropertyType property_type,
+                         const base::Value& value) override;
+
+  void BindToInterface(
+      const service_manager::BindSourceInfo& source_info,
+      resource_coordinator::mojom::TabSignalGeneratorRequest request);
+
+ private:
+  void OnFramePropertyChanged(
+      const FrameCoordinationUnitImpl* coordination_unit,
+      const mojom::PropertyType property_type,
+      const base::Value& value);
+
+  mojo::BindingSet<mojom::TabSignalGenerator> bindings_;
+  mojo::InterfacePtrSet<mojom::TabSignalObserver> observers_;
+  DISALLOW_COPY_AND_ASSIGN(TabSignalGeneratorImpl);
+};
+
+}  // namespace resource_coordinator
+
+#endif  // SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_TAB_SIGNAL_GENERATOR_IMPL_H_
diff --git a/services/resource_coordinator/manifest.json b/services/resource_coordinator/manifest.json
index 78624785..57f8e979 100644
--- a/services/resource_coordinator/manifest.json
+++ b/services/resource_coordinator/manifest.json
@@ -6,6 +6,7 @@
       "provides": {
         "coordination_unit": [ "resource_coordinator::mojom::CoordinationUnitProvider" ],
         "service_callbacks": [ "resource_coordinator::mojom::ServiceCallbacks" ],
+        "tab_signal": [ "resource_coordinator::mojom::TabSignalGenerator" ],
         "tests": [ "*" ]
       },
       "requires": {
diff --git a/services/resource_coordinator/public/cpp/coordination_unit_id.h b/services/resource_coordinator/public/cpp/coordination_unit_id.h
index a145799..44d815b 100644
--- a/services/resource_coordinator/public/cpp/coordination_unit_id.h
+++ b/services/resource_coordinator/public/cpp/coordination_unit_id.h
@@ -5,6 +5,7 @@
 #define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_ID_H_
 
 #include <string>
+#include <tuple>
 
 #include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
 #include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
@@ -29,6 +30,10 @@
     return id == b.id && type == b.type;
   }
 
+  bool operator<(const CoordinationUnitID& b) const {
+    return std::tie(id, type) < std::tie(b.id, b.type);
+  }
+
   CoordinationUnitTypeId id;
   CoordinationUnitType type;
 };
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
index 0763762..1f514e0 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.cc
@@ -11,3 +11,11 @@
     "GlobalResourceCoordinator", base::FEATURE_DISABLED_BY_DEFAULT};
 
 }  // namespace features
+
+namespace resource_coordinator {
+
+bool IsResourceCoordinatorEnabled() {
+  return base::FeatureList::IsEnabled(features::kGlobalResourceCoordinator);
+}
+
+}  // namespace resource_coordinator
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_features.h b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
index 83fe5ba6..2444a78 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_features.h
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_features.h
@@ -20,4 +20,11 @@
 
 }  // namespace features
 
+namespace resource_coordinator {
+
+bool SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT
+IsResourceCoordinatorEnabled();
+
+}  // namespace resource_coordinator
+
 #endif  // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_RESOURCE_COORDINATOR_FEATURES_H_
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc b/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc
index 21b2928..b01d8ad 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_interface.cc
@@ -51,6 +51,7 @@
     const CoordinationUnitID& cu_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(connector);
+  cu_id_ = cu_id;
   mojom::CoordinationUnitProviderPtr provider;
   connector->BindInterface(mojom::kServiceName, mojo::MakeRequest(&provider));
 
diff --git a/services/resource_coordinator/public/cpp/resource_coordinator_interface.h b/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
index b1475105..8dd4028 100644
--- a/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
+++ b/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
@@ -43,6 +43,7 @@
                    std::unique_ptr<base::Value> value);
   void AddChild(const ResourceCoordinatorInterface& child);
   void RemoveChild(const ResourceCoordinatorInterface& child);
+  CoordinationUnitID id() const { return cu_id_; }
 
  private:
   void ConnectToService(service_manager::Connector* connector,
@@ -51,6 +52,7 @@
   void RemoveChildByID(const CoordinationUnitID& child_id);
 
   mojom::CoordinationUnitPtr service_;
+  CoordinationUnitID cu_id_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/services/resource_coordinator/public/interfaces/BUILD.gn b/services/resource_coordinator/public/interfaces/BUILD.gn
index 33587e1..9772afc 100644
--- a/services/resource_coordinator/public/interfaces/BUILD.gn
+++ b/services/resource_coordinator/public/interfaces/BUILD.gn
@@ -15,6 +15,7 @@
     "memory_instrumentation/memory_instrumentation.mojom",
     "service_callbacks.mojom",
     "service_constants.mojom",
+    "tab_signal.mojom",
     "tracing/tracing.mojom",
     "tracing/tracing_constants.mojom",
   ]
diff --git a/services/resource_coordinator/public/interfaces/coordination_unit.mojom b/services/resource_coordinator/public/interfaces/coordination_unit.mojom
index 2b8ae10..be02883 100644
--- a/services/resource_coordinator/public/interfaces/coordination_unit.mojom
+++ b/services/resource_coordinator/public/interfaces/coordination_unit.mojom
@@ -35,6 +35,7 @@
 enum PropertyType {
   kTest,
   kCPUUsage,
+  kNetworkIdle,
   kVisible,
 };
 
diff --git a/services/resource_coordinator/public/interfaces/events.mojom b/services/resource_coordinator/public/interfaces/events.mojom
index ee46713..57c942e3 100644
--- a/services/resource_coordinator/public/interfaces/events.mojom
+++ b/services/resource_coordinator/public/interfaces/events.mojom
@@ -7,12 +7,14 @@
 enum EventType {
   kTestEvent,
   kOnNavigationCommit,
+
+  // WebContents event types.
   kOnWebContentsShown,
   kOnWebContentsHidden,
-  kOnRendererFrameCreated,
+
+  // Process event types.
   kOnProcessAudioStarted,
   kOnProcessAudioStopped,
-  kOnLocalFrameNetworkIdle,
 };
 
 struct Event {
diff --git a/services/resource_coordinator/public/interfaces/tab_signal.mojom b/services/resource_coordinator/public/interfaces/tab_signal.mojom
new file mode 100644
index 0000000..7976f8b
--- /dev/null
+++ b/services/resource_coordinator/public/interfaces/tab_signal.mojom
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module resource_coordinator.mojom;
+
+import "coordination_unit.mojom";
+import "mojo/common/values.mojom";
+
+// Event signal scoped to a tab.
+enum TabEvent {
+  kDoneLoading,
+};
+
+// A TabSignalObserver implementation receives tab-scoped signal from
+// TabSignalGenerator.
+// Any interested party that needs to observe tab-scoped signal from GRC must
+// implement this interface, construct mojo channel to the implementation, and
+// pass the interface pointer of mojo channel to TabSignalGenerator through
+// TabSignalGenerator::AddObserver.
+interface TabSignalObserver {
+  OnEventReceived(CoordinationUnitID cu_id, TabEvent event);
+};
+
+// A TabSignalGenerator implementation will be implemented inside GRC to observe
+// signals from Coordination Units, generate tab-scoped signals, sends signals
+// to TabSignalObserver implementations.
+// There will be only one TabSignalGenerator implementation.
+interface TabSignalGenerator {
+  AddObserver(TabSignalObserver observer);
+};
\ No newline at end of file
diff --git a/services/resource_coordinator/resource_coordinator_service.cc b/services/resource_coordinator/resource_coordinator_service.cc
index 1de5dfb..b733a052 100644
--- a/services/resource_coordinator/resource_coordinator_service.cc
+++ b/services/resource_coordinator/resource_coordinator_service.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
-#include "services/resource_coordinator/coordination_unit/tab_signal_generator.h"
+#include "services/resource_coordinator/coordination_unit/tab_signal_generator_impl.h"
 #include "services/resource_coordinator/service_callbacks_impl.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
@@ -17,12 +17,7 @@
   auto resource_coordinator_service =
       base::MakeUnique<ResourceCoordinatorService>();
 
-  // Register new |CoordinationUnitGraphObserver| implementations here.
-  resource_coordinator_service->coordination_unit_manager()->RegisterObserver(
-      base::MakeUnique<TabSignalGenerator>());
-
-  return std::unique_ptr<service_manager::Service>(
-      resource_coordinator_service.release());
+  return resource_coordinator_service;
 }
 
 ResourceCoordinatorService::ResourceCoordinatorService()
@@ -39,6 +34,14 @@
                                     base::Unretained(ref_factory_.get()),
                                     base::Unretained(this)));
 
+  // Register new |CoordinationUnitGraphObserver| implementations here.
+  auto tab_signal_generator_impl = base::MakeUnique<TabSignalGeneratorImpl>();
+  registry_.AddInterface(
+      base::Bind(&TabSignalGeneratorImpl::BindToInterface,
+                 base::Unretained(tab_signal_generator_impl.get())));
+  coordination_unit_manager_.RegisterObserver(
+      std::move(tab_signal_generator_impl));
+
   coordination_unit_manager_.OnStart(&registry_, ref_factory_.get());
 }
 
diff --git a/services/ui/public/interfaces/window_manager.mojom b/services/ui/public/interfaces/window_manager.mojom
index 97f2b78a..269aba2b 100644
--- a/services/ui/public/interfaces/window_manager.mojom
+++ b/services/ui/public/interfaces/window_manager.mojom
@@ -284,6 +284,8 @@
   // WindowManagerWindowTreeFactory::CreateWindowTree() for details).
   // |local_surface_id| identifies the ID to use to submit CompositorFrames.
   // base::nullopt indicates failure.
+  // This function may also be used to move an existing display root to a new
+  // display.
   SetDisplayRoot(display.mojom.Display display,
                  WmViewportMetrics viewport_metrics,
                  bool is_primary_display,
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 92bbfdf..82fcc26b5 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -291,8 +291,7 @@
   DCHECK(window_manager_state_);  // Only called for window manager.
   DVLOG(3) << "SetDisplayRoot client=" << id_
            << " global window_id=" << client_window_id.id;
-  Display* display = display_manager()->GetDisplayById(display_to_create.id());
-  if (display) {
+  if (display_manager()->GetDisplayById(display_to_create.id())) {
     DVLOG(1) << "SetDisplayRoot called with existing display "
              << display_to_create.id();
     return nullptr;
@@ -305,14 +304,15 @@
   }
 
   ServerWindow* window = GetWindowByClientId(client_window_id);
-  // The window must not have a parent.
-  if (!window || window->parent()) {
+  const bool is_moving_to_new_display =
+      window && window->parent() && base::ContainsKey(roots_, window);
+  if (!window || (window->parent() && !is_moving_to_new_display)) {
     DVLOG(1) << "SetDisplayRoot called with invalid window id "
              << client_window_id.id;
     return nullptr;
   }
 
-  if (base::ContainsKey(roots_, window)) {
+  if (base::ContainsKey(roots_, window) && !is_moving_to_new_display) {
     DVLOG(1) << "SetDisplayRoot called with existing root";
     return nullptr;
   }
@@ -323,7 +323,7 @@
   viewport_metrics.device_scale_factor =
       transport_viewport_metrics.device_scale_factor;
   viewport_metrics.ui_scale_factor = transport_viewport_metrics.ui_scale_factor;
-  display = display_manager()->AddDisplayForWindowManager(
+  Display* display = display_manager()->AddDisplayForWindowManager(
       is_primary_display, display_to_create, viewport_metrics);
   DCHECK(display);
   WindowManagerDisplayRoot* display_root =
@@ -336,7 +336,13 @@
   // care of any modifications it needs to do.
   roots_.insert(window);
   Operation op(this, window_server_, OperationType::ADD_WINDOW);
+  ServerWindow* old_parent =
+      is_moving_to_new_display ? window->parent() : nullptr;
   display_root->root()->Add(window);
+  if (is_moving_to_new_display) {
+    DCHECK(old_parent);
+    window_manager_state_->DeleteWindowManagerDisplayRoot(old_parent);
+  }
   return window;
 }
 
diff --git a/services/ui/ws/window_tree_unittest.cc b/services/ui/ws/window_tree_unittest.cc
index 8350e1f..bc99456 100644
--- a/services/ui/ws/window_tree_unittest.cc
+++ b/services/ui/ws/window_tree_unittest.cc
@@ -1644,6 +1644,81 @@
                   .empty());
 }
 
+TEST_F(WindowTreeManualDisplayTest, MoveDisplayRootToNewDisplay) {
+  const bool automatically_create_display_roots = false;
+  AddWindowManager(window_server(), kTestUserId1,
+                   automatically_create_display_roots);
+
+  WindowManagerState* window_manager_state =
+      window_server()->GetWindowManagerStateForUser(kTestUserId1);
+  ASSERT_TRUE(window_manager_state);
+  WindowTree* window_manager_tree = window_manager_state->window_tree();
+  EXPECT_TRUE(window_manager_tree->roots().empty());
+  TestWindowManager* test_window_manager =
+      window_server_delegate()->last_binding()->window_manager();
+  EXPECT_EQ(1, test_window_manager->connect_count());
+  EXPECT_EQ(0, test_window_manager->display_added_count());
+
+  // Create a window for the windowmanager and set it as the root.
+  ClientWindowId display_root_id = BuildClientWindowId(window_manager_tree, 10);
+  ASSERT_TRUE(window_manager_tree->NewWindow(display_root_id,
+                                             ServerWindow::Properties()));
+  ServerWindow* display_root =
+      window_manager_tree->GetWindowByClientId(display_root_id);
+  ASSERT_TRUE(display_root);
+  display::Display display1 = MakeDisplay(0, 0, 1024, 768, 1.0f);
+  constexpr int64_t display1_id = 101;
+  display1.set_id(display1_id);
+
+  mojom::WmViewportMetrics metrics;
+  metrics.bounds_in_pixels = display1.bounds();
+  metrics.device_scale_factor = 1.5;
+  metrics.ui_scale_factor = 2.5;
+  const bool is_primary_display = true;
+  ASSERT_TRUE(WindowTreeTestApi(window_manager_tree)
+                  .ProcessSetDisplayRoot(display1, metrics, is_primary_display,
+                                         display_root_id));
+  ASSERT_TRUE(display_root->parent());
+  const WindowId display1_parent_id = display_root->parent()->id();
+  EXPECT_TRUE(window_server_delegate()
+                  ->last_binding()
+                  ->client()
+                  ->tracker()
+                  ->changes()
+                  ->empty());
+  EXPECT_EQ(1u, window_manager_tree->roots().size());
+
+  // Call ProcessSetDisplayRoot() again, with a different display.
+  display::Display display2 = MakeDisplay(0, 0, 1024, 768, 1.0f);
+  constexpr int64_t display2_id = 102;
+  display2.set_id(display2_id);
+  ASSERT_TRUE(WindowTreeTestApi(window_manager_tree)
+                  .ProcessSetDisplayRoot(display2, metrics, is_primary_display,
+                                         display_root_id));
+  ASSERT_TRUE(display_root->parent());
+  EXPECT_NE(display1_parent_id, display_root->parent()->id());
+  EXPECT_TRUE(window_server_delegate()
+                  ->last_binding()
+                  ->client()
+                  ->tracker()
+                  ->changes()
+                  ->empty());
+  EXPECT_EQ(1u, window_manager_tree->roots().size());
+  // The WindowManagerDisplayRoot for |display1| should have been deleted.
+  EXPECT_EQ(1u, WindowManagerStateTestApi(window_manager_state)
+                    .window_manager_display_roots()
+                    .size());
+  EXPECT_FALSE(window_server()->display_manager()->GetDisplayById(display1_id));
+  EXPECT_TRUE(window_server()->display_manager()->GetDisplayById(display2_id));
+
+  // Delete the root, which should delete the WindowManagerDisplayRoot.
+  EXPECT_TRUE(window_manager_tree->DeleteWindow(display_root_id));
+  EXPECT_TRUE(window_manager_tree->roots().empty());
+  EXPECT_TRUE(WindowManagerStateTestApi(window_manager_state)
+                  .window_manager_display_roots()
+                  .empty());
+}
+
 TEST_F(WindowTreeManualDisplayTest,
        DisplayManagerObserverNotifiedWithManualRoots) {
   const bool automatically_create_display_roots = false;
diff --git a/services/viz/README.md b/services/viz/README.md
new file mode 100644
index 0000000..2c81055
--- /dev/null
+++ b/services/viz/README.md
@@ -0,0 +1,143 @@
+Viz Directory Structure
+--------------------------------------------------------------------------------
+
+The Viz (Visuals) service is a collection of subservices: compositing, gl, hit
+testing, and media.
+
+Viz has two types of clients: a single privileged client and one or more
+unprivileged clients.
+
+The privileged client is responsible for starting and restarting Viz after a
+crash and for facilitating connections to Viz from unprivileged clients. The
+privileged client is trusted by all other clients, and is expected to be
+long-lived and not prone to crashes.
+
+Unprivileged clients request connections to Viz through the privileged client
+such as the browser process or the window server. Furthermore, unprivileged
+clients may be malicious or may crash at any time. Unprivileged clients are
+expected to be mutually distrusting of one another. Thus, an unprivileged client
+cannot be provided interfaces by which it can impact the operation of another
+client.
+
+For example, a channel to the GL service can only be dispensed by the privileged
+client, but can be used by unprivileged clients. GL commands are exposed as a
+stable public API to the command buffer by the client library whereas the
+underlying IPC messages and their semantics are constantly changing and
+meaningless without deep knowledge of implementation details.
+
+We propose the following directory structure to accommodate Viz's needs.
+
+//services/viz/public/interfaces/{compositing, gl, hit_test, media}
+//services/viz/public/<language>/{compositing, gl, hit_test, media}
+--------------------------------------------------------------------------------
+
+The interfaces directories contain mojoms that define the public, unprivileged
+interface for the Viz subservices. Clients may directly use the mojo interfaces
+in these directories or choose to use the client library in a public/<language>
+directory if one exists for a given mojom. private and privileged interfaces
+described below may depend on public interfaces.
+
+//services/viz/public/<language>/{compositing, gl, hit_test, media}:data_types
+--------------------------------------------------------------------------------
+
+Common data types such as CompositorFrame, and GpuMemoryBufferHandle can live in
+//services/viz/public/<language>/{compositing, gl, hit_test, media} under the
+data_types target.
+
+Their associated mojoms can live in:
+
+//services/viz/public/interfaces/{compositing, gl, hit_test, media}.
+
+Note:
+
+//services/viz/public/<language>/{compositing, gl, hit_test, media}:data_types
+holds C++ types only and does not depend on
+//services/viz/public/interfaces/{compositing, gl, hit_test, media}. Instead,
+there are StructTraits with the interfaces that produce/consume data_types for
+mojo transport.
+
+//services/viz/{compositing, gl, hit_test, media}/private/interfaces
+--------------------------------------------------------------------------------
+
+These interfaces directories contain mojoms that may only be used by going
+through a language-specific client library. They are meant for unprivileged use,
+without direct access to the mojoms. As such, only the
+//services/viz/public/<language> and //services/viz/privileged/<language>
+directories may depend on private, while other directories including interface
+directories must not. There is no private client library, as these are meant for
+consumption by the public client library.
+
+//services/viz/{compositing, gl, hit_test, media}/privileged/interfaces
+//services/viz/{compositing, gl, hit_test, media}/privileged/<language>
+--------------------------------------------------------------------------------
+
+The interfaces directories contains mojoms that may only be used by the
+privileged client. Privileged interfaces are kept in separate directories to
+facilitate security reviews. These interfaces may be used directly or through
+the a privileged/<language> client library. The public and private interfaces
+must not depend on privileged interfaces. Typically, the browser process or the
+window server serves as the privileged client to Viz.
+
+//services/viz/main
+--------------------------------------------------------------------------------
+
+This is the glue code that implements the primordial VizMain interface (in
+//services/viz/main/privileged/interfaces) that starts up the Viz process
+through the service manager. VizMain is a factory interface that enables the
+privileged client to instantiate the Viz subservices: compositing, gl, hit_test,
+and media.
+
+//services/viz/{compositing, gl, hit_test, media}/service
+--------------------------------------------------------------------------------
+
+Service-side implementation code live in the various sub-service "service"
+directories. Service code may depend on the public/<language>/…:data_types
+target and interfaces subdirectories, but cannot depend on any of the
+//service/viz/public/<language>/... client library.
+
+Short term: //components/viz and //gpu and //media
+--------------------------------------------------------------------------------
+
+At this time, the Viz public client library for the compositing and hit_test
+subservices live in //components/viz/client, and the privileged client library
+lives in //components/viz/host.
+
+Command buffer code will continue to live in //gpu and media code will continue
+to live in //media.
+
+Once the content module has been removed (or no longer depends on
+components/viz/service), the code in //components/viz/client will move to
+appropriate destinations in //services/viz/public/<language>/....
+//components/viz/service will move to the appropriate service directories in
+//services/viz/.... //components/viz/host will move to
+//services/viz/{compositing, gl, hit_test, media}/privileged.
+
+Once the content module is gone, and //services/ui is the only privileged
+client, then perhaps the privileged client library may move to //services/ui.
+
+Acceptable Dependencies
+--------------------------------------------------------------------------------
+
+Note: => means can depend on
+
+Unprivileged client, can depend on
+  services/viz/public/<language>/{compositing, gl, hit_test, media} =>
+    services/viz/public/interfaces/{compositing, gl, hit_test, media} =>
+      services/viz/public/<language>/{compositing, gl, hit_test, media}:data_types
+    services/viz/private/interfaces/{compositing, gl, hit_test, media} =>
+      services/viz/public/<language>/{compositing, gl, hit_test, media}:data_types
+  services/viz/public/interfaces/{compositing, gl, hit_test, media}
+
+The privileged client can depend on
+  services/viz/privileged/<language>/{compositing, gl, hit_test, media} =>
+    services/viz/privileged/interfaces/{compositing, gl, hit_test, media}
+  services/viz/public/interfaces/{compositing, gl, hit_test, media}
+  services/viz/public/<language>/{compositing, gl, hit_test, media}
+
+Services can depend on:
+  services/viz/public/interfaces/{compositing, gl, hit_test, media}
+  services/viz/public/<language>/{compositing, gl, hit_test, media}:data_types
+  services/viz/privileged/interfaces/{compositing, gl, hit_test, media}
+  services/viz/private/interfaces/{compositing, gl, hit test, media}
+
+
diff --git a/services/viz/hit_test/public/interfaces/BUILD.gn b/services/viz/hit_test/public/interfaces/BUILD.gn
new file mode 100644
index 0000000..b9d25a15
--- /dev/null
+++ b/services/viz/hit_test/public/interfaces/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+  sources = [
+    "hit_test_region_list.mojom",
+  ]
+
+  public_deps = [
+    "//cc/ipc:interfaces",
+    "//ui/gfx/geometry/mojo",
+    "//ui/gfx/mojo",
+  ]
+}
diff --git a/services/viz/hit_test/public/interfaces/OWNERS b/services/viz/hit_test/public/interfaces/OWNERS
new file mode 100644
index 0000000..e1fa1e06
--- /dev/null
+++ b/services/viz/hit_test/public/interfaces/OWNERS
@@ -0,0 +1,3 @@
+rjkroege@chromium.org
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/viz/hit_test/public/interfaces/hit_test_region_list.mojom b/services/viz/hit_test/public/interfaces/hit_test_region_list.mojom
new file mode 100644
index 0000000..3c36743
--- /dev/null
+++ b/services/viz/hit_test/public/interfaces/hit_test_region_list.mojom
@@ -0,0 +1,59 @@
+// 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.
+
+module viz.mojom;
+
+import "cc/ipc/surface_id.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+import "ui/gfx/mojo/transform.mojom";
+
+// Region maps to this surface (me).
+const uint32 kHitTestMine = 0x01;
+
+// Region ignored for hit testing (transparent backgrounds & hover:none).
+const uint32 kHitTestIgnore = 0x02;
+
+// Region maps to child surface (OOPIF).
+const uint32 kHitTestChildSurface = 0x04;
+
+// Irregular boundary - send HitTestRequest to resolve.
+const uint32 kHitTestAsk = 0x08;
+
+// Touch event handler exists.
+const uint32 kHitTestTouchEventHandler = 0x10;
+
+struct HitTestRegion {
+  // Flags to indicate the type of HitTestRegion.
+  uint32 flags;
+
+  // SurfaceId is required when flags = kHitTestChildSurface.
+  cc.mojom.SurfaceId surface_id;
+
+  // The rect of the region in the coordinate space of the embedder.
+  gfx.mojom.Rect rect;
+
+  // The transform of the region.  The transform applied to the rect
+  // defines the space occupied by this region in the coordinate space of
+  // the embedder.
+  gfx.mojom.Transform transform;
+};
+
+struct HitTestRegionList {
+  // SurfaceId corresponding to this HitTestData.
+  cc.mojom.SurfaceId surface_id;
+
+  // Flags indicate how to handle events that match no sub-regions.
+  // kHitTestMine routes un-matched events to this surface (opaque).
+  // kHitTestIgnore keeps previous match in the parent (transparent).
+  uint32 flags;
+
+  // The bounds of the surface.
+  gfx.mojom.Rect bounds;
+
+  // The transform applied to all regions in this surface.
+  gfx.mojom.Transform transform;
+
+  // The list of sub-regions in front to back order.
+  array<HitTestRegion> regions;
+};
diff --git a/testing/buildbot/tryserver.chromium.perf.json b/testing/buildbot/tryserver.chromium.perf.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/testing/buildbot/tryserver.chromium.perf.json
@@ -0,0 +1 @@
+{}
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 4dc74b6..c73d3c1 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -547,6 +547,9 @@
 Bug(none) fast/loader/stateobjects/pushstate-in-data-url-denied.html [ Failure ]
 Bug(none) fast/loader/url-strip-cr-lf-tab.html [ Failure ]
 Bug(none) fast/media/mq-color-gamut-picture.html [ Failure ]
+Bug(none) fast/mediacapturefromelement/HTMLMediaElementCapture-capture.html [ Timeout ]
+Bug(none) fast/mediacapturefromelement/HTMLMediaElementCapture-creation.html [ Timeout ]
+Bug(none) fast/mediacapturefromelement/HTMLMediaElementCapture-ended.html [ Timeout ]
 Bug(none) fast/mediarecorder/BlobEvent-basic.html [ Failure ]
 Bug(none) fast/mediastream/MediaStreamTrack-clone.html [ Timeout ]
 Bug(none) fast/mediastream/MediaStreamTrack-contentHint.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 6a8af3f..86de759 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1804,6 +1804,19 @@
 crbug.com/626703 external/wpt/css/css-writing-modes-3/sizing-orthog-vrl-in-htb-020.xht [ Failure ]
 crbug.com/626703 external/wpt/css/css-writing-modes-3/wm-propagation-body-008.xht [ Failure ]
 
+crbug.com/743085 inspector-protocol/debugger/debugger-setBlackboxPatterns.js [ NeedsManualRebaseline ]
+crbug.com/743085 inspector-protocol/debugger/stepping-with-blackboxed-ranges.js [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-breakpoints/possible-breakpoints.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-frameworks/frameworks-sourcemap.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-step/debugger-step-into-inlined-scripts.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-step/debugger-step-over-inlined-scripts.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger-step/debugger-step-through-promises.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger/debugger-return-value.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger/live-edit.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger/source-frame-breakpoint-decorations.html [ NeedsManualRebaseline ]
+crbug.com/743085 inspector/sources/debugger/source-frame-inline-breakpoint-decorations.html [ NeedsManualRebaseline ]
+
 crbug.com/655458 crbug.com/721814 external/wpt/mediacapture-image/idlharness.html [ Skip ]
 crbug.com/655458 crbug.com/721814 external/wpt/WebCryptoAPI/idlharness.html [ Skip ]
 crbug.com/655458 crbug.com/721814 external/wpt/WebCryptoAPI/idlharness.https.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 02dbe699..71fac13 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -104544,16 +104544,6 @@
      {}
     ]
    ],
-   "service-workers/service-worker/fetch-canvas-tainting-cache.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "service-workers/service-worker/fetch-canvas-tainting.https-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "service-workers/service-worker/fetch-event-redirect.https-expected.txt": [
     [
      {}
@@ -125513,6 +125503,16 @@
      {}
     ]
    ],
+   "dom/abort/event.any.js": [
+    [
+     "/dom/abort/event.any.html",
+     {}
+    ],
+    [
+     "/dom/abort/event.any.worker.html",
+     {}
+    ]
+   ],
    "dom/collections/HTMLCollection-as-proto-length-get-throws.html": [
     [
      "/dom/collections/HTMLCollection-as-proto-length-get-throws.html",
@@ -183681,11 +183681,11 @@
    "reftest"
   ],
   "css-paint-api/background-image-tiled-ref.html": [
-   "a879be73470aae683bd7596132225770bc8be27b",
+   "bcee5040691f057a672e58eec3beed75122be3b8",
    "support"
   ],
   "css-paint-api/background-image-tiled.html": [
-   "03aff62fc21832b44d9de15805232d87d0089ed3",
+   "83f9e2566f9e6957fdf3b67e9e62374984861e78",
    "reftest"
   ],
   "css-paint-api/geometry-background-image-001-ref.html": [
@@ -183713,11 +183713,11 @@
    "reftest"
   ],
   "css-paint-api/geometry-background-image-tiled-001-ref.html": [
-   "df994fa58244f5e8d4b4aac7f0ad335fe8570dcc",
+   "475fd7979cd173f378c03a7d9d27503e12c2dc7c",
    "support"
   ],
   "css-paint-api/geometry-background-image-tiled-001.html": [
-   "f89e6c4f164c10a64037a3feefd915d760a99765",
+   "a892266cab4d74a3f4df2bbe1cda8823a38f3153",
    "reftest"
   ],
   "css-paint-api/geometry-background-image-tiled-002-ref.html": [
@@ -220356,6 +220356,10 @@
    "e3e7f3973cf8f9b466d4f22d1ec3b9b9241fb906",
    "support"
   ],
+  "dom/abort/event.any.js": [
+   "25e9c1104acb9b0092d1303190588a3953cf635d",
+   "testharness"
+  ],
   "dom/collections/HTMLCollection-as-proto-length-get-throws.html": [
    "487f3991b116ceb503352ed025961282a8761e95",
    "testharness"
@@ -220601,7 +220605,7 @@
    "testharness"
   ],
   "dom/interface-objects.html": [
-   "144554e0a9d53cdbb2c1f01d3dc169010db693b3",
+   "05963c8b0a839f3e07b5478d99fc034e4654b515",
    "testharness"
   ],
   "dom/interfaces-expected.txt": [
@@ -220609,7 +220613,7 @@
    "support"
   ],
   "dom/interfaces.html": [
-   "aae8f328bc52cbb17f47f78ace6d20c25a9c3acc",
+   "7d00e3a778083a91156f4e042c7abd270060a7fc",
    "testharness"
   ],
   "dom/lists/DOMTokenList-Iterable.html": [
@@ -225193,7 +225197,7 @@
    "support"
   ],
   "fetch/api/response/response-consume-stream.html": [
-   "7dd429b389a997a879362629985089bad495a227",
+   "dad05becbd8f3944aa3709ae1a3e578c05d4d935",
    "testharness"
   ],
   "fetch/api/response/response-consume.html": [
@@ -241761,7 +241765,7 @@
    "support"
   ],
   "interfaces/dom.idl": [
-   "2b94c6332d8535bbcfd605bc3ed46ba6f705de62",
+   "f39e0bad95534e2cc59012436ea430fe2a414c05",
    "support"
   ],
   "interfaces/fullscreen.idl": [
@@ -251217,7 +251221,7 @@
    "support"
   ],
   "payment-request/payment-request-canmakepayment-method.https.html": [
-   "3b145e1e2164d5201ded51ce138aeeb4163e0261",
+   "988988ff3ff697b9e4ce615c709fb49df69235ab",
    "testharness"
   ],
   "payment-request/payment-request-constructor-crash.https-expected.txt": [
@@ -260648,18 +260652,10 @@
    "401235c18e1594c7248b22eb6881d54801de9809",
    "testharness"
   ],
-  "service-workers/service-worker/fetch-canvas-tainting-cache.https-expected.txt": [
-   "0d8e7b013322279c687fe6a602746db6c3a4bca2",
-   "support"
-  ],
   "service-workers/service-worker/fetch-canvas-tainting-cache.https.html": [
    "b3f8375bc412c99099ac886673fd80f6cb0a312b",
    "testharness"
   ],
-  "service-workers/service-worker/fetch-canvas-tainting.https-expected.txt": [
-   "76743fb558f5f25a03603e2795bfbdf90deca639",
-   "support"
-  ],
   "service-workers/service-worker/fetch-canvas-tainting.https.html": [
    "9c2e160f95d2915a961bd7da840ac53779c9387d",
    "testharness"
@@ -264417,7 +264413,7 @@
    "support"
   ],
   "url/urlsearchparams-constructor.html": [
-   "854e06efa9598f66705605bdef20c4a500ab2e9b",
+   "e7d341e38acba7c7608da8567c20a3468ca522e2",
    "testharness"
   ],
   "url/urlsearchparams-delete-expected.txt": [
@@ -264425,7 +264421,7 @@
    "support"
   ],
   "url/urlsearchparams-delete.html": [
-   "b1fcda755e2a9e3308a222fe213abf0a255f0777",
+   "4713dfec8b4277cc29520dbd25958bd74e440c19",
    "testharness"
   ],
   "url/urlsearchparams-foreach-expected.txt": [
@@ -264453,7 +264449,7 @@
    "testharness"
   ],
   "url/urlsearchparams-sort.html": [
-   "6a3904b5dada6b1e071b16529e75c6ce18ce45d6",
+   "dfc8f32339d084299318e9eb94fc47171247f2e1",
    "testharness"
   ],
   "url/urlsearchparams-stringifier.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https.html b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https.html
new file mode 100644
index 0000000..681e195
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/script-src/script-src-strict_dynamic_worker-importScripts.https.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<script src='../support/testharness-helper.js'></script>
+
+<meta http-equiv="content-security-policy" content="script-src 'nonce-abc' 'strict-dynamic'">
+
+<script nonce="abc">
+  async_test(t => {
+    assert_no_csp_event_for_url(t, "../support/import-scripts.js");
+    var w = new Worker("../support/import-scripts.js");
+    assert_no_event(t, w, "error");
+    waitUntilEvent(w, "message")
+      .then(t.step_func_done(e => {
+        assert_true(e.data.executed);
+      }));
+  }, "`importScripts(...)` is allowed by 'strict-dynamic'");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/import-scripts.js b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/import-scripts.js
new file mode 100644
index 0000000..8325ebb3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/content-security-policy/support/import-scripts.js
@@ -0,0 +1,3 @@
+self.a = false;
+importScripts('/content-security-policy/support/var-a.js');
+postMessage({ 'executed': self.a });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/abort/event.any.js b/third_party/WebKit/LayoutTests/external/wpt/dom/abort/event.any.js
new file mode 100644
index 0000000..3b25702
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/abort/event.any.js
@@ -0,0 +1,22 @@
+test(t => {
+  const c = new AbortController(),
+        s = c.signal;
+  let state = "begin";
+
+  assert_false(s.aborted);
+
+  s.addEventListener("abort",
+    t.step_func(e => {
+      assert_equals(state, "begin");
+      state = "aborted";
+    })
+  );
+  c.abort();
+
+  assert_equals(state, "aborted");
+  assert_true(s.aborted);
+
+  c.abort();
+}, "AbortController() basics");
+
+done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects-expected.txt
new file mode 100644
index 0000000..cfa04f8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects-expected.txt
@@ -0,0 +1,26 @@
+This is a testharness.js-based test.
+PASS Interface objects properties should not be Enumerable 
+PASS Should be able to delete Event. 
+PASS Should be able to delete CustomEvent. 
+PASS Should be able to delete EventTarget. 
+FAIL Should be able to delete AbortController. assert_true: Interface should exist. expected true got false
+FAIL Should be able to delete AbortSignal. assert_true: Interface should exist. expected true got false
+PASS Should be able to delete Node. 
+PASS Should be able to delete Document. 
+PASS Should be able to delete DOMImplementation. 
+PASS Should be able to delete DocumentFragment. 
+PASS Should be able to delete ProcessingInstruction. 
+PASS Should be able to delete DocumentType. 
+PASS Should be able to delete Element. 
+PASS Should be able to delete Attr. 
+PASS Should be able to delete CharacterData. 
+PASS Should be able to delete Text. 
+PASS Should be able to delete Comment. 
+PASS Should be able to delete NodeIterator. 
+PASS Should be able to delete TreeWalker. 
+PASS Should be able to delete NodeFilter. 
+PASS Should be able to delete NodeList. 
+PASS Should be able to delete HTMLCollection. 
+PASS Should be able to delete DOMTokenList. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects.html b/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects.html
index df4ca51..936d635 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interface-objects.html
@@ -15,6 +15,8 @@
   "Event",
   "CustomEvent",
   "EventTarget",
+  "AbortController",
+  "AbortSignal",
   "Node",
   "Document",
   "DOMImplementation",
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt
index a5f71f6..d102b79 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 1618 tests; 1610 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 1646 tests; 1610 PASS, 36 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Test driver 
 PASS Event interface: existence and properties of interface object 
 PASS Event interface object length 
@@ -116,6 +116,34 @@
 PASS EventListener interface: existence and properties of interface prototype object 
 PASS EventListener interface: existence and properties of interface prototype object's "constructor" property 
 PASS EventListener interface: operation handleEvent(Event) 
+FAIL AbortController interface: existence and properties of interface object assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface object length assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface object name assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface: attribute signal assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController interface: operation abort() assert_own_property: self does not have own property "AbortController" expected property "AbortController" missing
+FAIL AbortController must be primary interface of new AbortController() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL Stringification of new AbortController() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL AbortController interface: new AbortController() must inherit property "signal" with the proper type (0) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL AbortController interface: new AbortController() must inherit property "abort" with the proper type (1) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL AbortSignal interface: existence and properties of interface object assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface object length assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface object name assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface: existence and properties of interface prototype object assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface: attribute aborted assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal interface: attribute onabort assert_own_property: self does not have own property "AbortSignal" expected property "AbortSignal" missing
+FAIL AbortSignal must be primary interface of new AbortController().signal assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL Stringification of new AbortController().signal assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL AbortSignal interface: new AbortController().signal must inherit property "aborted" with the proper type (0) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL AbortSignal interface: new AbortController().signal must inherit property "onabort" with the proper type (1) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: new AbortController().signal must inherit property "addEventListener" with the proper type (0) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: calling addEventListener(DOMString,EventListener,[object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: new AbortController().signal must inherit property "removeEventListener" with the proper type (1) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: calling removeEventListener(DOMString,EventListener,[object Object],[object Object]) on new AbortController().signal with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: new AbortController().signal must inherit property "dispatchEvent" with the proper type (2) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
+FAIL EventTarget interface: calling dispatchEvent(Event) on new AbortController().signal with too few arguments must throw TypeError assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: AbortController is not defined"
 PASS NodeList interface: existence and properties of interface object 
 PASS NodeList interface object length 
 PASS NodeList interface object name 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces.html
index 8b4140d..8e9572d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/interfaces.html
@@ -24,6 +24,8 @@
     EventTarget: ['new EventTarget()'],
     Event: ['document.createEvent("Event")', 'new Event("foo")'],
     CustomEvent: ['new CustomEvent("foo")'],
+    AbortController: ['new AbortController()'],
+    AbortSignal: ['new AbortController().signal'],
     Document: ['new Document()'],
     XMLDocument: ['xmlDoc'],
     DOMImplementation: ['document.implementation'],
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-consume-stream.html b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-consume-stream.html
index 54d55fcb..21424f2a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-consume-stream.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/response/response-consume-stream.html
@@ -65,7 +65,7 @@
 }, "Getting an error Response stream");
 
 promise_test(function(test) {
-    assert_equals(Response.redirect(301).body, null);
+    assert_equals(Response.redirect("/").body, null);
 }, "Getting a redirect Response stream");
 
     </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/dom.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/dom.idl
index 9ca270ea..b1a959ec 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/dom.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/dom.idl
@@ -1,5 +1,5 @@
-[Constructor(DOMString type, optional EventInit eventInitDict)/*,
- Exposed=(Window,Worker)*/]
+[Constructor(DOMString type, optional EventInit eventInitDict),
+ Exposed=(Window,Worker)]
 interface Event {
   readonly attribute DOMString type;
   readonly attribute EventTarget? target;
@@ -31,8 +31,8 @@
 };
 
 
-[Constructor(DOMString type, optional CustomEventInit eventInitDict)/*,
- Exposed=(Window,Worker)*/]
+[Constructor(DOMString type, optional CustomEventInit eventInitDict),
+ Exposed=(Window,Worker)]
 interface CustomEvent : Event {
   readonly attribute any detail;
 
@@ -44,7 +44,8 @@
 };
 
 
-[Constructor/*, Exposed=(Window,Worker)*/]
+[Constructor,
+ Exposed=(Window,Worker)]
 interface EventTarget {
   void addEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
   void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
@@ -61,6 +62,23 @@
 };
 
 
+[Constructor,
+ Exposed=(Window,Worker)]
+interface AbortController {
+  [SameObject] readonly attribute AbortSignal signal;
+
+  void abort();
+};
+
+
+[Exposed=(Window,Worker)]
+interface AbortSignal : EventTarget {
+  readonly attribute boolean aborted;
+
+  attribute EventHandler onabort;
+};
+
+
 [NoInterfaceObject,
  Exposed=Window]
 interface NonElementParentNode {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm
deleted file mode 100644
index c5b064de..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-a-128k-44100Hz-1ch.webm
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
deleted file mode 100644
index 8b705db..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm b/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm
deleted file mode 100644
index 189c472..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/webm/test-v-128k-320x240-24fps-8kfr.webm
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
index 891a62d..981ddb8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-request-canmakepayment-method.https.html
@@ -30,7 +30,7 @@
       `canMakePaymentPromise should be true`
     );
   } catch (err) {
-    assert_equal(
+    assert_equals(
       err.name,
       "NotAllowedError",
       "if it throws, then it must be a NotAllowedError."
@@ -71,7 +71,7 @@
       `should have thrown InvalidStateError, but instead returned "${result}"`
     );
   } catch (err) {
-    assert_equal(
+    assert_equals(
       err.name,
       "InvalidStateError",
       "must be an InvalidStateError."
@@ -124,7 +124,7 @@
     try {
       await request.canMakePayment();
     } catch (err) {
-      assert_equal(
+      assert_equals(
         err.name,
         "NotAllowedError",
         "if it throws, then it must be a NotAllowedError."
@@ -136,7 +136,7 @@
     try {
       await new PaymentRequest(defaultMethods, defaultDetails).canMakePayment();
     } catch (err) {
-      assert_equal(
+      assert_equals(
         err.name,
         "NotAllowedError",
         "if it throws, then it must be a NotAllowedError."
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor-expected.txt
deleted file mode 100644
index 31edfdf6..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-This is a testharness.js-based test.
-PASS Basic URLSearchParams construction 
-PASS URLSearchParams constructor, no arguments 
-FAIL URLSearchParams constructor, DOMException.prototype as argument Illegal invocation
-PASS URLSearchParams constructor, empty string as argument 
-PASS URLSearchParams constructor, {} as argument 
-PASS URLSearchParams constructor, string. 
-PASS URLSearchParams constructor, object. 
-PASS Parse + 
-PASS Parse encoded + 
-PASS Parse space 
-PASS Parse %20 
-PASS Parse \0 
-PASS Parse %00 
-PASS Parse ⎄ 
-PASS Parse %e2%8e%84 
-PASS Parse 💩 
-PASS Parse %f0%9f%92%a9 
-PASS Constructor with sequence of sequences of strings 
-PASS Construct with object with + 
-PASS Construct with object with two keys 
-PASS Construct with array with two keys 
-PASS Construct with object with NULL, non-ASCII, and surrogate keys 
-PASS Custom [Symbol.iterator] 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor.html b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor.html
index 1e214e0..0637a38 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-constructor.html
@@ -23,9 +23,11 @@
 }, "URLSearchParams constructor, no arguments")
 
 test(() => {
-    params = new URLSearchParams(DOMException.prototype);
+    params = new URLSearchParams(DOMException);
     assert_equals(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21&QUOTA_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25")
-}, "URLSearchParams constructor, DOMException.prototype as argument")
+    assert_throws(new TypeError(), () => new URLSearchParams(DOMException.prototype),
+                  "Constructing a URLSearchParams from DOMException.prototype should throw due to branding checks");
+}, "URLSearchParams constructor, DOMException as argument")
 
 test(() => {
     params = new URLSearchParams('');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete-expected.txt
deleted file mode 100644
index f3a9421..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-PASS Delete basics 
-PASS Deleting appended multiple 
-FAIL Deleting all params keeps ? in URL assert_equals: url.href has ? expected "http://example.com/?" but got "http://example.com/"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete.html b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete.html
index afc9c60..d4bc0a6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-delete.html
@@ -41,9 +41,16 @@
     var url = new URL('http://example.com/?param1&param2');
     url.searchParams.delete('param1');
     url.searchParams.delete('param2');
-    assert_equals(url.href, 'http://example.com/?', 'url.href has ?');
+    assert_equals(url.href, 'http://example.com/', 'url.href does not have ?');
     assert_equals(url.search, '', 'url.search does not have ?');
-}, 'Deleting all params keeps ? in URL');
+}, 'Deleting all params removes ? from URL');
+
+test(function() {
+    var url = new URL('http://example.com/?');
+    url.searchParams.delete('param1');
+    assert_equals(url.href, 'http://example.com/', 'url.href does not have ?');
+    assert_equals(url.search, '', 'url.search does not have ?');
+}, 'Removing non-existent param removes ? from URL');
 </script>
 </head>
 </html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-sort.html b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-sort.html
index e643ed3..34199894 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-sort.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/url/urlsearchparams-sort.html
@@ -47,4 +47,11 @@
     }
   }, "URL parse and sort: " + val.input)
 })
+
+test(function() {
+  const url = new URL("http://example.com/?")
+  url.searchParams.sort()
+  assert_equals(url.href, "http://example.com/")
+  assert_equals(url.search, "")
+}, "Sorting non-existent params removes ? from URL")
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-capture.html
similarity index 83%
rename from third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html
rename to third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-capture.html
index 3a99e5c..65d9d5c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/capture.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-capture.html
@@ -1,10 +1,6 @@
 <!DOCTYPE html>
-<html>
-<head>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-</head>
-<body>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
 <script>
 
 // Run captureStream() on different videos, and assert data is flowing.
@@ -12,7 +8,7 @@
 var makeAsyncTest = function(filename) {
   async_test(function(test) {
     var video = document.createElement('video');
-    video.src = "webm/" + filename;
+    video.src = "../../http/tests/media/resources/media-source/webm/" + filename;
     video.onerror = this.unreached_func("<video> error");
     video.play();
 
@@ -36,5 +32,3 @@
 ]);
 
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-creation.html
similarity index 78%
rename from third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html
rename to third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-creation.html
index bf4c2f6c6..57a29e6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/creation.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-creation.html
@@ -1,10 +1,6 @@
 <!DOCTYPE html>
-<html>
-<head>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-</head>
-<body>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
 <script>
 
 // Run captureStream() on <video>/<audio>s and inspect the generated Stream.
@@ -12,7 +8,7 @@
 var makeAsyncTest = function(filename, numTracks) {
   async_test(function() {
     var video = document.createElement('video');
-    video.src = "webm/" + filename;
+    video.src = "../../http/tests/media/resources/media-source/webm/" + filename;
     video.onerror = this.unreached_func("<video> error");
     video.play();
 
@@ -31,9 +27,7 @@
 generate_tests(makeAsyncTest, [
   [ "video-only", "test-v-128k-320x240-24fps-8kfr.webm", {vid : 1, aud : 0} ],
   [ "audio-only", "test-a-128k-44100Hz-1ch.webm", {vid : 0, aud : 1} ],
-  [ "video+audio", "test-av-384k-44100Hz-1ch-320x240-30fps-10kfr.webm", {vid : 1, aud : 1} ]
+  [ "video+audio", "test.webm", {vid : 1, aud : 1} ]
 ]);
 
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-ended.html
similarity index 77%
rename from third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html
rename to third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-ended.html
index 91bdbbf8..bf49be23 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/mediacapture-fromelement/ended.html
+++ b/third_party/WebKit/LayoutTests/fast/mediacapturefromelement/HTMLMediaElementCapture-ended.html
@@ -1,10 +1,6 @@
 <!DOCTYPE html>
-<html>
-<head>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-</head>
-<body>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
 <script>
 
 // Run captureStream() on different videos, and assert the mediastream is
@@ -13,7 +9,7 @@
 var makeAsyncTest = function(filename) {
   async_test(function(test) {
     var video = document.createElement('video');
-    video.src = "webm/" + filename;
+    video.src = "../../http/tests/media/resources/media-source/webm/" + filename;
     video.onerror = this.unreached_func("<video> error");
     video.play();
 
@@ -25,7 +21,7 @@
       assert_false(stream.active, 'stream must be inactive');
     });
 
- }), "<video>.captureStream() and assert ended event.";
+ }), "<video>.captureStream() and assert data flows.";
 };
 
 generate_tests(makeAsyncTest, [
@@ -35,5 +31,3 @@
 ]);
 
 </script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis-expected.html b/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis-expected.html
new file mode 100644
index 0000000..d912be9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis-expected.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<style>
+a.trigger {
+  width: 337px;
+  height: 16px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  display: inline-block;
+  border: 1px solid;
+}
+
+div{
+  height: 16px;
+  width: 32px;
+  float: left;
+}
+
+</style>
+<p>crbug.com/275883: Restore position of line box correctly after deleting ellipsis.</p>
+<a class="trigger">
+  <div></div>
+  <span id="span">This is shorter text</span>
+</a>
+<input type="button" id="input" value="Change Text" />
diff --git a/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis.html b/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis.html
new file mode 100644
index 0000000..886aa295
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/text/recalc-position-of-linebox-after-deleting-ellipsis.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<style>
+a.trigger {
+  width: 337px;
+  height: 16px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  display: inline-block;
+  border: 1px solid;
+}
+
+div{
+  height: 16px;
+  width: 32px;
+  float: left;
+}
+
+</style>
+<p>crbug.com/275883: Restore position of line box correctly after deleting ellipsis.</p>
+<a class="trigger">
+  <div></div>
+  <span id="span">Some text</span>
+</a>
+<input type="button" id="input" value="Change Text" />
+<script>
+var toggle = 0;
+input.onclick =  function (e) {
+  var text = (toggle) ? 'Really really really long text that is so long long really long' : 'This is shorter text';
+  span.textContent = text;
+  toggle = (toggle) ? 0 : 1;
+};
+document.body.offsetTop;
+eventSender.mouseMoveTo(355, 55);
+eventSender.mouseDown();
+eventSender.mouseUp();
+eventSender.mouseDown();
+eventSender.mouseUp();
+eventSender.mouseDown();
+eventSender.mouseUp();
+eventSender.mouseMoveTo(155, 55);
+eventSender.mouseDown();
+eventSender.mouseUp();
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close-expected.txt
new file mode 100644
index 0000000..ba4d5497
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close-expected.txt
@@ -0,0 +1,2 @@
+CONSOLE ERROR: line 4: The XSS Auditor refused to execute a script in 'http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=%3Cscript%3Ealert(1)%3C/script&clutter=%20' because its source code was found within the request. The server sent an 'X-XSS-Protection' header requesting this behavior.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close.html b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close.html
new file mode 100644
index 0000000..ee0468d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/xssAuditor/script-tag-with-partial-close.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.setXSSAuditorEnabled(true);
+}
+</script>
+</head>
+<body>
+<iframe src="http://localhost:8000/security/xssAuditor/resources/echo-intertag.pl?q=<script>alert(1)</script&clutter=%20">
+</iframe>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
index 287712b..3e19260 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/debugger-setBlackboxPatterns-expected.txt
@@ -19,7 +19,7 @@
 baz:4
 (...):1
 Paused in
-qwe:6
+qwe:5
 baz:4
 (...):1
 Paused in
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
index 10cc9e4..e4a3e75 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/debugger/stepping-with-blackboxed-ranges-expected.txt
@@ -47,7 +47,7 @@
 
 action: stepOver
 action: stepInto
-foo: 16:0
+foo: 15:15
 blackboxedBoo: 3:12
 notBlackboxedFoo: 3:12
 blackboxedFoo: 10:12
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
index 16d03a1..cbb3951 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-breakpoints/possible-breakpoints-expected.txt
@@ -13,7 +13,7 @@
 location(3, 2)
 location(3, 10)
 location(4, 2)
-location(5, 0)
+location(4, 9)
 Existing location by position
 location(2, 31)
 Not existing location by position
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-sourcemap-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-sourcemap-expected.txt
index 32425602c..8ab04c2 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-sourcemap-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-sourcemap-expected.txt
@@ -19,7 +19,7 @@
 
 Executing StepOut...
 Call stack:
-    0) testFunction (frameworks-sourcemap.html:12)
+    0) testFunction (frameworks-sourcemap.html:11)
     [setTimeout]
     0) scheduleTestFunction (debugger-test.js:3)
     <... skipped remaining frames ...>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
index a3fe614..0bfaed1 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-step-into-skips-setTimeout-expected.txt
@@ -28,7 +28,7 @@
 
 Executing StepInto...
 Call stack:
-    0) callback (frameworks-step-into-skips-setTimeout.html:21)
+    0) callback (frameworks-step-into-skips-setTimeout.html:20)
   * 1) Framework_scheduleUntilDone (framework.js:142)
     [setTimeout]
   * 0) Framework.schedule (framework.js:45)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
index 8dc8ec8..fbc82ef 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-into-inlined-scripts-expected.txt
@@ -7,7 +7,7 @@
 
 Executing StepInto...
 Call stack:
-    0) f1 (debugger-step-into-inlined-scripts.html:8)
+    0) f1 (debugger-step-into-inlined-scripts.html:7)
     1)  (debugger-step-into-inlined-scripts.html:9)
 
 Executing StepInto...
@@ -25,7 +25,7 @@
 
 Executing StepInto...
 Call stack:
-    0) f2 (debugger-step-into-inlined-scripts.html:16)
+    0) f2 (debugger-step-into-inlined-scripts.html:15)
     1)  (debugger-step-into-inlined-scripts.html:17)
 
 Executing StepInto...
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
index 2a44a8c..3688b4dd 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-over-inlined-scripts-expected.txt
@@ -7,7 +7,7 @@
 
 Executing StepOver...
 Call stack:
-    0) f1 (debugger-step-over-inlined-scripts.html:8)
+    0) f1 (debugger-step-over-inlined-scripts.html:7)
     1)  (debugger-step-over-inlined-scripts.html:9)
 
 Executing StepOver...
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-through-promises-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-through-promises-expected.txt
index c43938c..5fa68e0 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-through-promises-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-step/debugger-step-through-promises-expected.txt
@@ -30,7 +30,7 @@
 
 Executing StepOver...
 Call stack:
-    0) p2 (debugger-step-through-promises.html:18)
+    0) p2 (debugger-step-through-promises.html:17)
     [Promise.resolve]
     0) testFunction (debugger-step-through-promises.html:14)
     [setTimeout]
@@ -48,7 +48,7 @@
 
 Executing StepOver...
 Call stack:
-    0) p3 (debugger-step-through-promises.html:23)
+    0) p3 (debugger-step-through-promises.html:22)
     [Promise.resolve]
     0) testFunction (debugger-step-through-promises.html:19)
     [setTimeout]
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/debugger-return-value-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/debugger-return-value-expected.txt
index 05c46e9e..73f47c6 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/debugger-return-value-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/debugger-return-value-expected.txt
@@ -2,6 +2,6 @@
 
 Set timer for test function.
 Call stack:
-    0) testFunction (debugger-return-value.html:17)
+    0) testFunction (debugger-return-value.html:16)
        <return>: 10
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/live-edit-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/live-edit-expected.txt
index 0eb7a01..5c7fc3f3 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/live-edit-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/live-edit-expected.txt
@@ -35,6 +35,8 @@
 
 Running: testBreakpointsUpdated
 breakpoint at 3
+  inline breakpoint at (3, 4)
+  inline breakpoint at (3, 32) disabled
 
 Running: testNoCrashWhenLiveEditOnBreakpoint
 Script execution paused.
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt
index 9ed2e778..794f449 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-breakpoint-decorations-expected.txt
@@ -4,25 +4,41 @@
 Running: testAddRemoveBreakpoint
 Setting breakpoint
 breakpoint at 2
+  inline breakpoint at (2, 4)
+  inline breakpoint at (2, 13) disabled
 Toggle breakpoint
 
 Running: testTwoBreakpointsResolvedInOneLine
 Setting breakpoint
 breakpoint at 2 conditional
+  inline breakpoint at (2, 4)
+  inline breakpoint at (2, 13) disabled
 Toggle breakpoint
 
 Running: testDecorationInGutter
 Adding regular disabled breakpoint
 breakpoint at 2 disabled
+  inline breakpoint at (2, 4) disabled
+  inline breakpoint at (2, 13) disabled
 Adding conditional disabled breakpoint
 breakpoint at 2 disabled conditional
+  inline breakpoint at (2, 4) disabled
+  inline breakpoint at (2, 13) disabled
 Adding regular enabled breakpoint
 breakpoint at 2
+  inline breakpoint at (2, 4)
+  inline breakpoint at (2, 13) disabled
 Adding conditional enabled breakpoint
 breakpoint at 2 conditional
+  inline breakpoint at (2, 4)
+  inline breakpoint at (2, 13) disabled
 Disable breakpoints
 breakpoint at 2 disabled conditional
+  inline breakpoint at (2, 4) disabled
+  inline breakpoint at (2, 13) disabled
 Enable breakpoints
 breakpoint at 2 conditional
+  inline breakpoint at (2, 4)
+  inline breakpoint at (2, 13) disabled
 Remove breakpoints
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
index 41e13b8..3a35852 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/source-frame-inline-breakpoint-decorations-expected.txt
@@ -14,6 +14,8 @@
 Running: testAddRemoveBreakpointInLineWithOneLocation
 Setting breakpoint
 breakpoint at 5
+  inline breakpoint at (5, 4)
+  inline breakpoint at (5, 13) disabled
 Toggle breakpoint
 
 Running: clickByInlineBreakpoint
diff --git a/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/interface-objects-expected.txt b/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/interface-objects-expected.txt
deleted file mode 100644
index 231fddb2..0000000
--- a/third_party/WebKit/LayoutTests/platform/android/external/wpt/dom/interface-objects-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x584
diff --git a/third_party/WebKit/LayoutTests/platform/linux/bluetooth/idl/idl-BluetoothDevice-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/bluetooth/idl/idl-BluetoothDevice-expected.txt
new file mode 100644
index 0000000..73c8638c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/bluetooth/idl/idl-BluetoothDevice-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: line 169: Web Bluetooth is experimental on this platform. See https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/implementation-status.md
+This is a testharness.js-based test.
+FAIL BluetoothDevice IDL test Test bug: need to pass exception to assert_throws()
+PASS BluetoothDevice attributes. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/bluetooth/idl/idl-BluetoothDevice-expected.txt b/third_party/WebKit/LayoutTests/platform/win/bluetooth/idl/idl-BluetoothDevice-expected.txt
new file mode 100644
index 0000000..73c8638c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/bluetooth/idl/idl-BluetoothDevice-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE MESSAGE: line 169: Web Bluetooth is experimental on this platform. See https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/implementation-status.md
+This is a testharness.js-based test.
+FAIL BluetoothDevice IDL test Test bug: need to pass exception to assert_throws()
+PASS BluetoothDevice attributes. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/sensor/accelerometer.html b/third_party/WebKit/LayoutTests/sensor/accelerometer.html
index 0c89932..1acd08d 100644
--- a/third_party/WebKit/LayoutTests/sensor/accelerometer.html
+++ b/third_party/WebKit/LayoutTests/sensor/accelerometer.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script src="resources/generic-sensor-tests.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/sensor/ambient-light-sensor.html b/third_party/WebKit/LayoutTests/sensor/ambient-light-sensor.html
index caa3503..da3ddf5 100644
--- a/third_party/WebKit/LayoutTests/sensor/ambient-light-sensor.html
+++ b/third_party/WebKit/LayoutTests/sensor/ambient-light-sensor.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script src="resources/generic-sensor-tests.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/sensor/gyroscope.html b/third_party/WebKit/LayoutTests/sensor/gyroscope.html
index d0e1c72..15fdd03 100644
--- a/third_party/WebKit/LayoutTests/sensor/gyroscope.html
+++ b/third_party/WebKit/LayoutTests/sensor/gyroscope.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script src="resources/generic-sensor-tests.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/sensor/magnetometer.html b/third_party/WebKit/LayoutTests/sensor/magnetometer.html
index 61e6bfbb..2c05dbe 100644
--- a/third_party/WebKit/LayoutTests/sensor/magnetometer.html
+++ b/third_party/WebKit/LayoutTests/sensor/magnetometer.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script src="resources/generic-sensor-tests.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/sensor/mock-sensor.html b/third_party/WebKit/LayoutTests/sensor/mock-sensor.html
index 79683101..0383cfbc 100644
--- a/third_party/WebKit/LayoutTests/sensor/mock-sensor.html
+++ b/third_party/WebKit/LayoutTests/sensor/mock-sensor.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script>
 
@@ -11,4 +13,4 @@
   assert_true(sensor instanceof Object);
   assert_true(sensor.mockSensorProvider instanceof Object);
 }, 'Sensor Mojo bindings and mock interfaces are available to tests.')
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html b/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html
index 75c8e4a..0244ed7e 100644
--- a/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html
+++ b/third_party/WebKit/LayoutTests/sensor/orientation-sensor.html
@@ -2,6 +2,8 @@
 <script src="../resources/testharness.js"></script>
 <script src="../resources/testharnessreport.js"></script>
 <script src="../resources/mojo-helpers.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/services/device/public/interfaces/sensor_provider.mojom.js"></script>
 <script src="resources/sensor-helpers.js"></script>
 <script src="resources/generic-sensor-tests.js"></script>
 <script>
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
index 502316d..18853ee3 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
@@ -54,7 +54,7 @@
           .then(mockSensor => {
             return new Promise((resolve, reject) => {
               let wrapper = new CallbackWrapper(() => {
-                let configuration = mockSensor.active_sensor_configurations_[0];
+                let configuration = mockSensor.activeSensorConfigurations_[0];
                 assert_equals(configuration.frequency, 60);
                 sensorObject.stop();
                 assert_false(sensorObject.activated);
@@ -102,7 +102,7 @@
         .then(mockSensor => {
           return new Promise((resolve, reject) => {
             let wrapper = new CallbackWrapper(() => {
-              let configuration = mockSensor.active_sensor_configurations_[0];
+              let configuration = mockSensor.activeSensorConfigurations_[0];
               assert_equals(configuration.frequency, maxSupportedFrequency);
               sensorObject.stop();
               assert_false(sensorObject.activated);
@@ -126,7 +126,7 @@
         .then(mockSensor => {
           return new Promise((resolve, reject) => {
             let wrapper = new CallbackWrapper(() => {
-              let configuration = mockSensor.active_sensor_configurations_[0];
+              let configuration = mockSensor.activeSensorConfigurations_[0];
               assert_equals(configuration.frequency, minSupportedFrequency);
               sensorObject.stop();
               assert_false(sensorObject.activated);
@@ -379,12 +379,12 @@
               slowSensorNotifiedCounter++;
               if (slowSensorNotifiedCounter == 1) {
                   fastSensor.start();
-                  readingUpdatesCounter = mockSensor.reading_updates_count();
+                  readingUpdatesCounter = mockSensor.readingUpdatesCount();
               } else if (slowSensorNotifiedCounter == 2) {
                 // By the moment slow sensor (9 Hz) is notified for the
                 // next time, the fast sensor (30 Hz) has been notified
                 // for int(30/9) = 3 times.
-                let elapsedUpdates = mockSensor.reading_updates_count() - readingUpdatesCounter;
+                let elapsedUpdates = mockSensor.readingUpdatesCount() - readingUpdatesCounter;
                 // Approximation because 'slowSensor.onreading' is sometimes
                 // called before 'fastSensor.onreading', in this case
                 // 'fastSensorNotifiedCounter == elapsedUpdates - 1'.
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
index 0aca665d..ea7322c 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
@@ -1,374 +1,356 @@
 'use strict';
 
-// Wraps callback and calls reject_func if callback throws an error.
+// Wraps callback and calls rejectFunc if callback throws an error.
 class CallbackWrapper {
-  constructor(callback, reject_func) {
-    this.wrapper_func_ = (args) => {
+  constructor(callback, rejectFunc) {
+    this.wrapperFunc_ = (args) => {
       try {
         callback(args);
       } catch(e) {
-        reject_func(e);
+        rejectFunc(e);
       }
     }
   }
 
   get callback() {
-    return this.wrapper_func_;
+    return this.wrapperFunc_;
   }
 }
 
-function sensor_mocks(mojo) {
-  return define('Generic Sensor API mocks', [
-    'mojo/public/js/core',
-    'mojo/public/js/bindings',
-    'services/device/public/interfaces/sensor_provider.mojom',
-    'services/device/public/interfaces/sensor.mojom',
-    'services/device/public/interfaces/constants.mojom',
-  ], (core, bindings, sensor_provider, sensor, deviceConstants) => {
+function sensorMocks() {
+  // Helper function that returns resolved promise with result.
+  function sensorResponse(success) {
+    return Promise.resolve({success});
+  }
 
-    // Helper function that returns resolved promise with result.
-    function sensorResponse(success) {
-      return Promise.resolve({success});
+  // Class that mocks Sensor interface defined in sensor.mojom
+  class MockSensor {
+    constructor(sensorRequest, handle, offset, size, reportingMode) {
+      this.client_ = null;
+      this.startShouldFail_ = false;
+      this.reportingMode_ = reportingMode;
+      this.sensorReadingTimerId_ = null;
+      this.updateReadingFunction_ = null;
+      this.readingUpdatesCount_ = 0;
+      this.suspendCalled_ = null;
+      this.resumeCalled_ = null;
+      this.addConfigurationCalled_ = null;
+      this.removeConfigurationCalled_ = null;
+      this.activeSensorConfigurations_ = [];
+      let rv = handle.mapBuffer(offset, size);
+      assert_equals(rv.result, Mojo.RESULT_OK, "Failed to map shared buffer");
+      this.bufferArray_ = rv.buffer;
+      this.buffer_ = new Float64Array(this.bufferArray_);
+      this.resetBuffer();
+      this.binding_ = new mojo.Binding(device.mojom.Sensor, this,
+                                       sensorRequest);
+      this.binding_.setConnectionErrorHandler(() => {
+        this.reset();
+      });
     }
 
-    // Class that mocks Sensor interface defined in sensor.mojom
-    class MockSensor {
-      constructor(sensorRequest, handle, offset, size, reportingMode) {
-        this.client_ = null;
-        this.start_should_fail_ = false;
-        this.reporting_mode_ = reportingMode;
-        this.sensor_reading_timer_id_ = null;
-        this.update_reading_function_ = null;
-        this.reading_updates_count_ = 0;
-        this.suspend_called_ = null;
-        this.resume_called_ = null;
-        this.add_configuration_called_ = null;
-        this.remove_configuration_called_ = null;
-        this.active_sensor_configurations_ = [];
-        let rv = core.mapBuffer(handle, offset, size,
-            core.MAP_BUFFER_FLAG_NONE);
-        assert_equals(rv.result, core.RESULT_OK, "Failed to map shared buffer");
-        this.buffer_array_ = rv.buffer;
-        this.buffer_ = new Float64Array(this.buffer_array_);
-        this.resetBuffer();
-        this.binding_ = new bindings.Binding(sensor.Sensor, this,
-                                             sensorRequest);
-        this.binding_.setConnectionErrorHandler(() => {
-          this.reset();
-        });
-      }
+    // Returns default configuration.
+    getDefaultConfiguration() {
+      return Promise.resolve({frequency: 5});
+    }
 
-      // Returns default configuration.
-      getDefaultConfiguration() {
-        return Promise.resolve({frequency: 5});
-      }
+    readingUpdatesCount() {
+      return this.readingUpdatesCount_;
+    }
+    // Adds configuration for the sensor and starts reporting fake data
+    // through updateReadingFunction_ callback.
+    addConfiguration(configuration) {
+      assert_not_equals(configuration, null, "Invalid sensor configuration.");
 
-      reading_updates_count() {
-        return this.reading_updates_count_;
-      }
-      // Adds configuration for the sensor and starts reporting fake data
-      // through update_reading_function_ callback.
-      addConfiguration(configuration) {
-        assert_not_equals(configuration, null, "Invalid sensor configuration.");
+      this.activeSensorConfigurations_.push(configuration);
+      // Sort using descending order.
+      this.activeSensorConfigurations_.sort(
+          (first, second) => { return second.frequency - first.frequency });
 
-        this.active_sensor_configurations_.push(configuration);
-        // Sort using descending order.
-        this.active_sensor_configurations_.sort(
-            (first, second) => { return second.frequency - first.frequency });
-
-        if (!this.start_should_fail_ )
-          this.startReading();
-
-        if (this.add_configuration_called_ != null)
-          this.add_configuration_called_(this);
-
-        return sensorResponse(!this.start_should_fail_);
-      }
-
-      // Removes sensor configuration from the list of active configurations and
-      // stops notification about sensor reading changes if
-      // active_sensor_configurations_ is empty.
-      removeConfiguration(configuration) {
-        if (this.remove_configuration_called_ != null) {
-          this.remove_configuration_called_(this);
-        }
-
-        let index = this.active_sensor_configurations_.indexOf(configuration);
-        if (index !== -1) {
-          this.active_sensor_configurations_.splice(index, 1);
-        } else {
-          return sensorResponse(false);
-        }
-
-        if (this.active_sensor_configurations_.length === 0)
-          this.stopReading();
-
-        return sensorResponse(true);
-      }
-
-      // Suspends sensor.
-      suspend() {
-        this.stopReading();
-        if (this.suspend_called_ != null) {
-          this.suspend_called_(this);
-        }
-      }
-
-      // Resumes sensor.
-      resume() {
-        assert_equals(this.sensor_reading_timer_id_, null);
+      if (!this.startShouldFail_ )
         this.startReading();
-        if (this.resume_called_ != null) {
-          this.resume_called_(this);
-        }
+
+      if (this.addConfigurationCalled_ != null)
+        this.addConfigurationCalled_(this);
+
+      return sensorResponse(!this.startShouldFail_);
+    }
+
+    // Removes sensor configuration from the list of active configurations and
+    // stops notification about sensor reading changes if
+    // activeSensorConfigurations_ is empty.
+    removeConfiguration(configuration) {
+      if (this.removeConfigurationCalled_ != null) {
+        this.removeConfigurationCalled_(this);
       }
 
-      // Mock functions
+      let index = this.activeSensorConfigurations_.indexOf(configuration);
+      if (index !== -1) {
+        this.activeSensorConfigurations_.splice(index, 1);
+      } else {
+        return sensorResponse(false);
+      }
 
-      // Resets mock Sensor state.
-      reset() {
+      if (this.activeSensorConfigurations_.length === 0)
         this.stopReading();
 
-        this.reading_updates_count_ = 0;
-        this.start_should_fail_ = false;
-        this.update_reading_function_ = null;
-        this.active_sensor_configurations_ = [];
-        this.suspend_called_ = null;
-        this.resume_called_ = null;
-        this.add_configuration_called_ = null;
-        this.remove_configuration_called_ = null;
-        this.resetBuffer();
-        core.unmapBuffer(this.buffer_array_);
-        this.buffer_array_ = null;
-        this.binding_.close();
-      }
-
-      // Zeroes shared buffer.
-      resetBuffer() {
-        for (let i = 0; i < this.buffer_.length; ++i) {
-          this.buffer_[i] = 0;
-        }
-      }
-
-      // Sets callback that is used to deliver sensor reading updates.
-      setUpdateSensorReadingFunction(update_reading_function) {
-        this.update_reading_function_ = update_reading_function;
-        return Promise.resolve(this);
-      }
-
-      // Sets flag that forces sensor to fail when addConfiguration is invoked.
-      setStartShouldFail(should_fail) {
-        this.start_should_fail_ = should_fail;
-      }
-
-      // Returns resolved promise if suspend() was called, rejected otherwise.
-      suspendCalled() {
-        return new Promise((resolve, reject) => {
-          this.suspend_called_ = resolve;
-        });
-      }
-
-      // Returns resolved promise if resume() was called, rejected otherwise.
-      resumeCalled() {
-        return new Promise((resolve, reject) => {
-          this.resume_called_ = resolve;
-        });
-      }
-
-      // Resolves promise when addConfiguration() is called.
-      addConfigurationCalled() {
-        return new Promise((resolve, reject) => {
-          this.add_configuration_called_ = resolve;
-        });
-      }
-
-      // Resolves promise when removeConfiguration() is called.
-      removeConfigurationCalled() {
-        return new Promise((resolve, reject) => {
-          this.remove_configuration_called_ = resolve;
-        });
-      }
-
-      startReading() {
-        if (this.update_reading_function_ != null) {
-          this.stopReading();
-          let max_frequency_used =
-              this.active_sensor_configurations_[0].frequency;
-          let timeout = (1 / max_frequency_used) * 1000;
-          this.sensor_reading_timer_id_ = window.setInterval(() => {
-            if (this.update_reading_function_) {
-              this.update_reading_function_(this.buffer_);
-              // For all tests sensor reading should have monotonically
-              // increasing timestamp in seconds.
-              this.buffer_[1] = window.performance.now() * 0.001;
-              this.reading_updates_count_++;
-            }
-            if (this.reporting_mode_ === sensor.ReportingMode.ON_CHANGE) {
-              this.client_.sensorReadingChanged();
-            }
-          }, timeout);
-        }
-      }
-
-      stopReading() {
-        if (this.sensor_reading_timer_id_ != null) {
-          window.clearInterval(this.sensor_reading_timer_id_);
-          this.sensor_reading_timer_id_ = null;
-        }
-      }
-
+      return sensorResponse(true);
     }
 
-    // Helper function that returns resolved promise for getSensor() function.
-    function getSensorResponse(init_params, client_request) {
-      return Promise.resolve({init_params, client_request});
-    }
-
-    // Class that mocks SensorProvider interface defined in
-    // sensor_provider.mojom
-    class MockSensorProvider {
-      constructor() {
-        this.reading_size_in_bytes_ =
-            sensor_provider.SensorInitParams.kReadBufferSizeForTests;
-        this.shared_buffer_size_in_bytes_ = this.reading_size_in_bytes_ *
-                sensor.SensorType.LAST;
-        let rv =
-                core.createSharedBuffer(
-                        this.shared_buffer_size_in_bytes_,
-                        core.CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE);
-        assert_equals(rv.result, core.RESULT_OK, "Failed to create buffer");
-        this.shared_buffer_handle_ = rv.handle;
-        this.active_sensor_ = null;
-        this.get_sensor_should_fail_ = false;
-        this.resolve_func_ = null;
-        this.is_continuous_ = false;
-        this.max_frequency_ = 60;
-        this.min_frequency_ = 1;
-        this.binding_ = new bindings.Binding(sensor_provider.SensorProvider,
-                                             this);
-      }
-
-      // Returns initialized Sensor proxy to the client.
-      getSensor(type, request) {
-        if (this.get_sensor_should_fail_) {
-          var ignored = new sensor.SensorClientPtr();
-          return getSensorResponse(null, bindings.makeRequest(ignored));
-        }
-
-        let offset =
-                (sensor.SensorType.LAST - type) * this.reading_size_in_bytes_;
-        let reporting_mode = sensor.ReportingMode.ON_CHANGE;
-        if (this.is_continuous_) {
-            reporting_mode = sensor.ReportingMode.CONTINUOUS;
-        }
-
-        if (this.active_sensor_ == null) {
-          let mockSensor = new MockSensor(request, this.shared_buffer_handle_,
-              offset, this.reading_size_in_bytes_, reporting_mode);
-          this.active_sensor_ = mockSensor;
-        }
-
-        let rv =
-                core.duplicateBufferHandle(
-                        this.shared_buffer_handle_,
-                        core.DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE);
-
-        assert_equals(rv.result, core.RESULT_OK);
-
-        let default_config = {frequency: 5};
-
-        let init_params =
-            new sensor_provider.SensorInitParams(
-                { memory: rv.handle,
-                  buffer_offset: offset,
-                  mode: reporting_mode,
-                  default_configuration: default_config,
-                  minimum_frequency: this.min_frequency_,
-                  maximum_frequency: this.max_frequency_});
-
-        if (this.resolve_func_ !== null) {
-          this.resolve_func_(this.active_sensor_);
-        }
-
-        this.active_sensor_.client_ = new sensor.SensorClientPtr();
-        return getSensorResponse(
-            init_params, bindings.makeRequest(this.active_sensor_.client_));
-      }
-
-      // Binds object to mojo message pipe
-      bindToPipe(pipe) {
-        this.binding_.bind(pipe);
-        this.binding_.setConnectionErrorHandler(() => {
-          this.reset();
-        });
-      }
-
-      // Mock functions
-
-      // Resets state of mock SensorProvider between test runs.
-      reset() {
-        if (this.active_sensor_ != null) {
-          this.active_sensor_.reset();
-          this.active_sensor_ = null;
-        }
-
-        this.get_sensor_should_fail_ = false;
-        this.resolve_func_ = null;
-        this.max_frequency_ = 60;
-        this.min_frequency_ = 1;
-        this.is_continuous_ = false;
-        this.binding_.close();
-      }
-
-      // Sets flag that forces mock SensorProvider to fail when getSensor() is
-      // invoked.
-      setGetSensorShouldFail(should_fail) {
-        this.get_sensor_should_fail_ = should_fail;
-      }
-
-      // Returns mock sensor that was created in getSensor to the layout test.
-      getCreatedSensor() {
-        if (this.active_sensor_ != null) {
-          return Promise.resolve(this.active_sensor_);
-        }
-
-        return new Promise((resolve, reject) => {
-          this.resolve_func_ = resolve;
-         });
-      }
-
-      // Forces sensor to use |reporting_mode| as an update mode.
-      setContinuousReportingMode() {
-          this.is_continuous_ = true;
-      }
-
-      // Sets the maximum frequency for a concrete sensor.
-      setMaximumSupportedFrequency(frequency) {
-          this.max_frequency_ = frequency;
-      }
-
-      // Sets the minimum frequency for a concrete sensor.
-      setMinimumSupportedFrequency(frequency) {
-          this.min_frequency_ = frequency;
+    // Suspends sensor.
+    suspend() {
+      this.stopReading();
+      if (this.suspendCalled_ != null) {
+        this.suspendCalled_(this);
       }
     }
 
-    let mockSensorProvider = new MockSensorProvider;
-    mojo.connector.addInterfaceOverrideForTesting(
-        deviceConstants.kServiceName,
-        sensor_provider.SensorProvider.name,
-        pipe => {
-          mockSensorProvider.bindToPipe(pipe);
-        });
+    // Resumes sensor.
+    resume() {
+      assert_equals(this.sensorReadingTimerId_, null);
+      this.startReading();
+      if (this.resumeCalled_ != null) {
+        this.resumeCalled_(this);
+      }
+    }
 
-    return Promise.resolve({
-      mockSensorProvider: mockSensorProvider,
-    });
-  });
+    // Mock functions
+
+    // Resets mock Sensor state.
+    reset() {
+      this.stopReading();
+
+      this.readingUpdatesCount_ = 0;
+      this.startShouldFail_ = false;
+      this.updateReadingFunction_ = null;
+      this.activeSensorConfigurations_ = [];
+      this.suspendCalled_ = null;
+      this.resumeCalled_ = null;
+      this.addConfigurationCalled_ = null;
+      this.removeConfigurationCalled_ = null;
+      this.resetBuffer();
+      this.bufferArray_ = null;
+      this.binding_.close();
+    }
+
+    // Zeroes shared buffer.
+    resetBuffer() {
+      for (let i = 0; i < this.buffer_.length; ++i) {
+        this.buffer_[i] = 0;
+      }
+    }
+
+    // Sets callback that is used to deliver sensor reading updates.
+    setUpdateSensorReadingFunction(updateReadingFunction) {
+      this.updateReadingFunction_ = updateReadingFunction;
+      return Promise.resolve(this);
+    }
+
+    // Sets flag that forces sensor to fail when addConfiguration is invoked.
+    setStartShouldFail(shouldFail) {
+      this.startShouldFail_ = shouldFail;
+    }
+
+    // Returns resolved promise if suspend() was called, rejected otherwise.
+    suspendCalled() {
+      return new Promise((resolve, reject) => {
+        this.suspendCalled_ = resolve;
+      });
+    }
+
+    // Returns resolved promise if resume() was called, rejected otherwise.
+    resumeCalled() {
+      return new Promise((resolve, reject) => {
+        this.resumeCalled_ = resolve;
+      });
+    }
+
+    // Resolves promise when addConfiguration() is called.
+    addConfigurationCalled() {
+      return new Promise((resolve, reject) => {
+        this.addConfigurationCalled_ = resolve;
+      });
+    }
+
+    // Resolves promise when removeConfiguration() is called.
+    removeConfigurationCalled() {
+      return new Promise((resolve, reject) => {
+        this.removeConfigurationCalled_ = resolve;
+      });
+    }
+
+    startReading() {
+      if (this.updateReadingFunction_ != null) {
+        this.stopReading();
+        let maxFrequencyUsed = this.activeSensorConfigurations_[0].frequency;
+        let timeout = (1 / maxFrequencyUsed) * 1000;
+        this.sensorReadingTimerId_ = window.setInterval(() => {
+          if (this.updateReadingFunction_) {
+            this.updateReadingFunction_(this.buffer_);
+            // For all tests sensor reading should have monotonically
+            // increasing timestamp in seconds.
+            this.buffer_[1] = window.performance.now() * 0.001;
+            this.readingUpdatesCount_++;
+          }
+          if (this.reportingMode_ === device.mojom.ReportingMode.ON_CHANGE) {
+            this.client_.sensorReadingChanged();
+          }
+        }, timeout);
+      }
+    }
+
+    stopReading() {
+      if (this.sensorReadingTimerId_ != null) {
+        window.clearInterval(this.sensorReadingTimerId_);
+        this.sensorReadingTimerId_ = null;
+      }
+    }
+
+  }
+
+  // Helper function that returns resolved promise for getSensor() function.
+  function getSensorResponse(initParams, clientRequest) {
+    return Promise.resolve({initParams, clientRequest});
+  }
+
+  // Class that mocks SensorProvider interface defined in
+  // sensor_provider.mojom
+  class MockSensorProvider {
+    constructor() {
+      this.readingSizeInBytes_ =
+          device.mojom.SensorInitParams.kReadBufferSizeForTests;
+      this.sharedBufferSizeInBytes_ = this.readingSizeInBytes_ *
+              device.mojom.SensorType.LAST;
+      let rv = Mojo.createSharedBuffer(this.sharedBufferSizeInBytes_);
+      assert_equals(rv.result, Mojo.RESULT_OK, "Failed to create buffer");
+      this.sharedBufferHandle_ = rv.handle;
+      this.activeSensor_ = null;
+      this.getSensorShouldFail_ = false;
+      this.resolveFunc_ = null;
+      this.isContinuous_ = false;
+      this.maxFrequency_ = 60;
+      this.minFrequency_ = 1;
+      this.binding_ = new mojo.Binding(device.mojom.SensorProvider, this);
+
+      this.interceptor_ = new MojoInterfaceInterceptor(
+          device.mojom.SensorProvider.name);
+      this.interceptor_.oninterfacerequest = e => {
+        this.bindToPipe(e.handle);
+      };
+      this.interceptor_.start();
+    }
+
+    // Returns initialized Sensor proxy to the client.
+    getSensor(type, request) {
+      if (this.getSensorShouldFail_) {
+        var ignored = new device.mojom.SensorClientPtr();
+        return getSensorResponse(null, mojo.makeRequest(ignored));
+      }
+
+      let offset = (device.mojom.SensorType.LAST - type) *
+          this.readingSizeInBytes_;
+      let reportingMode = device.mojom.ReportingMode.ON_CHANGE;
+      if (this.isContinuous_) {
+        reportingMode = device.mojom.ReportingMode.CONTINUOUS;
+      }
+
+      if (this.activeSensor_ == null) {
+        let mockSensor = new MockSensor(request, this.sharedBufferHandle_,
+            offset, this.readingSizeInBytes_, reportingMode);
+        this.activeSensor_ = mockSensor;
+      }
+
+      let rv = this.sharedBufferHandle_.duplicateBufferHandle();
+
+      assert_equals(rv.result, Mojo.RESULT_OK);
+
+      let defaultConfig = {frequency: 5};
+
+      let initParams =
+          new device.mojom.SensorInitParams(
+              { memory: rv.handle,
+                bufferOffset: offset,
+                mode: reportingMode,
+                defaultConfiguration: defaultConfig,
+                minimumFrequency: this.minFrequency_,
+                maximumFrequency: this.maxFrequency_});
+
+      if (this.resolveFunc_ !== null) {
+        this.resolveFunc_(this.activeSensor_);
+      }
+
+      this.activeSensor_.client_ = new device.mojom.SensorClientPtr();
+      return getSensorResponse(
+          initParams, mojo.makeRequest(this.activeSensor_.client_));
+    }
+
+    // Binds object to mojo message pipe
+    bindToPipe(pipe) {
+      this.binding_.bind(pipe);
+      this.binding_.setConnectionErrorHandler(() => {
+        this.reset();
+      });
+    }
+
+    // Mock functions
+
+    // Resets state of mock SensorProvider between test runs.
+    reset() {
+      if (this.activeSensor_ != null) {
+        this.activeSensor_.reset();
+        this.activeSensor_ = null;
+      }
+
+      this.getSensorShouldFail_ = false;
+      this.resolveFunc_ = null;
+      this.maxFrequency_ = 60;
+      this.minFrequency_ = 1;
+      this.isContinuous_ = false;
+      this.binding_.close();
+      this.interceptor_.stop();
+    }
+
+    // Sets flag that forces mock SensorProvider to fail when getSensor() is
+    // invoked.
+    setGetSensorShouldFail(shouldFail) {
+      this.getSensorShouldFail_ = shouldFail;
+    }
+
+    // Returns mock sensor that was created in getSensor to the layout test.
+    getCreatedSensor() {
+      if (this.activeSensor_ != null) {
+        return Promise.resolve(this.activeSensor_);
+      }
+
+      return new Promise((resolve, reject) => {
+        this.resolveFunc_ = resolve;
+      });
+    }
+
+    // Forces sensor to use |reportingMode| as an update mode.
+    setContinuousReportingMode() {
+      this.isContinuous_ = true;
+    }
+
+    // Sets the maximum frequency for a concrete sensor.
+    setMaximumSupportedFrequency(frequency) {
+      this.maxFrequency_ = frequency;
+    }
+
+    // Sets the minimum frequency for a concrete sensor.
+    setMinimumSupportedFrequency(frequency) {
+      this.minFrequency_ = frequency;
+    }
+  }
+
+  let mockSensorProvider = new MockSensorProvider;
+  return {mockSensorProvider: mockSensorProvider};
 }
 
 function sensor_test(func, name, properties) {
-  mojo_test(mojo => sensor_mocks(mojo).then(sensor => {
+  mojo_test(() => {
+    let sensor = sensorMocks();
+
     // Clean up and reset mock sensor stubs asynchronously, so that the blink
     // side closes its proxies and notifies JS sensor objects before new test is
     // started.
@@ -383,5 +365,5 @@
     };
 
     return Promise.resolve(func(sensor)).then(onSuccess, onFailure);
-  }), name, properties);
+  }, name, properties);
 }
diff --git a/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp b/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
index c3fb7f9..d9c41486 100644
--- a/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
+++ b/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp
@@ -135,6 +135,15 @@
                                 script);
 }
 
+static bool StartsClosingScriptTagAt(const String& string, size_t start) {
+  if (start + 7 >= string.length())
+    return false;
+  // TODO(esprehn): StringView should probably have startsWith.
+  StringView script("</script");
+  return EqualIgnoringASCIICase(StringView(string, start, script.length()),
+                                script);
+}
+
 // If other files need this, we should move this to
 // core/html/parser/HTMLParserIdioms.h
 template <size_t inlineCapacity>
@@ -880,7 +889,8 @@
         break;
 
       if (last_non_space_position != kNotFound &&
-          StartsOpeningScriptTagAt(string, found_position)) {
+          (StartsOpeningScriptTagAt(string, found_position) ||
+           StartsClosingScriptTagAt(string, found_position))) {
         found_position = last_non_space_position + 1;
         break;
       }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 025d62c..1c653af 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -502,6 +502,16 @@
     SetChildrenInline(true);
   SetContainsInlineWithOutlineAndContinuation(false);
 
+  // Text truncation kicks in if overflow isn't visible and text-overflow isn't
+  // 'clip'. If this is an anonymous block, we have to examine the parent.
+  // FIXME: CSS3 says that descendants that are clipped must also know how to
+  // truncate. This is insanely difficult to figure out in general (especially
+  // in the middle of doing layout), so we only handle the simple case of an
+  // anonymous block truncating when its parent is clipped.
+  // Walk all the lines and delete our ellipsis line boxes if they exist.
+  if (ChildrenInline() && ShouldTruncateOverflowingText(this))
+    DeleteEllipsisLineBoxes();
+
   RebuildFloatsFromIntruding();
 
   // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 90683dda..8a0e092 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -877,6 +877,8 @@
   bool IsSelfCollapsingBlock() const override;
   bool CheckIfIsSelfCollapsingBlock() const;
 
+  bool ShouldTruncateOverflowingText(const LayoutBlockFlow*) const;
+
  protected:
   std::unique_ptr<LayoutBlockFlowRareData> rare_data_;
   std::unique_ptr<FloatingObjects> floating_objects_;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
index 694df3c..1380f19d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -1914,7 +1914,7 @@
          !o.IsElementContinuation() && ToLayoutInline(o).Continuation();
 }
 
-static inline bool ShouldTruncateOverflowingText(const LayoutBlockFlow* block) {
+bool LayoutBlockFlow::ShouldTruncateOverflowingText(const LayoutBlockFlow* block) const {
   const LayoutObject* object_to_check = block;
   if (block->IsAnonymousBlock()) {
     const LayoutObject* parent = block->Parent();
@@ -1947,18 +1947,6 @@
       layout_state.SetNeedsPaginationStrutRecalculation();
   }
 
-  // Text truncation kicks in if overflow isn't visible and text-overflow isn't
-  // 'clip'. If this is an anonymous block, we have to examine the parent.
-  // FIXME: CSS3 says that descendants that are clipped must also know how to
-  // truncate. This is insanely difficult to figure out in general (especially
-  // in the middle of doing layout), so we only handle the simple case of an
-  // anonymous block truncating when its parent is clipped.
-  bool has_text_overflow = ShouldTruncateOverflowingText(this);
-
-  // Walk all the lines and delete our ellipsis line boxes if they exist.
-  if (has_text_overflow)
-    DeleteEllipsisLineBoxes();
-
   if (FirstChild()) {
     for (InlineWalker walker(LineLayoutBlockFlow(this)); !walker.AtEnd();
          walker.Advance()) {
@@ -2035,9 +2023,7 @@
                    IsHorizontalWritingMode() ? kHorizontalLine : kVerticalLine,
                    kPositionOfInteriorLineBoxes));
 
-  // See if we have any lines that spill out of our block.  If we do, then we
-  // will possibly need to truncate text.
-  if (has_text_overflow)
+  if (ShouldTruncateOverflowingText(this))
     CheckLinesForTextOverflow();
 
   // Ensure the new line boxes will be painted.
diff --git a/third_party/WebKit/Source/core/layout/LayoutListItem.cpp b/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
index 3271727..92af3053 100644
--- a/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
@@ -228,7 +228,7 @@
   // FIXME: This recurses to a possible depth of the length of the list.
   // That's not good -- we need to change this to an iterative algorithm.
   if (LayoutListItem* previous_item = PreviousListItem(list, this))
-    return SaturatedAddition(previous_item->Value(), value_step);
+    return ClampAdd(previous_item->Value(), value_step);
 
   if (o_list_element)
     return o_list_element->start();
diff --git a/third_party/WebKit/Source/core/loader/NetworkQuietDetector.cpp b/third_party/WebKit/Source/core/loader/NetworkQuietDetector.cpp
index 3504d07..9c98ce0 100644
--- a/third_party/WebKit/Source/core/loader/NetworkQuietDetector.cpp
+++ b/third_party/WebKit/Source/core/loader/NetworkQuietDetector.cpp
@@ -73,8 +73,8 @@
     auto frame_resource_coordinator =
         GetSupplementable()->GetFrame()->GetFrameResourceCoordinator();
     if (frame_resource_coordinator) {
-      frame_resource_coordinator->SendEvent(
-          resource_coordinator::mojom::EventType::kOnLocalFrameNetworkIdle);
+      frame_resource_coordinator->SetProperty(
+          resource_coordinator::mojom::PropertyType::kNetworkIdle, true);
     }
   }
 
diff --git a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
index 7367e716..b8053383 100644
--- a/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
+++ b/third_party/WebKit/Source/core/paint/NinePieceImageGrid.cpp
@@ -62,10 +62,8 @@
   // as its height, and Wside as the border image width offset for the side, let
   // f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbottom)). If f < 1, then all
   // W are reduced by multiplying them by f.
-  int border_side_width =
-      std::max(1, SaturatedAddition(left_.width, right_.width));
-  int border_side_height =
-      std::max(1, SaturatedAddition(top_.width, bottom_.width));
+  int border_side_width = ClampAdd(left_.width, right_.width).Max(1);
+  int border_side_height = ClampAdd(top_.width, bottom_.width).Max(1);
   float border_side_scale_factor =
       std::min((float)border_image_area.Width() / border_side_width,
                (float)border_image_area.Height() / border_side_height);
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index f77bb4c..4c8ba37f 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -1898,7 +1898,7 @@
     return GraphicsContext::FocusRingOutsetExtent(
         OutlineOffset(), std::ceil(GetOutlineStrokeWidthForFocusRing()));
   }
-  return std::max(0, SaturatedAddition(OutlineWidth(), OutlineOffset()));
+  return ClampAdd(OutlineWidth(), OutlineOffset()).Max(0);
 }
 
 float ComputedStyle::GetOutlineStrokeWidthForFocusRing() const {
diff --git a/third_party/WebKit/Source/core/timing/Performance.cpp b/third_party/WebKit/Source/core/timing/Performance.cpp
index e32c306..2520de2 100644
--- a/third_party/WebKit/Source/core/timing/Performance.cpp
+++ b/third_party/WebKit/Source/core/timing/Performance.cpp
@@ -46,7 +46,7 @@
 #include "platform/loader/fetch/ResourceTimingInfo.h"
 #include "platform/RuntimeEnabledFeatures.h"
 
-static const double kLongTaskThreshold = 0.05;
+static const double kLongTaskObserverThreshold = 0.05;
 
 static const char kUnknownAttribution[] = "unknown";
 static const char kAmbiguousAttribution[] = "multiple-contexts";
@@ -162,7 +162,7 @@
     UseCounter::Count(&GetFrame()->LocalFrameRoot(),
                       WebFeature::kLongTaskObserver);
     GetFrame()->GetPerformanceMonitor()->Subscribe(
-        PerformanceMonitor::kLongTask, kLongTaskThreshold, this);
+        PerformanceMonitor::kLongTask, kLongTaskObserverThreshold, this);
   } else {
     GetFrame()->GetPerformanceMonitor()->UnsubscribeAll(this);
   }
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
index 87ae80d..34e8a1e 100644
--- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.cpp
@@ -81,6 +81,8 @@
   ThreadableLoaderOptions options;
 
   ResourceLoaderOptions resource_loader_options;
+  resource_loader_options.parser_disposition =
+      ParserDisposition::kNotParserInserted;
 
   WorkerThreadableLoader::LoadResourceSynchronously(
       ToWorkerGlobalScope(execution_context), request, *this, options,
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index d7dce91e0..f48a3ba0 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -248,6 +248,8 @@
     if (!executionContext)
       return Promise.resolve();
 
+    // Evaluate location.href for a more specific URL than inspectedURL provides so that SPA hash navigation routes
+    // will be respected and audited.
     return new Promise(resolve => {
       executionContext.evaluate('window.location.href', 'audits', false, false, true, false, false, (object, err) => {
         if (!err && object) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
index 4da1164..9081df8 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/RuntimeModel.js
@@ -113,7 +113,7 @@
    * @return {?SDK.ExecutionContext}
    */
   defaultExecutionContext() {
-    for (var context of this._executionContextById.values()) {
+    for (var context of this.executionContexts()) {
       if (context.isDefault)
         return context;
     }
diff --git a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
index dd2ba69..e576aa0 100644
--- a/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/Bluetooth.cpp
@@ -9,12 +9,14 @@
 #include "bindings/core/v8/CallbackPromiseAdapter.h"
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "build/build_config.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
 #include "core/dom/UserGestureIndicator.h"
 #include "core/frame/LocalFrame.h"
+#include "core/inspector/ConsoleMessage.h"
 #include "modules/bluetooth/BluetoothDevice.h"
 #include "modules/bluetooth/BluetoothError.h"
 #include "modules/bluetooth/BluetoothRemoteGATTCharacteristic.h"
@@ -153,6 +155,15 @@
                                        ExceptionState& exception_state) {
   ExecutionContext* context = ExecutionContext::From(script_state);
 
+// Remind developers when they are using Web Bluetooth on unsupported platforms.
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_MACOSX)
+  context->AddConsoleMessage(ConsoleMessage::Create(
+      kJSMessageSource, kInfoMessageLevel,
+      "Web Bluetooth is experimental on this platform. See "
+      "https://github.com/WebBluetoothCG/web-bluetooth/blob/gh-pages/"
+      "implementation-status.md"));
+#endif
+
   // If the Relevant settings object is not a secure context, reject promise
   // with a SecurityError and abort these steps.
   String error_message;
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
index 3e8d3300..5b9bc61 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
@@ -366,7 +366,7 @@
   // initializeNewSession() is called in response to the user calling
   // generateRequest().
   WebContentDecryptionModule* cdm = media_keys->ContentDecryptionModule();
-  session_ = WTF::WrapUnique(cdm->CreateSession());
+  session_ = cdm->CreateSession();
   session_->SetClientInterface(this);
 
   // From https://w3c.github.io/encrypted-media/#createSession:
diff --git a/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.h b/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.h
index cd4e2eac..77843fa 100644
--- a/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.h
+++ b/third_party/WebKit/Source/modules/gamepad/NavigatorGamepad.h
@@ -30,7 +30,6 @@
 #include "core/frame/LocalDOMWindow.h"
 #include "core/frame/Navigator.h"
 #include "core/frame/PlatformEventController.h"
-#include "device/gamepad/public/cpp/gamepads.h"
 #include "modules/ModulesExport.h"
 #include "platform/AsyncMethodRunner.h"
 #include "platform/Supplementable.h"
@@ -61,10 +60,6 @@
 
   DECLARE_VIRTUAL_TRACE();
 
-  void DidConnectOrDisconnectGamepad(unsigned index,
-                                     const device::Gamepad&,
-                                     bool connected);
-
  private:
   explicit NavigatorGamepad(Navigator&);
 
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProviderProxy.cpp b/third_party/WebKit/Source/modules/sensor/SensorProviderProxy.cpp
index 408e833..3a7663a 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorProviderProxy.cpp
+++ b/third_party/WebKit/Source/modules/sensor/SensorProviderProxy.cpp
@@ -6,9 +6,8 @@
 
 #include "modules/sensor/SensorProxy.h"
 #include "platform/mojo/MojoHelper.h"
-#include "public/platform/Platform.h"
 #include "services/device/public/interfaces/constants.mojom-blink.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 
 namespace blink {
 
@@ -20,8 +19,8 @@
   if (IsInitialized())
     return;
 
-  Platform::Current()->GetConnector()->BindInterface(
-      device::mojom::blink::kServiceName, mojo::MakeRequest(&sensor_provider_));
+  GetSupplementable()->GetInterfaceProvider().GetInterface(
+      mojo::MakeRequest(&sensor_provider_));
   sensor_provider_.set_connection_error_handler(ConvertToBaseCallback(
       WTF::Bind(&SensorProviderProxy::OnSensorProviderConnectionError,
                 WrapWeakPersistent(this))));
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
index c1ddf208..1d8fb80 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
+++ b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
@@ -114,14 +114,11 @@
 
 void SensorProxy::UpdateSensorReading() {
   DCHECK(ShouldProcessReadings());
-  int read_attempts = 0;
-  const int kMaxReadAttemptsCount = 10;
   device::SensorReading reading_data;
-  while (!TryReadFromBuffer(reading_data)) {
-    if (++read_attempts == kMaxReadAttemptsCount) {
-      HandleSensorError();
-      return;
-    }
+  if (!shared_buffer_handle_->is_valid() ||
+      !shared_buffer_reader_->GetReading(&reading_data)) {
+    HandleSensorError();
+    return;
   }
 
   if (reading_.timestamp != reading_data.timestamp) {
@@ -202,6 +199,11 @@
     HandleSensorError();
     return;
   }
+
+  const auto* buffer = static_cast<const device::SensorReadingSharedBuffer*>(
+      shared_buffer_.get());
+  shared_buffer_reader_.reset(
+      new device::SensorReadingSharedBufferReader(buffer));
   frequency_limits_.first = params->minimum_frequency;
   frequency_limits_.second = params->maximum_frequency;
 
@@ -254,19 +256,6 @@
   UpdatePollingStatus();
 }
 
-bool SensorProxy::TryReadFromBuffer(device::SensorReading& result) {
-  DCHECK(IsInitialized());
-  const ReadingBuffer* buffer =
-      static_cast<const ReadingBuffer*>(shared_buffer_.get());
-  const device::OneWriterSeqLock& seqlock = buffer->seqlock.value();
-  auto version = seqlock.ReadBegin();
-  auto reading_data = buffer->reading;
-  if (seqlock.ReadRetry(version))
-    return false;
-  result = reading_data;
-  return true;
-}
-
 void SensorProxy::OnPollingTimer(TimerBase*) {
   UpdateSensorReading();
 }
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProxy.h b/third_party/WebKit/Source/modules/sensor/SensorProxy.h
index 939bcea3..0057978 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorProxy.h
+++ b/third_party/WebKit/Source/modules/sensor/SensorProxy.h
@@ -14,6 +14,7 @@
 #include "platform/heap/Handle.h"
 #include "platform/wtf/Vector.h"
 #include "services/device/public/cpp/generic_sensor/sensor_reading.h"
+#include "services/device/public/cpp/generic_sensor/sensor_reading_shared_buffer_reader.h"
 #include "services/device/public/interfaces/sensor.mojom-blink.h"
 #include "services/device/public/interfaces/sensor_provider.mojom-blink.h"
 
@@ -112,8 +113,6 @@
       bool result);
   void OnRemoveConfigurationCompleted(double frequency, bool result);
 
-  bool TryReadFromBuffer(device::SensorReading& result);
-
   void OnPollingTimer(TimerBase*);
 
   // Returns 'true' if readings should be propagated to Observers
@@ -141,6 +140,8 @@
   State state_;
   mojo::ScopedSharedBufferHandle shared_buffer_handle_;
   mojo::ScopedSharedBufferMapping shared_buffer_;
+  std::unique_ptr<device::SensorReadingSharedBufferReader>
+      shared_buffer_reader_;
   bool suspended_;
   device::SensorReading reading_;
   std::pair<double, double> frequency_limits_;
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index d1974c0e..db78d784b 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -1970,6 +1970,7 @@
     "text/ICUErrorTest.cpp",
     "text/PlatformLocaleTest.cpp",
     "text/SegmentedStringTest.cpp",
+    "text/SuffixTreeTest.cpp",
     "text/TextBreakIteratorTest.cpp",
     "text/TextEncodingDetectorTest.cpp",
     "text/UnicodeUtilitiesTest.cpp",
diff --git a/third_party/WebKit/Source/platform/LayoutUnit.h b/third_party/WebKit/Source/platform/LayoutUnit.h
index dfefdea..534496a 100644
--- a/third_party/WebKit/Source/platform/LayoutUnit.h
+++ b/third_party/WebKit/Source/platform/LayoutUnit.h
@@ -53,7 +53,7 @@
 #define REPORT_OVERFLOW(doesOverflow) ((void)0)
 #endif
 
-static const int kLayoutUnitFractionalBits = 6;
+static const unsigned kLayoutUnitFractionalBits = 6;
 static const int kFixedPointDenominator = 1 << kLayoutUnitFractionalBits;
 
 const int kIntMaxForLayoutUnit = INT_MAX / kFixedPointDenominator;
@@ -154,7 +154,7 @@
     return ToInt();
   }
   ALWAYS_INLINE int Round() const {
-    return SaturatedAddition(RawValue(), kFixedPointDenominator / 2) >>
+    return ClampAdd(RawValue(), kFixedPointDenominator / 2) >>
            kLayoutUnitFractionalBits;
   }
 
@@ -516,7 +516,7 @@
 
 ALWAYS_INLINE LayoutUnit operator+(const LayoutUnit& a, const LayoutUnit& b) {
   LayoutUnit return_val;
-  return_val.SetRawValue(SaturatedAddition(a.RawValue(), b.RawValue()));
+  return_val.SetRawValue(ClampAdd(a.RawValue(), b.RawValue()).RawValue());
   return return_val;
 }
 
@@ -546,7 +546,7 @@
 
 ALWAYS_INLINE LayoutUnit operator-(const LayoutUnit& a, const LayoutUnit& b) {
   LayoutUnit return_val;
-  return_val.SetRawValue(SaturatedSubtraction(a.RawValue(), b.RawValue()));
+  return_val.SetRawValue(ClampSub(a.RawValue(), b.RawValue()).RawValue());
   return return_val;
 }
 
@@ -576,7 +576,7 @@
 
 inline LayoutUnit operator-(const LayoutUnit& a) {
   LayoutUnit return_val;
-  return_val.SetRawValue(SaturatedNegative(a.RawValue()));
+  return_val.SetRawValue((-MakeClampedNum(a.RawValue())).RawValue());
   return return_val;
 }
 
@@ -608,7 +608,7 @@
 }
 
 inline LayoutUnit& operator+=(LayoutUnit& a, const LayoutUnit& b) {
-  a.SetRawValue(SaturatedAddition(a.RawValue(), b.RawValue()));
+  a.SetRawValue(ClampAdd(a.RawValue(), b.RawValue()).RawValue());
   return a;
 }
 
@@ -633,7 +633,7 @@
 }
 
 inline LayoutUnit& operator-=(LayoutUnit& a, const LayoutUnit& b) {
-  a.SetRawValue(SaturatedSubtraction(a.RawValue(), b.RawValue()));
+  a.SetRawValue(ClampSub(a.RawValue(), b.RawValue()).RawValue());
   return a;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/AcceptLanguagesResolver.cpp b/third_party/WebKit/Source/platform/fonts/AcceptLanguagesResolver.cpp
index 031e8f3f..26898c5 100644
--- a/third_party/WebKit/Source/platform/fonts/AcceptLanguagesResolver.cpp
+++ b/third_party/WebKit/Source/platform/fonts/AcceptLanguagesResolver.cpp
@@ -9,14 +9,9 @@
 
 namespace blink {
 
-static String& CurrentAcceptLanguages() {
-  DEFINE_STATIC_LOCAL(String, current, ());
-  return current;
-}
-
 void AcceptLanguagesResolver::AcceptLanguagesChanged(
     const String& accept_languages) {
-  String& current_value = CurrentAcceptLanguages();
+  String& current_value = FontGlobalContext::CurrentAcceptLanguages();
   if (current_value == accept_languages)
     return;
 
@@ -25,7 +20,8 @@
 }
 
 const LayoutLocale* AcceptLanguagesResolver::LocaleForHan() {
-  return LocaleForHanFromAcceptLanguages(CurrentAcceptLanguages());
+  return LocaleForHanFromAcceptLanguages(
+      FontGlobalContext::CurrentAcceptLanguages());
 }
 
 const LayoutLocale* AcceptLanguagesResolver::LocaleForHanFromAcceptLanguages(
diff --git a/third_party/WebKit/Source/platform/fonts/FontCache.cpp b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
index 2e5ebc8..0dc5a27 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCache.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCache.cpp
@@ -206,17 +206,6 @@
   return result;
 }
 
-typedef HashMap<FontCache::FontFileKey,
-                RefPtr<OpenTypeVerticalData>,
-                IntHash<FontCache::FontFileKey>,
-                UnsignedWithZeroKeyHashTraits<FontCache::FontFileKey>>
-    FontVerticalDataCache;
-
-FontVerticalDataCache& FontVerticalDataCacheInstance() {
-  DEFINE_STATIC_LOCAL(FontVerticalDataCache, font_vertical_data_cache, ());
-  return font_vertical_data_cache;
-}
-
 void FontCache::SetFontManager(sk_sp<SkFontMgr> font_manager) {
   DCHECK(!static_font_manager_);
   static_font_manager_ = font_manager.release();
@@ -226,7 +215,7 @@
     const FontFileKey& key,
     const FontPlatformData& platform_data) {
   FontVerticalDataCache& font_vertical_data_cache =
-      FontVerticalDataCacheInstance();
+      FontGlobalContext::GetFontVerticalDataCache();
   FontVerticalDataCache::iterator result = font_vertical_data_cache.find(key);
   if (result != font_vertical_data_cache.end())
     return result.Get()->value;
@@ -330,7 +319,7 @@
 
 void FontCache::PurgeFontVerticalDataCache() {
   FontVerticalDataCache& font_vertical_data_cache =
-      FontVerticalDataCacheInstance();
+      FontGlobalContext::GetFontVerticalDataCache();
   if (!font_vertical_data_cache.IsEmpty()) {
     // Mark & sweep unused verticalData
     FontVerticalDataCache::iterator vertical_data_end =
diff --git a/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5 b/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5
index 4d86dc7..638bf799 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5
+++ b/third_party/WebKit/Source/platform/fonts/FontFamilyNames.json5
@@ -19,6 +19,7 @@
     "Courier New",
     "Courier",
     "Helvetica",
+    "Lucida Grande",
     "Microsoft Sans Serif",
     "MS Sans Serif",
     "MS Serif",
@@ -33,5 +34,7 @@
     "monospace",
     "sans-serif",
     "serif",
+
+    "BlinkMacSystemFont",
   ],
 }
diff --git a/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h b/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
index 4571cd3..8084733 100644
--- a/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
+++ b/third_party/WebKit/Source/platform/fonts/FontGlobalContext.h
@@ -23,6 +23,12 @@
 using LayoutLocaleMap =
     HashMap<AtomicString, RefPtr<LayoutLocale>, CaseFoldingHash>;
 
+typedef HashMap<FontCache::FontFileKey,
+                RefPtr<OpenTypeVerticalData>,
+                IntHash<FontCache::FontFileKey>,
+                WTF::UnsignedWithZeroKeyHashTraits<FontCache::FontFileKey>>
+    FontVerticalDataCache;
+
 enum CreateIfNeeded { kDoNotCreate, kCreate };
 
 // FontGlobalContext contains non-thread-safe, thread-specific data used for
@@ -83,6 +89,14 @@
     return Get()->has_default_locale_for_han_;
   }
 
+  static inline String& CurrentAcceptLanguages() {
+    return Get()->current_accept_languages_;
+  }
+
+  static inline FontVerticalDataCache& GetFontVerticalDataCache() {
+    return Get()->font_vertical_data_cache_;
+  }
+
   // Called by MemoryCoordinator to clear memory.
   static void ClearMemory();
 
@@ -105,6 +119,10 @@
   const LayoutLocale* system_locale_;
   const LayoutLocale* default_locale_for_han_;
   bool has_default_locale_for_han_;
+
+  String current_accept_languages_;
+
+  FontVerticalDataCache font_vertical_data_cache_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/OrientationIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/OrientationIteratorTest.cpp
index a792987..a5c5269 100644
--- a/third_party/WebKit/Source/platform/fonts/OrientationIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/OrientationIteratorTest.cpp
@@ -9,28 +9,29 @@
 
 namespace blink {
 
-struct TestRun {
+struct OrientationTestRun {
   std::string text;
   OrientationIterator::RenderOrientation code;
 };
 
-struct ExpectedRun {
+struct OrientationExpectedRun {
   unsigned limit;
   OrientationIterator::RenderOrientation render_orientation;
 
-  ExpectedRun(unsigned the_limit,
-              OrientationIterator::RenderOrientation the_render_orientation)
+  OrientationExpectedRun(
+      unsigned the_limit,
+      OrientationIterator::RenderOrientation the_render_orientation)
       : limit(the_limit), render_orientation(the_render_orientation) {}
 };
 
 class OrientationIteratorTest : public ::testing::Test {
  protected:
-  void CheckRuns(const Vector<TestRun>& runs) {
+  void CheckRuns(const Vector<OrientationTestRun>& runs) {
     String text(g_empty_string16_bit);
-    Vector<ExpectedRun> expect;
+    Vector<OrientationExpectedRun> expect;
     for (auto& run : runs) {
       text.append(String::FromUTF8(run.text.c_str()));
-      expect.push_back(ExpectedRun(text.length(), run.code));
+      expect.push_back(OrientationExpectedRun(text.length(), run.code));
     }
     OrientationIterator orientation_iterator(text.Characters16(), text.length(),
                                              FontOrientation::kVerticalMixed);
@@ -38,7 +39,7 @@
   }
 
   void VerifyRuns(OrientationIterator* orientation_iterator,
-                  const Vector<ExpectedRun>& expect) {
+                  const Vector<OrientationExpectedRun>& expect) {
     unsigned limit;
     OrientationIterator::RenderOrientation render_orientation;
     unsigned long run_count = 0;
@@ -53,9 +54,9 @@
 };
 
 // TODO(esprehn): WTF::Vector should allow initialization from a literal.
-#define CHECK_RUNS(...)                                              \
-  static const TestRun kRunsArray[] = __VA_ARGS__;                   \
-  Vector<TestRun> runs;                                              \
+#define CHECK_ORIENTATION(...)                                       \
+  static const OrientationTestRun kRunsArray[] = __VA_ARGS__;        \
+  Vector<OrientationTestRun> runs;                                   \
   runs.Append(kRunsArray, sizeof(kRunsArray) / sizeof(*kRunsArray)); \
   CheckRuns(runs);
 
@@ -72,42 +73,44 @@
 }
 
 TEST_F(OrientationIteratorTest, OneCharLatin) {
-  CHECK_RUNS({{"A", OrientationIterator::kOrientationRotateSideways}});
+  CHECK_ORIENTATION({{"A", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, OneAceOfSpades) {
-  CHECK_RUNS({{"🂡", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"🂡", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, CombiningCircle) {
-  CHECK_RUNS({{"◌́◌̀◌̈◌̂◌̄◌̊", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"◌́◌̀◌̈◌̂◌̄◌̊", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, OneEthiopicSyllable) {
-  CHECK_RUNS({{"ጀ", OrientationIterator::kOrientationRotateSideways}});
+  CHECK_ORIENTATION({{"ጀ", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, JapaneseLetterlikeEnd) {
-  CHECK_RUNS(
+  CHECK_ORIENTATION(
       {{"いろは", OrientationIterator::kOrientationKeep},
        {"ℐℒℐℒℐℒℐℒℐℒℐℒℐℒ", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, LetterlikeJapaneseEnd) {
-  CHECK_RUNS({{"ℐ", OrientationIterator::kOrientationRotateSideways},
-              {"いろは", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"ℐ", OrientationIterator::kOrientationRotateSideways},
+                     {"いろは", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, OneCharJapanese) {
-  CHECK_RUNS({{"い", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"い", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, Japanese) {
-  CHECK_RUNS({{"いろはにほへと", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION(
+      {{"いろはにほへと", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, IVS) {
-  CHECK_RUNS({{"愉\xF3\xA0\x84\x81", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION(
+      {{"愉\xF3\xA0\x84\x81", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, MarkAtFirstCharRotated) {
@@ -117,47 +120,50 @@
   // http://www.unicode.org/reports/tr50/#grapheme_clusters
   // https://drafts.csswg.org/css-writing-modes-3/#vertical-orientations
   // U+0300 COMBINING GRAVE ACCENT is Mn (Mark, Nonspacing) with Rotated.
-  CHECK_RUNS({{"\xCC\x80", OrientationIterator::kOrientationRotateSideways}});
+  CHECK_ORIENTATION(
+      {{"\xCC\x80", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, MarkAtFirstCharUpright) {
   // U+20DD COMBINING ENCLOSING CIRCLE is Me (Mark, Enclosing) with Upright.
-  CHECK_RUNS({{"\xE2\x83\x9D", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"\xE2\x83\x9D", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, MarksAtFirstCharUpright) {
   // U+20DD COMBINING ENCLOSING CIRCLE is Me (Mark, Enclosing) with Upright.
   // U+0300 COMBINING GRAVE ACCENT is Mn (Mark, Nonspacing) with Rotated.
-  CHECK_RUNS({{"\xE2\x83\x9D\xCC\x80", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION(
+      {{"\xE2\x83\x9D\xCC\x80", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, MarksAtFirstCharUprightThenBase) {
   // U+20DD COMBINING ENCLOSING CIRCLE is Me (Mark, Enclosing) with Upright.
   // U+0300 COMBINING GRAVE ACCENT is Mn (Mark, Nonspacing) with Rotated.
-  CHECK_RUNS(
+  CHECK_ORIENTATION(
       {{"\xE2\x83\x9D\xCC\x80", OrientationIterator::kOrientationKeep},
        {"ABC\xE2\x83\x9D", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, JapaneseLatinMixedInside) {
-  CHECK_RUNS({{"いろはに", OrientationIterator::kOrientationKeep},
-              {"Abc", OrientationIterator::kOrientationRotateSideways},
-              {"ほへと", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{"いろはに", OrientationIterator::kOrientationKeep},
+                     {"Abc", OrientationIterator::kOrientationRotateSideways},
+                     {"ほへと", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, PunctuationJapanese) {
-  CHECK_RUNS({{".…¡", OrientationIterator::kOrientationRotateSideways},
-              {"ほへと", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION({{".…¡", OrientationIterator::kOrientationRotateSideways},
+                     {"ほへと", OrientationIterator::kOrientationKeep}});
 }
 
 TEST_F(OrientationIteratorTest, JapaneseLatinMixedOutside) {
-  CHECK_RUNS({{"Abc", OrientationIterator::kOrientationRotateSideways},
-              {"ほへと", OrientationIterator::kOrientationKeep},
-              {"Xyz", OrientationIterator::kOrientationRotateSideways}});
+  CHECK_ORIENTATION({{"Abc", OrientationIterator::kOrientationRotateSideways},
+                     {"ほへと", OrientationIterator::kOrientationKeep},
+                     {"Xyz", OrientationIterator::kOrientationRotateSideways}});
 }
 
 TEST_F(OrientationIteratorTest, JapaneseMahjonggMixed) {
-  CHECK_RUNS({{"いろはに🀤ほへと", OrientationIterator::kOrientationKeep}});
+  CHECK_ORIENTATION(
+      {{"いろはに🀤ほへと", OrientationIterator::kOrientationKeep}});
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
index 6bb487e..7691c31 100644
--- a/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/ScriptRunIteratorTest.cpp
@@ -12,16 +12,16 @@
 
 namespace blink {
 
-struct TestRun {
+struct ScriptTestRun {
   std::string text;
   UScriptCode code;
 };
 
-struct ExpectedRun {
+struct ScriptExpectedRun {
   unsigned limit;
   UScriptCode code;
 
-  ExpectedRun(unsigned the_limit, UScriptCode the_code)
+  ScriptExpectedRun(unsigned the_limit, UScriptCode the_code)
       : limit(the_limit), code(the_code) {}
 };
 
@@ -286,12 +286,12 @@
 
 class ScriptRunIteratorTest : public ::testing::Test {
  protected:
-  void CheckRuns(const Vector<TestRun>& runs) {
+  void CheckRuns(const Vector<ScriptTestRun>& runs) {
     String text(g_empty_string16_bit);
-    Vector<ExpectedRun> expect;
+    Vector<ScriptExpectedRun> expect;
     for (auto& run : runs) {
       text.append(String::FromUTF8(run.text.c_str()));
-      expect.push_back(ExpectedRun(text.length(), run.code));
+      expect.push_back(ScriptExpectedRun(text.length(), run.code));
     }
     ScriptRunIterator script_run_iterator(text.Characters16(), text.length());
     VerifyRuns(&script_run_iterator, expect);
@@ -299,12 +299,12 @@
 
   // FIXME crbug.com/527329 - CheckMockRuns should be replaced by finding
   // suitable equivalent real codepoint sequences instead.
-  void CheckMockRuns(const Vector<TestRun>& runs) {
+  void CheckMockRuns(const Vector<ScriptTestRun>& runs) {
     String text(g_empty_string16_bit);
-    Vector<ExpectedRun> expect;
-    for (const TestRun& run : runs) {
+    Vector<ScriptExpectedRun> expect;
+    for (const ScriptTestRun& run : runs) {
       text.append(MockScriptData::ToTestString(run.text));
-      expect.push_back(ExpectedRun(text.length(), run.code));
+      expect.push_back(ScriptExpectedRun(text.length(), run.code));
     }
 
     ScriptRunIterator script_run_iterator(text.Characters16(), text.length(),
@@ -313,7 +313,7 @@
   }
 
   void VerifyRuns(ScriptRunIterator* script_run_iterator,
-                  const Vector<ExpectedRun>& expect) {
+                  const Vector<ScriptExpectedRun>& expect) {
     unsigned limit;
     UScriptCode code;
     unsigned long run_count = 0;
@@ -338,134 +338,136 @@
 }
 
 // Some of our compilers cannot initialize a vector from an array yet.
-#define DECLARE_RUNSVECTOR(...)                    \
-  static const TestRun kRunsArray[] = __VA_ARGS__; \
-  Vector<TestRun> runs;                            \
+#define DECLARE_SCRIPT_RUNSVECTOR(...)                   \
+  static const ScriptTestRun kRunsArray[] = __VA_ARGS__; \
+  Vector<ScriptTestRun> runs;                            \
   runs.Append(kRunsArray, sizeof(kRunsArray) / sizeof(*kRunsArray));
 
-#define CHECK_RUNS(...)            \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_SCRIPT_RUNS(...)            \
+  DECLARE_SCRIPT_RUNSVECTOR(__VA_ARGS__); \
   CheckRuns(runs);
 
-#define CHECK_MOCK_RUNS(...)       \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_MOCK_SCRIPT_RUNS(...)       \
+  DECLARE_SCRIPT_RUNSVECTOR(__VA_ARGS__); \
   CheckMockRuns(runs);
 
 TEST_F(ScriptRunIteratorTest, Whitespace) {
-  CHECK_RUNS({{" \t ", USCRIPT_COMMON}});
+  CHECK_SCRIPT_RUNS({{" \t ", USCRIPT_COMMON}});
 }
 
 TEST_F(ScriptRunIteratorTest, Common) {
-  CHECK_RUNS({{" ... !?", USCRIPT_COMMON}});
+  CHECK_SCRIPT_RUNS({{" ... !?", USCRIPT_COMMON}});
 }
 
 TEST_F(ScriptRunIteratorTest, CombiningCircle) {
-  CHECK_RUNS({{"◌́◌̀◌̈◌̂◌̄◌̊", USCRIPT_COMMON}});
+  CHECK_SCRIPT_RUNS({{"◌́◌̀◌̈◌̂◌̄◌̊", USCRIPT_COMMON}});
 }
 
 TEST_F(ScriptRunIteratorTest, Latin) {
-  CHECK_RUNS({{"latin", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"latin", USCRIPT_LATIN}});
 }
 
 TEST_F(ScriptRunIteratorTest, Chinese) {
-  CHECK_RUNS({{"萬國碼", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"萬國碼", USCRIPT_HAN}});
 }
 
 // Close bracket without matching open is ignored
 TEST_F(ScriptRunIteratorTest, UnbalancedParens1) {
-  CHECK_RUNS({{"(萬", USCRIPT_HAN}, {"a]", USCRIPT_LATIN}, {")", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS(
+      {{"(萬", USCRIPT_HAN}, {"a]", USCRIPT_LATIN}, {")", USCRIPT_HAN}});
 }
 
 // Open bracket without matching close is popped when inside
 // matching close brackets, so doesn't match later close.
 TEST_F(ScriptRunIteratorTest, UnbalancedParens2) {
-  CHECK_RUNS(
+  CHECK_SCRIPT_RUNS(
       {{"(萬", USCRIPT_HAN}, {"a[", USCRIPT_LATIN}, {")]", USCRIPT_HAN}});
 }
 
 // space goes with leading script
 TEST_F(ScriptRunIteratorTest, LatinHan) {
-  CHECK_RUNS({{"Unicode ", USCRIPT_LATIN}, {"萬國碼", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"Unicode ", USCRIPT_LATIN}, {"萬國碼", USCRIPT_HAN}});
 }
 
 // space goes with leading script
 TEST_F(ScriptRunIteratorTest, HanLatin) {
-  CHECK_RUNS({{"萬國碼 ", USCRIPT_HAN}, {"Unicode", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"萬國碼 ", USCRIPT_HAN}, {"Unicode", USCRIPT_LATIN}});
 }
 
 TEST_F(ScriptRunIteratorTest, ParenEmptyParen) {
-  CHECK_RUNS({{"()", USCRIPT_COMMON}});
+  CHECK_SCRIPT_RUNS({{"()", USCRIPT_COMMON}});
 }
 
 TEST_F(ScriptRunIteratorTest, ParenChineseParen) {
-  CHECK_RUNS({{"(萬國碼)", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"(萬國碼)", USCRIPT_HAN}});
 }
 
 TEST_F(ScriptRunIteratorTest, ParenLatinParen) {
-  CHECK_RUNS({{"(Unicode)", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"(Unicode)", USCRIPT_LATIN}});
 }
 
 // open paren gets leading script
 TEST_F(ScriptRunIteratorTest, LatinParenChineseParen) {
-  CHECK_RUNS({{"Unicode (", USCRIPT_LATIN},
-              {"萬國碼", USCRIPT_HAN},
-              {")", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"Unicode (", USCRIPT_LATIN},
+                     {"萬國碼", USCRIPT_HAN},
+                     {")", USCRIPT_LATIN}});
 }
 
 // open paren gets first trailing script if no leading script
 TEST_F(ScriptRunIteratorTest, ParenChineseParenLatin) {
-  CHECK_RUNS({{"(萬國碼) ", USCRIPT_HAN}, {"Unicode", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"(萬國碼) ", USCRIPT_HAN}, {"Unicode", USCRIPT_LATIN}});
 }
 
 // leading common and open paren get first trailing script.
 // TODO(dougfelt): we don't do quote matching, but probably should figure out
 // something better then doing nothing.
 TEST_F(ScriptRunIteratorTest, QuoteParenChineseParenLatinQuote) {
-  CHECK_RUNS({{"\"(萬國碼) ", USCRIPT_HAN}, {"Unicode\"", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS(
+      {{"\"(萬國碼) ", USCRIPT_HAN}, {"Unicode\"", USCRIPT_LATIN}});
 }
 
 // Emojies are resolved to the leading script.
 TEST_F(ScriptRunIteratorTest, EmojiCommon) {
-  CHECK_RUNS({{"百家姓🌱🌲🌳🌴", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"百家姓🌱🌲🌳🌴", USCRIPT_HAN}});
 }
 
 // Unmatched close brace gets leading context
 TEST_F(ScriptRunIteratorTest, UnmatchedClose) {
-  CHECK_RUNS({{"Unicode (", USCRIPT_LATIN},
-              {"萬國碼] ", USCRIPT_HAN},
-              {") Unicode\"", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"Unicode (", USCRIPT_LATIN},
+                     {"萬國碼] ", USCRIPT_HAN},
+                     {") Unicode\"", USCRIPT_LATIN}});
 }
 
 // Match up to 32 bracket pairs
 TEST_F(ScriptRunIteratorTest, Match32Brackets) {
-  CHECK_RUNS({{"[萬國碼 ", USCRIPT_HAN},
-              {"Unicode (((((((((((((((((((((((((((((((!"
-               ")))))))))))))))))))))))))))))))",
-               USCRIPT_LATIN},
-              {"]", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"[萬國碼 ", USCRIPT_HAN},
+                     {"Unicode (((((((((((((((((((((((((((((((!"
+                      ")))))))))))))))))))))))))))))))",
+                      USCRIPT_LATIN},
+                     {"]", USCRIPT_HAN}});
 }
 
 // Matches 32 most recent bracket pairs. More than that, and we revert to
 // surrounding script.
 TEST_F(ScriptRunIteratorTest, Match32MostRecentBrackets) {
-  CHECK_RUNS({{"((([萬國碼 ", USCRIPT_HAN},
-              {"Unicode (((((((((((((((((((((((((((((((", USCRIPT_LATIN},
-              {"萬國碼!", USCRIPT_HAN},
-              {")))))))))))))))))))))))))))))))", USCRIPT_LATIN},
-              {"]", USCRIPT_HAN},
-              {"But )))", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"((([萬國碼 ", USCRIPT_HAN},
+                     {"Unicode (((((((((((((((((((((((((((((((", USCRIPT_LATIN},
+                     {"萬國碼!", USCRIPT_HAN},
+                     {")))))))))))))))))))))))))))))))", USCRIPT_LATIN},
+                     {"]", USCRIPT_HAN},
+                     {"But )))", USCRIPT_LATIN}});
 }
 
 // A char with multiple scripts that match both leading and trailing context
 // gets the leading context.
 TEST_F(ScriptRunIteratorTest, ExtensionsPreferLeadingContext) {
-  CHECK_MOCK_RUNS({{"h<lh>", USCRIPT_HAN}, {"l", USCRIPT_LATIN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"h<lh>", USCRIPT_HAN}, {"l", USCRIPT_LATIN}});
 }
 
 // A char with multiple scripts that only match trailing context gets the
 // trailing context.
 TEST_F(ScriptRunIteratorTest, ExtensionsMatchTrailingContext) {
-  CHECK_MOCK_RUNS({{"h", USCRIPT_HAN}, {"<gl>l", USCRIPT_LATIN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"h", USCRIPT_HAN}, {"<gl>l", USCRIPT_LATIN}});
 }
 
 // Retain first established priority script.  <lhg><gh> produce the script <gh>
@@ -473,23 +475,23 @@
 // remains.  Then <gh><hgl> retains g as priority, because of the two priority
 // scripts g and h that remain, g was encountered first.
 TEST_F(ScriptRunIteratorTest, ExtensionsRetainFirstPriorityScript) {
-  CHECK_MOCK_RUNS({{"<lhg><gh><hgl>", USCRIPT_GREEK}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<lhg><gh><hgl>", USCRIPT_GREEK}});
 }
 
 // Parens can have scripts that break script runs.
 TEST_F(ScriptRunIteratorTest, ExtensionsParens) {
-  CHECK_MOCK_RUNS({{"<gl><(lg>", USCRIPT_GREEK},
-                   {"h<[hl>", USCRIPT_HAN},
-                   {"l", USCRIPT_LATIN},
-                   {"<]hl>", USCRIPT_HAN},
-                   {"<)lg>", USCRIPT_GREEK}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<gl><(lg>", USCRIPT_GREEK},
+                          {"h<[hl>", USCRIPT_HAN},
+                          {"l", USCRIPT_LATIN},
+                          {"<]hl>", USCRIPT_HAN},
+                          {"<)lg>", USCRIPT_GREEK}});
 }
 
 // The close paren might be encountered before we've established the open
 // paren's script, but when this is the case the current set is still valid, so
 // this doesn't affect it nor break the run.
 TEST_F(ScriptRunIteratorTest, ExtensionsParens2) {
-  CHECK_MOCK_RUNS({{"<(lhg><gh><)lhg>", USCRIPT_GREEK}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<(lhg><gh><)lhg>", USCRIPT_GREEK}});
 }
 
 // A common script with a single extension should be treated as common, but
@@ -497,15 +499,15 @@
 // common, that takes priority.  If we encounter other common scripts with a
 // single extension, the current priority remains.
 TEST_F(ScriptRunIteratorTest, CommonWithPriority) {
-  CHECK_MOCK_RUNS({{"<ch>", USCRIPT_HAN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<ch>", USCRIPT_HAN}});
 }
 
 TEST_F(ScriptRunIteratorTest, CommonWithPriority2) {
-  CHECK_MOCK_RUNS({{"<ch><lh>", USCRIPT_LATIN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<ch><lh>", USCRIPT_LATIN}});
 }
 
 TEST_F(ScriptRunIteratorTest, CommonWithPriority3) {
-  CHECK_MOCK_RUNS({{"<ch><cl><cg>", USCRIPT_HAN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<ch><cl><cg>", USCRIPT_HAN}});
 }
 
 // UDatta (\xE0\xA5\x91) is inherited with LATIN, DEVANAGARI, BENGALI and
@@ -513,7 +515,7 @@
 // dotted circle U+25CC (\xE2\x97\x8C) is COMMON and has adopted the
 // preceding LATIN, it gets the LATIN. This is standard.
 TEST_F(ScriptRunIteratorTest, LatinDottedCircleUdatta) {
-  CHECK_RUNS({{"Latin \xE2\x97\x8C\xE0\xA5\x91", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"Latin \xE2\x97\x8C\xE0\xA5\x91", USCRIPT_LATIN}});
 }
 
 // In this situation, UDatta U+0951 (\xE0\xA5\x91) doesn't share a script
@@ -526,8 +528,8 @@
 // Taking into account a Unicode block and returning DEVANAGARI would be
 // slightly better.
 TEST_F(ScriptRunIteratorTest, HanDottedCircleUdatta) {
-  CHECK_RUNS({{"萬國碼 ", USCRIPT_HAN},
-              {"\xE2\x97\x8C\xE0\xA5\x91", USCRIPT_BENGALI}});
+  CHECK_SCRIPT_RUNS({{"萬國碼 ", USCRIPT_HAN},
+                     {"\xE2\x97\x8C\xE0\xA5\x91", USCRIPT_BENGALI}});
 }
 
 // Tatweel is \xD9\x80 Lm, Fathatan is \xD9\x8B Mn. The script of tatweel is
@@ -537,7 +539,8 @@
 // heuristic. This is exactly analogous to the Udatta tests above, except
 // Tatweel is Lm. But we don't take properties into account, only scripts.
 TEST_F(ScriptRunIteratorTest, LatinTatweelFathatan) {
-  CHECK_RUNS({{"Latin ", USCRIPT_LATIN}, {"\xD9\x80\xD9\x8B", USCRIPT_ARABIC}});
+  CHECK_SCRIPT_RUNS(
+      {{"Latin ", USCRIPT_LATIN}, {"\xD9\x80\xD9\x8B", USCRIPT_ARABIC}});
 }
 
 // Another case where if the mark accepts a script that was inherited by the
@@ -546,26 +549,27 @@
 // ARABIC TATWEEL \xD9\x80
 // ARABIC FATHATAN \xD9\x82
 TEST_F(ScriptRunIteratorTest, SyriacTatweelFathatan) {
-  CHECK_RUNS({{"\xDC\xA2\xD9\x80\xD9\x8B", USCRIPT_SYRIAC}});
+  CHECK_SCRIPT_RUNS({{"\xDC\xA2\xD9\x80\xD9\x8B", USCRIPT_SYRIAC}});
 }
 
 // The Udatta (\xE0\xA5\x91) is inherited, so will share runs with anything that
 // is not common.
 TEST_F(ScriptRunIteratorTest, HanUdatta) {
-  CHECK_RUNS({{"萬國碼\xE0\xA5\x91", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"萬國碼\xE0\xA5\x91", USCRIPT_HAN}});
 }
 
 // The Udatta U+0951 (\xE0\xA5\x91) is inherited, and will capture the space
 // and turn it into Bengali because SCRIPT_BENAGLI is 4 and SCRIPT_DEVANAGARI
 // is 10. See TODO comment for |getScripts| and HanDottedCircleUdatta.
 TEST_F(ScriptRunIteratorTest, HanSpaceUdatta) {
-  CHECK_RUNS({{"萬國碼", USCRIPT_HAN}, {" \xE0\xA5\x91", USCRIPT_BENGALI}});
+  CHECK_SCRIPT_RUNS(
+      {{"萬國碼", USCRIPT_HAN}, {" \xE0\xA5\x91", USCRIPT_BENGALI}});
 }
 
 // Corresponds to one test in RunSegmenter, where orientation of the
 // space character is sidesways in vertical.
 TEST_F(ScriptRunIteratorTest, Hangul) {
-  CHECK_RUNS({{"키스의 고유조건은", USCRIPT_HANGUL}});
+  CHECK_SCRIPT_RUNS({{"키스의 고유조건은", USCRIPT_HANGUL}});
 }
 
 // Corresponds to one test in RunSegmenter, which tests that the punctuation
@@ -573,45 +577,45 @@
 // should report one run, but the RunSegmenter should report three, with the
 // middle one rotated sideways.
 TEST_F(ScriptRunIteratorTest, HiraganaMixedPunctuation) {
-  CHECK_RUNS({{"いろはに.…¡ほへと", USCRIPT_HIRAGANA}});
+  CHECK_SCRIPT_RUNS({{"いろはに.…¡ほへと", USCRIPT_HIRAGANA}});
 }
 
 // Make sure Mock code works too.
 TEST_F(ScriptRunIteratorTest, MockHanInheritedGL) {
-  CHECK_MOCK_RUNS({{"h<igl>", USCRIPT_HAN}});
+  CHECK_MOCK_SCRIPT_RUNS({{"h<igl>", USCRIPT_HAN}});
 }
 
 TEST_F(ScriptRunIteratorTest, MockHanCommonInheritedGL) {
-  CHECK_MOCK_RUNS({{"h", USCRIPT_HAN}, {"c<igl>", USCRIPT_GREEK}});
+  CHECK_MOCK_SCRIPT_RUNS({{"h", USCRIPT_HAN}, {"c<igl>", USCRIPT_GREEK}});
 }
 
 // Leading inherited just act like common, except there's no preferred script.
 TEST_F(ScriptRunIteratorTest, MockLeadingInherited) {
-  CHECK_MOCK_RUNS({{"<igl>", USCRIPT_COMMON}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<igl>", USCRIPT_COMMON}});
 }
 
 // Leading inherited just act like common, except there's no preferred script.
 TEST_F(ScriptRunIteratorTest, MockLeadingInherited2) {
-  CHECK_MOCK_RUNS({{"<igl><ih>", USCRIPT_COMMON}});
+  CHECK_MOCK_SCRIPT_RUNS({{"<igl><ih>", USCRIPT_COMMON}});
 }
 
 TEST_F(ScriptRunIteratorTest, LeadingInheritedHan) {
   // DEVANAGARI STRESS SIGN UDATTA \xE0\xA5\x91
-  CHECK_RUNS({{"\xE0\xA5\x91萬國碼", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"\xE0\xA5\x91萬國碼", USCRIPT_HAN}});
 }
 
 TEST_F(ScriptRunIteratorTest, LeadingInheritedHan2) {
   // DEVANAGARI STRESS SIGN UDATTA \xE0\xA5\x91
   // ARABIC FATHATAN \xD9\x8B
-  CHECK_RUNS({{"\xE0\xA5\x91\xD9\x8B萬國碼", USCRIPT_HAN}});
+  CHECK_SCRIPT_RUNS({{"\xE0\xA5\x91\xD9\x8B萬國碼", USCRIPT_HAN}});
 }
 
 TEST_F(ScriptRunIteratorTest, OddLatinString) {
-  CHECK_RUNS({{"ç̈", USCRIPT_LATIN}});
+  CHECK_SCRIPT_RUNS({{"ç̈", USCRIPT_LATIN}});
 }
 
 TEST_F(ScriptRunIteratorTest, CommonMalayalam) {
-  CHECK_RUNS({{"100-ാം", USCRIPT_MALAYALAM}});
+  CHECK_SCRIPT_RUNS({{"100-ാം", USCRIPT_MALAYALAM}});
 }
 
 class ScriptRunIteratorICUDataTest : public ::testing::Test {
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
index d837015..a5e84b4e 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
@@ -39,6 +39,7 @@
 #include "SkTypes.h"
 
 #include "build/build_config.h"
+#include "platform/FontFamilyNames.h"
 #include "platform/fonts/FontDescription.h"
 #include "platform/fonts/VDMXParser.h"
 #include "platform/fonts/skia/SkiaTextMetrics.h"
@@ -184,12 +185,10 @@
   // web standard. The AppKit adjustment of 20% is too big and is
   // incorrectly added to line spacing, so we use a 15% adjustment instead
   // and add it to the ascent.
-  DEFINE_STATIC_LOCAL(AtomicString, times_name, ("Times"));
-  DEFINE_STATIC_LOCAL(AtomicString, helvetica_name, ("Helvetica"));
-  DEFINE_STATIC_LOCAL(AtomicString, courier_name, ("Courier"));
   String family_name = platform_data_.FontFamilyName();
-  if (family_name == times_name || family_name == helvetica_name ||
-      family_name == courier_name)
+  if (family_name == FontFamilyNames::Times ||
+      family_name == FontFamilyNames::Helvetica ||
+      family_name == FontFamilyNames::Courier)
     ascent += floorf(((ascent + descent) * 0.15f) + 0.5f);
 #endif
 
diff --git a/third_party/WebKit/Source/platform/fonts/SmallCapsIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/SmallCapsIteratorTest.cpp
index 8728265..5f51a87 100644
--- a/third_party/WebKit/Source/platform/fonts/SmallCapsIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SmallCapsIteratorTest.cpp
@@ -9,35 +9,36 @@
 
 namespace blink {
 
-struct TestRun {
+struct SmallCapsTestRun {
   std::string text;
   SmallCapsIterator::SmallCapsBehavior code;
 };
 
-struct ExpectedRun {
+struct SmallCapsExpectedRun {
   unsigned limit;
   SmallCapsIterator::SmallCapsBehavior small_caps_behavior;
 
-  ExpectedRun(unsigned the_limit,
-              SmallCapsIterator::SmallCapsBehavior the_small_caps_behavior)
+  SmallCapsExpectedRun(
+      unsigned the_limit,
+      SmallCapsIterator::SmallCapsBehavior the_small_caps_behavior)
       : limit(the_limit), small_caps_behavior(the_small_caps_behavior) {}
 };
 
 class SmallCapsIteratorTest : public ::testing::Test {
  protected:
-  void CheckRuns(const Vector<TestRun>& runs) {
+  void CheckRuns(const Vector<SmallCapsTestRun>& runs) {
     String text(g_empty_string16_bit);
-    Vector<ExpectedRun> expect;
+    Vector<SmallCapsExpectedRun> expect;
     for (auto& run : runs) {
       text.append(String::FromUTF8(run.text.c_str()));
-      expect.push_back(ExpectedRun(text.length(), run.code));
+      expect.push_back(SmallCapsExpectedRun(text.length(), run.code));
     }
     SmallCapsIterator small_caps_iterator(text.Characters16(), text.length());
     VerifyRuns(&small_caps_iterator, expect);
   }
 
   void VerifyRuns(SmallCapsIterator* small_caps_iterator,
-                  const Vector<ExpectedRun>& expect) {
+                  const Vector<SmallCapsExpectedRun>& expect) {
     unsigned limit;
     SmallCapsIterator::SmallCapsBehavior small_caps_behavior;
     unsigned long run_count = 0;
@@ -52,13 +53,13 @@
 };
 
 // Some of our compilers cannot initialize a vector from an array yet.
-#define DECLARE_RUNSVECTOR(...)                    \
-  static const TestRun kRunsArray[] = __VA_ARGS__; \
-  Vector<TestRun> runs;                            \
+#define DECLARE_SMALL_CAPS_RUNSVECTOR(...)                  \
+  static const SmallCapsTestRun kRunsArray[] = __VA_ARGS__; \
+  Vector<SmallCapsTestRun> runs;                            \
   runs.Append(kRunsArray, sizeof(kRunsArray) / sizeof(*kRunsArray));
 
-#define CHECK_RUNS(...)            \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_SMALL_CAPS_RUN(...)             \
+  DECLARE_SMALL_CAPS_RUNSVECTOR(__VA_ARGS__); \
   CheckRuns(runs);
 
 TEST_F(SmallCapsIteratorTest, Empty) {
@@ -73,44 +74,44 @@
 }
 
 TEST_F(SmallCapsIteratorTest, UppercaseA) {
-  CHECK_RUNS({{"A", SmallCapsIterator::kSmallCapsSameCase}});
+  CHECK_SMALL_CAPS_RUN({{"A", SmallCapsIterator::kSmallCapsSameCase}});
 }
 
 TEST_F(SmallCapsIteratorTest, LowercaseA) {
-  CHECK_RUNS({{"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
+  CHECK_SMALL_CAPS_RUN({{"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
 }
 
 TEST_F(SmallCapsIteratorTest, UppercaseLowercaseA) {
-  CHECK_RUNS({{"A", SmallCapsIterator::kSmallCapsSameCase},
-              {"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
+  CHECK_SMALL_CAPS_RUN({{"A", SmallCapsIterator::kSmallCapsSameCase},
+                        {"a", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
 }
 
 TEST_F(SmallCapsIteratorTest, UppercasePunctuationMixed) {
-  CHECK_RUNS({{"AAA??", SmallCapsIterator::kSmallCapsSameCase}});
+  CHECK_SMALL_CAPS_RUN({{"AAA??", SmallCapsIterator::kSmallCapsSameCase}});
 }
 
 TEST_F(SmallCapsIteratorTest, LowercasePunctuationMixed) {
-  CHECK_RUNS({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
-              {"===", SmallCapsIterator::kSmallCapsSameCase}});
+  CHECK_SMALL_CAPS_RUN({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
+                        {"===", SmallCapsIterator::kSmallCapsSameCase}});
 }
 
 TEST_F(SmallCapsIteratorTest, LowercasePunctuationInterleaved) {
-  CHECK_RUNS({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
-              {"===", SmallCapsIterator::kSmallCapsSameCase},
-              {"bbb", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
+  CHECK_SMALL_CAPS_RUN({{"aaa", SmallCapsIterator::kSmallCapsUppercaseNeeded},
+                        {"===", SmallCapsIterator::kSmallCapsSameCase},
+                        {"bbb", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
 }
 
 TEST_F(SmallCapsIteratorTest, Japanese) {
-  CHECK_RUNS({{"ほへと", SmallCapsIterator::kSmallCapsSameCase}});
+  CHECK_SMALL_CAPS_RUN({{"ほへと", SmallCapsIterator::kSmallCapsSameCase}});
 }
 
 TEST_F(SmallCapsIteratorTest, Armenian) {
-  CHECK_RUNS({{"աբգդ", SmallCapsIterator::kSmallCapsUppercaseNeeded},
-              {"ԵԶԷԸ", SmallCapsIterator::kSmallCapsSameCase}});
+  CHECK_SMALL_CAPS_RUN({{"աբգդ", SmallCapsIterator::kSmallCapsUppercaseNeeded},
+                        {"ԵԶԷԸ", SmallCapsIterator::kSmallCapsSameCase}});
 }
 
 TEST_F(SmallCapsIteratorTest, CombiningCharacterSequence) {
-  CHECK_RUNS({{"èü", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
+  CHECK_SMALL_CAPS_RUN({{"èü", SmallCapsIterator::kSmallCapsUppercaseNeeded}});
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp b/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
index 0e0e377..c44c3220 100644
--- a/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SymbolsIteratorTest.cpp
@@ -9,35 +9,36 @@
 
 namespace blink {
 
-struct TestRun {
+struct FallbackTestRun {
   std::string text;
   FontFallbackPriority font_fallback_priority;
 };
 
-struct ExpectedRun {
+struct FallbackExpectedRun {
   unsigned limit;
   FontFallbackPriority font_fallback_priority;
 
-  ExpectedRun(unsigned the_limit,
-              FontFallbackPriority the_font_fallback_priority)
+  FallbackExpectedRun(unsigned the_limit,
+                      FontFallbackPriority the_font_fallback_priority)
       : limit(the_limit), font_fallback_priority(the_font_fallback_priority) {}
 };
 
 class SymbolsIteratorTest : public ::testing::Test {
  protected:
-  void CheckRuns(const Vector<TestRun>& runs) {
+  void CheckRuns(const Vector<FallbackTestRun>& runs) {
     String text(g_empty_string16_bit);
-    Vector<ExpectedRun> expect;
+    Vector<FallbackExpectedRun> expect;
     for (auto& run : runs) {
       text.append(String::FromUTF8(run.text.c_str()));
-      expect.push_back(ExpectedRun(text.length(), run.font_fallback_priority));
+      expect.push_back(
+          FallbackExpectedRun(text.length(), run.font_fallback_priority));
     }
     SymbolsIterator symbols_iterator(text.Characters16(), text.length());
     VerifyRuns(&symbols_iterator, expect);
   }
 
   void VerifyRuns(SymbolsIterator* symbols_iterator,
-                  const Vector<ExpectedRun>& expect) {
+                  const Vector<FallbackExpectedRun>& expect) {
     unsigned limit;
     FontFallbackPriority font_fallback_priority;
     unsigned long run_count = 0;
@@ -53,13 +54,13 @@
 };
 
 // Some of our compilers cannot initialize a vector from an array yet.
-#define DECLARE_RUNSVECTOR(...)                    \
-  static const TestRun kRunsArray[] = __VA_ARGS__; \
-  Vector<TestRun> runs;                            \
+#define DECLARE_FALLBACK_RUNSVECTOR(...)                   \
+  static const FallbackTestRun kRunsArray[] = __VA_ARGS__; \
+  Vector<FallbackTestRun> runs;                            \
   runs.Append(kRunsArray, sizeof(kRunsArray) / sizeof(*kRunsArray));
 
-#define CHECK_RUNS(...)            \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_RUNS(...)                     \
+  DECLARE_FALLBACK_RUNSVECTOR(__VA_ARGS__); \
   CheckRuns(runs);
 
 TEST_F(SymbolsIteratorTest, Empty) {
diff --git a/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp b/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp
index 370603eb..6a321713 100644
--- a/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp
+++ b/third_party/WebKit/Source/platform/fonts/android/FontCacheAndroid.cpp
@@ -30,10 +30,11 @@
 
 #include "platform/fonts/FontCache.h"
 
+#include "platform/FontFamilyNames.h"
 #include "platform/Language.h"
-#include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/FontDescription.h"
 #include "platform/fonts/FontFaceCreationParams.h"
+#include "platform/fonts/SimpleFontData.h"
 #include "third_party/skia/include/core/SkTypeface.h"
 #include "third_party/skia/include/ports/SkFontMgr.h"
 
@@ -55,7 +56,7 @@
   // do here, use "Arial", the value LayoutTheme uses for CSS system font
   // keywords such as "menu".
   NOTREACHED();
-  return "Arial";
+  return FontFamilyNames::Arial;
 }
 
 static AtomicString DefaultFontFamily() {
@@ -67,7 +68,8 @@
 
 // static
 const AtomicString& FontCache::SystemFontFamily() {
-  DEFINE_STATIC_LOCAL(AtomicString, system_font_family, (DefaultFontFamily()));
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, system_font_family,
+                                  (DefaultFontFamily()));
   return system_font_family;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp b/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp
index b034c71e..4328823 100644
--- a/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp
+++ b/third_party/WebKit/Source/platform/fonts/linux/FontCacheLinux.cpp
@@ -39,7 +39,7 @@
     : purge_prevent_count_(0), font_manager_(sk_ref_sp(static_font_manager_)) {}
 
 static AtomicString& MutableSystemFontFamily() {
-  DEFINE_STATIC_LOCAL(AtomicString, system_font_family, ());
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, system_font_family, ());
   return system_font_family;
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm b/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm
index ad0cd39..2f91a0bb 100644
--- a/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm
+++ b/third_party/WebKit/Source/platform/fonts/mac/FontCacheMac.mm
@@ -31,6 +31,7 @@
 
 #import <AppKit/AppKit.h>
 #include <memory>
+#include "platform/FontFamilyNames.h"
 #include "platform/LayoutTestSupport.h"
 #include "platform/RuntimeEnabledFeatures.h"
 #include "platform/WebTaskRunner.h"
@@ -63,9 +64,7 @@
 
 // static
 const AtomicString& FontCache::LegacySystemFontFamily() {
-  DEFINE_STATIC_LOCAL(AtomicString, legacy_system_font_family,
-                      ("BlinkMacSystemFont"));
-  return legacy_system_font_family;
+  return FontFamilyNames::BlinkMacSystemFont;
 }
 
 static void InvalidateFontCache() {
@@ -232,13 +231,11 @@
 PassRefPtr<SimpleFontData> FontCache::GetLastResortFallbackFont(
     const FontDescription& font_description,
     ShouldRetain should_retain) {
-  DEFINE_STATIC_LOCAL(AtomicString, times_str, ("Times"));
-
   // FIXME: Would be even better to somehow get the user's default font here.
   // For now we'll pick the default that the user would get without changing
   // any prefs.
   RefPtr<SimpleFontData> simple_font_data =
-      GetFontData(font_description, times_str,
+      GetFontData(font_description, FontFamilyNames::Times,
                   AlternateFontName::kAllowAlternate, should_retain);
   if (simple_font_data)
     return simple_font_data;
@@ -247,8 +244,7 @@
   // where the user doesn't have it, we fall back on Lucida Grande because
   // that's guaranteed to be there, according to Nathan Taylor. This is good
   // enough to avoid a crash at least.
-  DEFINE_STATIC_LOCAL(AtomicString, lucida_grande_str, ("Lucida Grande"));
-  return GetFontData(font_description, lucida_grande_str,
+  return GetFontData(font_description, FontFamilyNames::Lucida_Grande,
                      AlternateFontName::kAllowAlternate, should_retain);
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
index 7c27533..e67ebcb 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -96,12 +96,6 @@
     FontGlobalContext::GetHarfBuzzFontCache().erase(unique_id_);
 }
 
-static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) {
-  // We treat HarfBuzz hb_position_t as 16.16 fixed-point.
-  static constexpr int kHbPosition1 = 1 << 16;
-  return clampTo<int>(value * kHbPosition1);
-}
-
 static hb_bool_t HarfBuzzGetGlyph(hb_font_t* hb_font,
                                   void* font_data,
                                   hb_codepoint_t unicode,
@@ -149,8 +143,8 @@
   Glyph the_glyph = glyph;
   vertical_data->GetVerticalTranslationsForGlyphs(
       hb_font_data->simple_font_data_, &the_glyph, 1, result);
-  *x = SkiaScalarToHarfBuzzPosition(-result[0]);
-  *y = SkiaScalarToHarfBuzzPosition(-result[1]);
+  *x = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[0]);
+  *y = SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(-result[1]);
   return true;
 }
 
@@ -163,13 +157,14 @@
   const OpenTypeVerticalData* vertical_data =
       hb_font_data->simple_font_data_->VerticalData();
   if (!vertical_data)
-    return SkiaScalarToHarfBuzzPosition(
+    return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(
         hb_font_data->simple_font_data_->GetFontMetrics().Height());
 
   Glyph the_glyph = glyph;
   float advance_height =
       -vertical_data->AdvanceHeight(hb_font_data->simple_font_data_, the_glyph);
-  return SkiaScalarToHarfBuzzPosition(SkFloatToScalar(advance_height));
+  return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(
+      SkFloatToScalar(advance_height));
 }
 
 static hb_position_t HarfBuzzGetGlyphHorizontalKerning(
@@ -194,8 +189,8 @@
   if (typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments)) {
     SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
     SkScalar size = hb_font_data->paint_.getTextSize();
-    return SkiaScalarToHarfBuzzPosition(SkIntToScalar(kerning_adjustments[0]) *
-                                        size / upm);
+    return SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(
+        SkIntToScalar(kerning_adjustments[0]) * size / upm);
   }
 
   return 0;
@@ -343,7 +338,8 @@
   harf_buzz_font_data_->UpdateSimpleFontData(platform_data_);
 
   DCHECK(harf_buzz_font_data_->simple_font_data_);
-  int scale = SkiaScalarToHarfBuzzPosition(platform_data_->size());
+  int scale =
+      SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(platform_data_->size());
   hb_font_set_scale(unscaled_font_, scale, scale);
 
   SkTypeface* typeface = harf_buzz_font_data_->paint_.getTypeface();
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/RunSegmenterTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/RunSegmenterTest.cpp
index 11a6a12..7ea7607 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/RunSegmenterTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/RunSegmenterTest.cpp
@@ -77,17 +77,17 @@
 };
 
 // Some of our compilers cannot initialize a vector from an array yet.
-#define DECLARE_RUNSVECTOR(...)                             \
+#define DECLARE_SEGMENTER_RUNSVECTOR(...)                   \
   static const SegmenterTestRun kRunsArray[] = __VA_ARGS__; \
   Vector<SegmenterTestRun> runs;                            \
   runs.Append(kRunsArray, sizeof(kRunsArray) / sizeof(*kRunsArray));
 
-#define CHECK_RUNS_MIXED(...)      \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_RUNS_MIXED(...)                \
+  DECLARE_SEGMENTER_RUNSVECTOR(__VA_ARGS__); \
   CheckRuns(runs, FontOrientation::kVerticalMixed);
 
-#define CHECK_RUNS_HORIZONTAL(...) \
-  DECLARE_RUNSVECTOR(__VA_ARGS__); \
+#define CHECK_RUNS_HORIZONTAL(...)           \
+  DECLARE_SEGMENTER_RUNSVECTOR(__VA_ARGS__); \
   CheckRuns(runs, FontOrientation::kHorizontal);
 
 TEST_F(RunSegmenterTest, Empty) {
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
index da429606..4c30d2f 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultSpacing.h
@@ -65,6 +65,11 @@
   bool is_vertical_offset_;
 };
 
+// Forward declare so no implicit instantiations happen before the
+// first explicit instantiation (which would be a C++ violation).
+template <>
+void ShapeResultSpacing<TextRun>::SetSpacingAndExpansion(
+    const FontDescription&);
 }  // namespace blink
 
 #endif
diff --git a/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.cpp b/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.cpp
index df2ecfb..f0d04dc 100644
--- a/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.cpp
+++ b/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.cpp
@@ -11,12 +11,6 @@
 
 namespace blink {
 
-static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) {
-  // We treat HarfBuzz hb_position_t as 16.16 fixed-point.
-  static const int kHbPosition1 = 1 << 16;
-  return clampTo<int>(value * kHbPosition1);
-}
-
 SkiaTextMetrics::SkiaTextMetrics(const SkPaint* paint) : paint_(paint) {
   CHECK(paint_->getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
 }
@@ -88,4 +82,10 @@
   return SkScalarToFloat(sk_width);
 }
 
+hb_position_t SkiaTextMetrics::SkiaScalarToHarfBuzzPosition(SkScalar value) {
+  // We treat HarfBuzz hb_position_t as 16.16 fixed-point.
+  static const int kHbPosition1 = 1 << 16;
+  return clampTo<int>(value * kHbPosition1);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.h b/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.h
index 25fb260..c76f9c4 100644
--- a/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.h
+++ b/third_party/WebKit/Source/platform/fonts/skia/SkiaTextMetrics.h
@@ -22,6 +22,8 @@
   void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds);
   float GetSkiaWidthForGlyph(Glyph);
 
+  static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value);
+
  private:
   const SkPaint* paint_;
 };
diff --git a/third_party/WebKit/Source/platform/geometry/IntPoint.h b/third_party/WebKit/Source/platform/geometry/IntPoint.h
index f11a140..420e87c 100644
--- a/third_party/WebKit/Source/platform/geometry/IntPoint.h
+++ b/third_party/WebKit/Source/platform/geometry/IntPoint.h
@@ -69,8 +69,8 @@
     y_ += dy;
   }
   void SaturatedMove(int dx, int dy) {
-    x_ = SaturatedAddition(x_, dx);
-    y_ = SaturatedAddition(y_, dy);
+    x_ = ClampAdd(x_, dx);
+    y_ = ClampAdd(y_, dy);
   }
 
   void Scale(float sx, float sy) {
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTest.cpp
index c2a7b08..436069b 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTest.cpp
@@ -239,7 +239,7 @@
   decoder->ClearCacheExceptFrame(kNotFound);
 
   for (size_t i = 0; i < kNumFrames; ++i) {
-    SCOPED_TRACE(testing::Message() << i);
+    SCOPED_TRACE(::testing::Message() << i);
     EXPECT_EQ(ImageFrame::kFrameEmpty, frame_buffers[i].GetStatus());
   }
 }
@@ -256,7 +256,7 @@
   decoder->ResetRequiredPreviousFrames();
   decoder->ClearCacheExceptFrame(5);
   for (size_t i = 0; i < kNumFrames; ++i) {
-    SCOPED_TRACE(testing::Message() << i);
+    SCOPED_TRACE(::testing::Message() << i);
     if (i == 5)
       EXPECT_EQ(ImageFrame::kFrameComplete, frame_buffers[i].GetStatus());
     else
diff --git a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.cpp b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.cpp
index 23627c7..68d5b7d 100644
--- a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.cpp
+++ b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.cpp
@@ -33,22 +33,14 @@
 
   service_.set_connection_error_handler(
       ConvertToBaseCallback(WTF::Bind(&onConnectionError)));
-
-  resource_coordinator::mojom::blink::EventPtr event =
-      resource_coordinator::mojom::blink::Event::New();
-  event->type = resource_coordinator::mojom::EventType::kOnRendererFrameCreated;
-  service_->SendEvent(std::move(event));
 }
 
 FrameResourceCoordinator::~FrameResourceCoordinator() = default;
 
-void FrameResourceCoordinator::SendEvent(
-    const resource_coordinator::mojom::blink::EventType& event_type) {
-  resource_coordinator::mojom::blink::EventPtr event =
-      resource_coordinator::mojom::blink::Event::New();
-  event->type = event_type;
-
-  service_->SendEvent(std::move(event));
+void FrameResourceCoordinator::SetProperty(
+    const resource_coordinator::mojom::blink::PropertyType property_type,
+    const bool value) {
+  service_->SetProperty(property_type, base::MakeUnique<base::Value>(value));
 }
 
 DEFINE_TRACE(FrameResourceCoordinator) {}
diff --git a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.h b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.h
index 810706f09..fa58ec7 100644
--- a/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.h
+++ b/third_party/WebKit/Source/platform/instrumentation/resource_coordinator/FrameResourceCoordinator.h
@@ -22,7 +22,8 @@
   static bool IsEnabled();
   static FrameResourceCoordinator* Create(service_manager::InterfaceProvider*);
   virtual ~FrameResourceCoordinator();
-  void SendEvent(const resource_coordinator::mojom::blink::EventType&);
+  void SetProperty(const resource_coordinator::mojom::blink::PropertyType,
+                   const bool);
 
   DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
index dd6c295..7a35234 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -836,7 +836,18 @@
   //
   // request_initiator_context is benign (indicates document vs. worker).
 
-  if (new_options.synchronous_policy != options_.synchronous_policy)
+  // Reuse only if both the existing Resource and the new request are
+  // asynchronous. Particularly,
+  // 1. Sync and async Resource/requests shouldn't be mixed (crbug.com/652172),
+  // 2. Sync existing Resources shouldn't be revalidated, and
+  // 3. Sync new requests shouldn't revalidate existing Resources.
+  //
+  // 2. and 3. are because SyncResourceHandler handles redirects without
+  // calling WillFollowRedirect, and causes response URL mismatch
+  // (crbug.com/618967) and bypassing redirect restriction around revalidation
+  // (crbug.com/613971 for 2. and crbug.com/614989 for 3.).
+  if (new_options.synchronous_policy == kRequestSynchronously ||
+      options_.synchronous_policy == kRequestSynchronously)
     return false;
 
   if (resource_request_.GetKeepalive() || new_request.GetKeepalive()) {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
index 0108188..95f5d2d4 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -19,6 +19,8 @@
 #include "platform/scheduler/base/work_queue_sets.h"
 #include "platform/wtf/PtrUtil.h"
 
+static const double kLongTaskTraceEventThreshold = 0.05;
+
 namespace blink {
 namespace scheduler {
 
@@ -535,11 +537,11 @@
 
   currently_executing_task_queue_ = prev_executing_task_queue;
 
-
+  double task_end_time = 0;
   if (queue->GetShouldNotifyObservers()) {
     if (task_start_time) {
       *time_after_task = real_time_domain()->Now();
-      double task_end_time = MonotonicTimeInSeconds(*time_after_task);
+      task_end_time = MonotonicTimeInSeconds(*time_after_task);
 
       queue->OnTaskCompleted(
           base::TimeTicks() + base::TimeDelta::FromSecondsD(task_start_time),
@@ -554,6 +556,12 @@
     queue->NotifyDidProcessTask(pending_task);
   }
 
+  if (task_start_time && task_end_time &&
+      task_end_time - task_start_time > kLongTaskTraceEventThreshold) {
+    TRACE_EVENT_INSTANT1("blink", "LongTask", TRACE_EVENT_SCOPE_THREAD,
+                         "duration", task_end_time - task_start_time);
+  }
+
   return ProcessTaskResult::EXECUTED;
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
index 9bf2ad2..2a6584d0 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
@@ -220,10 +220,10 @@
   selector_.EnableQueue(task_queues_[2].get());
   selector_.SetQueuePriority(task_queues_[2].get(),
                              TaskQueue::BEST_EFFORT_PRIORITY);
-  EXPECT_THAT(PopTasks(), testing::ElementsAre(2));
+  EXPECT_THAT(PopTasks(), ::testing::ElementsAre(2));
   task_queues_[4]->SetQueueEnabledForTest(true);
   selector_.EnableQueue(task_queues_[4].get());
-  EXPECT_THAT(PopTasks(), testing::ElementsAre(4));
+  EXPECT_THAT(PopTasks(), ::testing::ElementsAre(4));
 }
 
 TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) {
diff --git a/third_party/WebKit/Source/platform/text/SuffixTree.h b/third_party/WebKit/Source/platform/text/SuffixTree.h
index 2723d546..1caf5269 100644
--- a/third_party/WebKit/Source/platform/text/SuffixTree.h
+++ b/third_party/WebKit/Source/platform/text/SuffixTree.h
@@ -26,6 +26,9 @@
 #ifndef SuffixTree_h
 #define SuffixTree_h
 
+#include <algorithm>
+#include <utility>
+
 #include "platform/wtf/Allocator.h"
 #include "platform/wtf/Noncopyable.h"
 #include "platform/wtf/Vector.h"
@@ -63,9 +66,10 @@
     Node* current = &root_;
     int limit = std::min(depth_, query.length());
     for (int i = 0; i < limit; ++i) {
-      current = current->at(Codebook::CodeWord(query[i]));
-      if (!current)
+      auto iter = current->Find(Codebook::CodeWord(query[i]));
+      if (iter == current->End())
         return false;
+      current = iter->second;
     }
     return true;
   }
@@ -76,27 +80,39 @@
     WTF_MAKE_NONCOPYABLE(Node);
 
    public:
-    Node(bool is_leaf = false) {
-      children_.resize(Codebook::kCodeSize);
-      children_.Fill(0);
-      is_leaf_ = is_leaf;
-    }
+    Node(bool is_leaf = false) : is_leaf_(is_leaf) {}
 
     ~Node() {
-      for (unsigned i = 0; i < children_.size(); ++i) {
-        Node* child = children_.at(i);
+      for (const auto& pair : children_) {
+        Node* child = pair.second;
         if (child && !child->is_leaf_)
           delete child;
       }
     }
 
-    Node*& at(int code_word) { return children_.at(code_word); }
+    Node*& At(int key) {
+      auto it = Find(key);
+      if (it != children_.end())
+        return it->second;
+      children_.emplace_back(key, nullptr);
+      return children_.back().second;
+    }
+
+    typename Vector<std::pair<int, Node*>>::iterator Find(int key) {
+      return std::find_if(children_.begin(), children_.end(),
+                          [key](const std::pair<int, Node*>& entry) {
+                            return entry.first == key;
+                          });
+    }
+
+    typename Vector<std::pair<int, Node*>>::iterator End() {
+      return children_.end();
+    }
 
    private:
-    typedef Vector<Node*, Codebook::kCodeSize> ChildrenVector;
-
-    ChildrenVector children_;
-    bool is_leaf_;
+    // TODO(tsepez): convert to base::flat_map when allowed in blink.
+    Vector<std::pair<int, Node*>> children_;
+    const bool is_leaf_;
   };
 
   void Build(const String& text) {
@@ -105,7 +121,7 @@
       unsigned limit = std::min(base + depth_, text.length());
       for (unsigned offset = 0; base + offset < limit; ++offset) {
         DCHECK_NE(current, &leaf_);
-        Node*& child = current->at(Codebook::CodeWord(text[base + offset]));
+        Node*& child = current->At(Codebook::CodeWord(text[base + offset]));
         if (!child)
           child = base + offset + 1 == limit ? &leaf_ : new Node();
         current = child;
diff --git a/third_party/WebKit/Source/platform/text/SuffixTreeTest.cpp b/third_party/WebKit/Source/platform/text/SuffixTreeTest.cpp
new file mode 100644
index 0000000..b1348c2
--- /dev/null
+++ b/third_party/WebKit/Source/platform/text/SuffixTreeTest.cpp
@@ -0,0 +1,32 @@
+// 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 "platform/text/SuffixTree.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+
+TEST(SuffixTreeTest, EmptyString) {
+  SuffixTree<ASCIICodebook> tree("", 16);
+  EXPECT_TRUE(tree.MightContain(""));
+  EXPECT_FALSE(tree.MightContain("potato"));
+}
+
+TEST(SuffixTreeTest, NormalString) {
+  SuffixTree<ASCIICodebook> tree("banana", 16);
+  EXPECT_TRUE(tree.MightContain(""));
+  EXPECT_TRUE(tree.MightContain("a"));
+  EXPECT_TRUE(tree.MightContain("na"));
+  EXPECT_TRUE(tree.MightContain("ana"));
+  EXPECT_TRUE(tree.MightContain("nana"));
+  EXPECT_TRUE(tree.MightContain("anana"));
+  EXPECT_TRUE(tree.MightContain("banana"));
+  EXPECT_FALSE(tree.MightContain("ab"));
+  EXPECT_FALSE(tree.MightContain("bananan"));
+  EXPECT_FALSE(tree.MightContain("abanana"));
+  EXPECT_FALSE(tree.MightContain("potato"));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/weborigin/KURL.h b/third_party/WebKit/Source/platform/weborigin/KURL.h
index 2ed5360..26e4d1e 100644
--- a/third_party/WebKit/Source/platform/weborigin/KURL.h
+++ b/third_party/WebKit/Source/platform/weborigin/KURL.h
@@ -36,6 +36,28 @@
 #include "url/third_party/mozilla/url_parse.h"
 #include "url/url_canon.h"
 
+// KURL is Blink's main URL class, and is the analog to GURL in other Chromium
+// code. It is not thread safe but is generally cheap to copy and compare KURLs
+// to each other.
+//
+// KURL and GURL both share the same underlying URL parser, whose code is
+// located in //url, but KURL is backed by Blink specific WTF::Strings. This
+// means that KURLs are usually cheap to copy due to WTF::Strings being
+// internally ref-counted. However, please don't copy KURLs if you can use a
+// const ref, since the size of the parsed structure and related metadata is
+// non-trivial.
+//
+// In fact, for the majority of KURLs (i.e. those not copied across threads),
+// the backing string is an AtomicString, meaning that it is stored in the
+// thread-local AtomicString table, allowing optimizations like fast comparison.
+// See platform/wtf/text/AtomicString.h for information on the performance
+// characteristics of AtomicStrings.
+//
+// KURL also has a few other optimizations, including:
+//  - Cached bit for whether the KURL is http/https
+//  - Internal reference to the URL protocol (scheme) to avoid String allocation
+//    for the callers that require it. Common protocols like http and https are
+//    stored as static strings which can be shared across threads.
 namespace WTF {
 class TextEncoding;
 }
diff --git a/third_party/WebKit/Source/platform/wtf/SaturatedArithmetic.h b/third_party/WebKit/Source/platform/wtf/SaturatedArithmetic.h
index c85f2916..11ca582 100644
--- a/third_party/WebKit/Source/platform/wtf/SaturatedArithmetic.h
+++ b/third_party/WebKit/Source/platform/wtf/SaturatedArithmetic.h
@@ -31,18 +31,19 @@
 #ifndef SaturatedArithmetic_h
 #define SaturatedArithmetic_h
 
+#include "base/numerics/clamped_math.h"
 #include "base/numerics/saturated_arithmetic.h"
 
 namespace WTF {
-using base::SaturatedAddition;
-using base::SaturatedSubtraction;
-using base::SaturatedNegative;
+using base::ClampAdd;
+using base::ClampSub;
+using base::MakeClampedNum;
 using base::SaturatedSet;
 }  // namespace WTF
 
-using WTF::SaturatedAddition;
-using WTF::SaturatedSubtraction;
-using WTF::SaturatedNegative;
+using WTF::ClampAdd;
+using WTF::ClampSub;
+using WTF::MakeClampedNum;
 using WTF::SaturatedSet;
 
 #endif  // SaturatedArithmetic_h
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index d1fe40c6..93446f5 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -175,7 +175,15 @@
 
     def additional_driver_flag(self):
         if self.driver_name() == self.CONTENT_SHELL_NAME:
-            return ['--run-layout-test']
+            # This is the fingerprint of wpt's certificate found in thirdparty/wpt/certs. Use
+            #
+            #   openssl x509 -noout -pubkey -in 127.0.0.1.pem |
+            #   openssl pkey -pubin -outform der |
+            #   openssl dgst -sha256 -binary |
+            #   base64
+            #
+            # to regenerate.
+            return ['--run-layout-test', '--ignore-certificate-errors-spki-list=Nxvaj3+bY3oVrTc+Jp7m3E3sB1n3lXtnMDCyBsqEXiY=']
         return []
 
     def supports_per_test_timeout(self):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
index 25bb5a7..097417da 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_exporter.py
@@ -238,7 +238,10 @@
                 'the WPT Importer is blocked from operating.\n\n'
                 '(There is ongoing work to 1. prevent CLs with red upstream PRs from landing '
                 '(https://crbug.com/711447) and 2. prevent the importer from being blocked on '
-                'stuck exportable changes (https://crbug.com/734121))'
+                'stuck exportable changes (https://crbug.com/734121))\n\n'
+                'WPT Export docs:\n'
+                'https://chromium.googlesource.com/chromium/src/+/master'
+                '/docs/testing/web_platform_tests.md#Automatic-export-process'
             ).format(
                 pr_url='%spull/%d' % (WPT_GH_URL, response_data['number'])
             ))
diff --git a/third_party/WebKit/public/platform/WebContentDecryptionModule.h b/third_party/WebKit/public/platform/WebContentDecryptionModule.h
index 11f96c7..fc25730 100644
--- a/third_party/WebKit/public/platform/WebContentDecryptionModule.h
+++ b/third_party/WebKit/public/platform/WebContentDecryptionModule.h
@@ -31,6 +31,8 @@
 #ifndef WebContentDecryptionModule_h
 #define WebContentDecryptionModule_h
 
+#include <memory>
+
 #include "public/platform/WebContentDecryptionModuleResult.h"
 #include "public/platform/WebContentDecryptionModuleSession.h"
 
@@ -41,7 +43,8 @@
   virtual ~WebContentDecryptionModule();
 
   // Must return non-null.
-  virtual WebContentDecryptionModuleSession* CreateSession() = 0;
+  virtual std::unique_ptr<WebContentDecryptionModuleSession>
+  CreateSession() = 0;
 
   virtual void SetServerCertificate(const unsigned char* certificate,
                                     size_t certificate_length,
diff --git a/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt b/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt
index 04d47f04..9200f48 100644
--- a/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt
+++ b/third_party/gvr-android-sdk/test-apks/daydream_home/apk_version_history.txt
@@ -6,3 +6,4 @@
 v1.4 9afe32eb4676d4bcceae81605a3be6aa0e5be3d5
 v1.5 a02e2f95aa6f741f2be0ae03a4829e21fd749cf3
 v1.6 43b876df3398687dfa1ae059ef2f64009c76254e
+v1.7 d5c72438acffe723e7717c45deedd8431bc613e7
diff --git a/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1 b/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1
index 5c6216fb6..31836cd7 100644
--- a/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1
+++ b/third_party/gvr-android-sdk/test-apks/daydream_home/daydream_home_current.apk.sha1
@@ -1 +1 @@
-43b876df3398687dfa1ae059ef2f64009c76254e
\ No newline at end of file
+d5c72438acffe723e7717c45deedd8431bc613e7
\ No newline at end of file
diff --git a/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt b/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt
index 7b87608..4831ae6 100644
--- a/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt
+++ b/third_party/gvr-android-sdk/test-apks/vr_services/apk_version_history.txt
@@ -9,3 +9,4 @@
 v1.4 3e0cc24655847c7b922149754324a189e7092310
 v1.5 5d6d55728c7c728cef5416f37b0b71615719474e
 v1.6 abcdae2281956a76aa3b98d2e8f05a1975170dd0
+v1.7 fcfa178173a2c0cab9c7d51829c2ee76ab66e1d9
diff --git a/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1 b/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1
index 2877b099..fb68207 100644
--- a/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1
+++ b/third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk.sha1
@@ -1 +1 @@
-abcdae2281956a76aa3b98d2e8f05a1975170dd0
\ No newline at end of file
+fcfa178173a2c0cab9c7d51829c2ee76ab66e1d9
\ No newline at end of file
diff --git a/tools/copyright_scanner/OWNERS b/tools/copyright_scanner/OWNERS
deleted file mode 100644
index 90a3cbe..0000000
--- a/tools/copyright_scanner/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-phajdan.jr@chromium.org
-sgurun@chromium.org
-torne@chromium.org
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 756d74f..2edf298 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -259,7 +259,8 @@
       'GPU Win x64 Builder': 'gpu_tests_deqp_gles_release_trybot',
       'GPU Win x64 Builder (dbg)': 'gpu_tests_deqp_gles_debug_trybot',
       'Linux ChromiumOS Builder': 'gpu_fyi_tests_chromeos_release_trybot',
-      'Linux ChromiumOS Ozone Builder': 'gpu_fyi_tests_chromeos_release_trybot',
+      # This is, confusingly, apparently not actually building ChromiumOS.
+      'Linux ChromiumOS Ozone Builder': 'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot',
       'Linux GPU TSAN Release': 'gpu_fyi_tests_release_trybot_tsan',
       'Mac GPU ASAN Release': 'gpu_fyi_tests_release_trybot_asan',
     },
@@ -1234,6 +1235,10 @@
       'gpu_fyi_tests', 'debug_trybot',
     ],
 
+    'gpu_fyi_tests_ozone_linux_system_gbm_libdrm_release_trybot': [
+      'gpu_fyi_tests', 'ozone_linux', 'system_gbm_libdrm', 'release_trybot',
+    ],
+
     'gpu_fyi_tests_release_trybot': [
       'gpu_fyi_tests', 'release_trybot',
     ],
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 389d9cc..5ec7b17 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -68709,6 +68709,36 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchTapDurationNotSeen" units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration of a tap that triggered a Contextual Search when the user does
+    not open the panel. Implemented for Android.  Logged when the panel closes
+    after being triggered by a tap.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchTapDurationSeen" units="ms">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The duration of a tap that triggered a Contextual Search when the user does
+    open the panel. Implemented for Android.  Logged when the panel closes after
+    being triggered by a tap and subsequently opened.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchTapLongDurationSeen"
+    enum="ContextualSearchResultsSeen">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether results were seen for a Tap that was of long duration. Recorded when
+    the UX is hidden. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchTapLongWordSeen"
     enum="ContextualSearchResultsSeen">
   <owner>donnd@chromium.org</owner>
@@ -68719,6 +68749,16 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchTapShortDurationSeen"
+    enum="ContextualSearchResultsSeen">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether results were seen for a Tap that was of short duration. Recorded
+    when the UX is hidden. Implemented for Android.
+  </summary>
+</histogram>
+
 <histogram name="Search.ContextualSearchTapShortWordSeen"
     enum="ContextualSearchResultsSeen">
   <owner>donnd@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index 951ca4ef..271b3175 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -278,67 +278,61 @@
     Ranker.  These metrics are recorded each time the user triggers the
     Contextual Search UI via a tap gesture (when enabled).
   </summary>
-  <metric name="DURATION_AFTER_SCROLL_MS">
+  <metric name="DurationAfterScrollMs">
     <summary>
       Duration in MS between showing the UI and a subsequent scroll event, or
       not recorded if there was no subsequent scroll.
     </summary>
   </metric>
-  <metric name="DURATION_BEFORE_SCROLL_MS">
-    <summary>
-      Duration in MS between showing the most recent scroll event and showing
-      the UI, or 0 if no previous scroll event occurred.
-    </summary>
-  </metric>
-  <metric name="OUTCOME_WAS_PANEL_OPENED">
+  <metric name="OutcomeWasPanelOpened">
     <summary>
       Whether the user opened the overlay panel.  This is the primary outcome
       metric.
     </summary>
   </metric>
-  <metric name="OUTCOME_WAS_QUICK_ACTION_CLICKED">
+  <metric name="OutcomeWasQuickActionClicked">
     <summary>
       Whether the user clicked within the overlay panel when a Quick-Action was
       shown.  This is a secondary outcome metric.
     </summary>
   </metric>
-  <metric name="OUTCOME_WAS_QUICK_ANSWER_SEEN">
+  <metric name="OutcomeWasQuickAnswerSeen">
     <summary>
       Whether the user could see a Quick-Answer caption within the overlay
       panel.  This is a tertiary outcome metric.
     </summary>
   </metric>
-  <metric name="PREVIOUS_28DAY_CTR_PERCENT">
+  <metric name="Previous28DayCtrPercent">
     <summary>
       The CTR of the overlay panel for this user, aggregated over a previous 28
       day period, expressed as an integer between 0-99.
     </summary>
   </metric>
-  <metric name="PREVIOUS_28DAY_IMPRESSIONS_COUNT">
+  <metric name="Previous28DayImpressionsCount">
     <summary>
       The count of views of the overlay panel for this user, aggregated over a
       previous 28 day period.
     </summary>
   </metric>
-  <metric name="PREVIOUS_WEEK_CTR_PERCENT">
+  <metric name="PreviousWeekCtrPercent">
     <summary>
       The CTR of the overlay panel for this user, aggregated over the previous
       week, expressed as an integer between 0-99.
     </summary>
   </metric>
-  <metric name="PREVIOUS_WEEK_IMPRESSIONS_COUNT">
+  <metric name="PreviousWeekImpressionsCount">
     <summary>
       The count of views of the overlay panel for this user, aggregated over the
       previous week.
     </summary>
   </metric>
-  <metric name="SCREEN_TOP_DPS">
+  <metric name="ScreenTopDps">
     <summary>
       The location of the tap relative to the top of the screen, expressed in
       DPs.
     </summary>
   </metric>
-  <metric name="WAS_SCREEN_BOTTOM">
+  <metric name="WasScreenBottom">
     <summary>
       The location of the tap relative to the bottom of the screen, expressed as
       an integer with 0 meaning not at the bottom and 1 meaning at the bottom.
diff --git a/tools/perf/benchmarks/battor.py b/tools/perf/benchmarks/battor.py
index 3480b0c..b6bf1df 100644
--- a/tools/perf/benchmarks/battor.py
+++ b/tools/perf/benchmarks/battor.py
@@ -13,7 +13,7 @@
 # are the primary means of benchmarking power.
 class _BattOrBenchmark(perf_benchmark.PerfBenchmark):
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter(
         filter_string='toplevel')
     options = timeline_based_measurement.Options(category_filter)
diff --git a/tools/perf/benchmarks/blob_storage.py b/tools/perf/benchmarks/blob_storage.py
index 40e2f13..05b8ad2 100644
--- a/tools/perf/benchmarks/blob_storage.py
+++ b/tools/perf/benchmarks/blob_storage.py
@@ -21,7 +21,7 @@
 
   page_set = page_sets.BlobWorkshopPageSet
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
     cat_filter.AddIncludedCategory(BLOB_CATEGORY)
     cat_filter.AddIncludedCategory(TIMELINE_REQUIRED_CATEGORY)
diff --git a/tools/perf/benchmarks/indexeddb_perf.py b/tools/perf/benchmarks/indexeddb_perf.py
index d04c88d..a065ddd 100644
--- a/tools/perf/benchmarks/indexeddb_perf.py
+++ b/tools/perf/benchmarks/indexeddb_perf.py
@@ -107,7 +107,7 @@
   """IndexedDB Performance tests that use tracing."""
   page_set = page_sets.IndexedDBEndurePageSet
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     cat_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
     cat_filter.AddIncludedCategory(IDB_CATEGORY)
     cat_filter.AddIncludedCategory(TIMELINE_REQUIRED_CATEGORY)
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py
index 0c217119..fdbff12 100644
--- a/tools/perf/benchmarks/loading.py
+++ b/tools/perf/benchmarks/loading.py
@@ -17,7 +17,7 @@
 
   options = {'pageset_repeat': 2}
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     tbm_options = timeline_based_measurement.Options()
     loading_metrics_category.AugmentOptionsForLoadingMetrics(tbm_options)
     return tbm_options
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py
index 4200606..3b1e09d 100644
--- a/tools/perf/benchmarks/media.py
+++ b/tools/perf/benchmarks/media.py
@@ -92,7 +92,7 @@
   def CreateStorySet(self, options):
     return page_sets.ToughVideoCasesPageSet(measure_memory=True)
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     category_filter = chrome_trace_category_filter.ChromeTraceCategoryFilter()
 
     # 'toplevel' category provides CPU time slices used by # cpuTimeMetric.
diff --git a/tools/perf/benchmarks/memory.py b/tools/perf/benchmarks/memory.py
index cea629c..4824036 100644
--- a/tools/perf/benchmarks/memory.py
+++ b/tools/perf/benchmarks/memory.py
@@ -27,7 +27,7 @@
   is part of chrome tracing, and extracts it using timeline-based measurements.
   """
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     # Enable only memory-infra, to get memory dumps, and blink.console, to get
     # the timeline markers used for mapping threads to tabs.
     trace_memory = chrome_trace_category_filter.ChromeTraceCategoryFilter(
@@ -161,7 +161,7 @@
       r'renderer_processes:'
       r'(reported_by_chrome:v8|reported_by_os:system_memory:[^:]+$)')
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     v8_categories = [
         'blink.console', 'renderer.scheduler', 'v8', 'webkit.console']
     memory_categories = ['blink.console', 'disabled-by-default-memory-infra']
diff --git a/tools/perf/benchmarks/oopif.py b/tools/perf/benchmarks/oopif.py
index a657346a..413f1b09 100644
--- a/tools/perf/benchmarks/oopif.py
+++ b/tools/perf/benchmarks/oopif.py
@@ -15,7 +15,7 @@
 class _OopifBase(perf_benchmark.PerfBenchmark):
   options = {'pageset_repeat': 2}
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     tbm_options = timeline_based_measurement.Options()
     loading_metrics_category.AugmentOptionsForLoadingMetrics(tbm_options)
     return tbm_options
diff --git a/tools/perf/benchmarks/oortonline.py b/tools/perf/benchmarks/oortonline.py
index f6a98a0..f335f04 100644
--- a/tools/perf/benchmarks/oortonline.py
+++ b/tools/perf/benchmarks/oortonline.py
@@ -79,7 +79,7 @@
         pass # http://oortonline.gl/#run not disabled.
     return StoryExpectations()
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
       # Implicitly disable all categories.
       '-*',
diff --git a/tools/perf/benchmarks/power.py b/tools/perf/benchmarks/power.py
index ee78b23f..7a98df2a 100644
--- a/tools/perf/benchmarks/power.py
+++ b/tools/perf/benchmarks/power.py
@@ -76,7 +76,7 @@
   Our power benchmarks are prone to noise caused by other things running on the
   system. This benchmark is intended to help find the sources of noise.
   """
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options(
         chrome_trace_category_filter.ChromeTraceCategoryFilter())
     options.config.enable_battor_trace = True
diff --git a/tools/perf/benchmarks/start_with_url.py b/tools/perf/benchmarks/start_with_url.py
index 56d23c3..ec426fe 100644
--- a/tools/perf/benchmarks/start_with_url.py
+++ b/tools/perf/benchmarks/start_with_url.py
@@ -19,7 +19,7 @@
         '--enable-stats-collection-bindings'
     ])
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     startup_category_filter = (
         chrome_trace_category_filter.ChromeTraceCategoryFilter(
             filter_string='startup,blink.user_timing'))
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index c5a8dab..e0515f8 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -33,7 +33,7 @@
   https://goo.gl/Jek2NL.
   """
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options(
         chrome_trace_category_filter.ChromeTraceCategoryFilter(
             filter_string='rail,toplevel'))
@@ -97,7 +97,7 @@
   """
   options = {'pageset_repeat': 3}
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options(
         chrome_trace_category_filter.ChromeTraceCategoryFilter(
             '-*,disabled-by-default-memory-infra'))
@@ -178,7 +178,7 @@
   def GetExpectations(self):
     return page_sets.SystemHealthWebviewStartupExpectations()
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options()
     options.SetTimelineBasedMetrics(['webviewStartupMetric'])
     options.config.enable_atrace_trace = True
diff --git a/tools/perf/benchmarks/tracing.py b/tools/perf/benchmarks/tracing.py
index 7e39d103..10d12c6d 100644
--- a/tools/perf/benchmarks/tracing.py
+++ b/tools/perf/benchmarks/tracing.py
@@ -20,7 +20,7 @@
 
   page_set = page_sets.Top10PageSet
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     options = timeline_based_measurement.Options(
         timeline_based_measurement.DEBUG_OVERHEAD_LEVEL)
     options.SetTimelineBasedMetrics(['tracingMetric'])
@@ -45,7 +45,7 @@
   """Measures the overhead of background memory-infra dumps"""
   page_set = page_sets.Top10PageSet
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     # Enable only memory-infra category with periodic background mode dumps
     # every 200 milliseconds.
     trace_memory = chrome_trace_category_filter.ChromeTraceCategoryFilter(
diff --git a/tools/perf/benchmarks/v8.py b/tools/perf/benchmarks/v8.py
index f5d8241..4e46990 100644
--- a/tools/perf/benchmarks/v8.py
+++ b/tools/perf/benchmarks/v8.py
@@ -46,7 +46,7 @@
     options.AppendExtraBrowserArgs(
       '--enable-blink-features=BlinkRuntimeCallStats')
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     # TODO(fmeawad): most of the cat_filter information is extracted from
     # page_cycler_v2 TimelineBasedMeasurementOptionsForLoadingMetric because
     # used by the loadingMetric because the runtimeStatsMetric uses the
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index 40fd920..d8b40ed 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -53,7 +53,7 @@
   See browsing_stories._BrowsingStory for workload description.
   """
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
       # Disable all categories by default.
       '-*',
@@ -109,7 +109,7 @@
   See browsing_stories._BrowsingStory for workload description.
   """
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
       # Disable all categories by default.
       '-*',
diff --git a/tools/perf/benchmarks/webrtc.py b/tools/perf/benchmarks/webrtc.py
index ffc2e453..b74a749 100644
--- a/tools/perf/benchmarks/webrtc.py
+++ b/tools/perf/benchmarks/webrtc.py
@@ -21,7 +21,7 @@
   def Name(cls):
     return 'webrtc'
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     categories = [
         # Disable all categories by default.
         '-*',
diff --git a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
index da191a9..29588dc 100644
--- a/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
+++ b/tools/perf/contrib/cros_benchmarks/page_cycler_v2.py
@@ -19,7 +19,7 @@
 class _PageCyclerV2(perf_benchmark.PerfBenchmark):
   options = {'pageset_repeat': 2}
 
-  def CreateTimelineBasedMeasurementOptions(self):
+  def CreateCoreTimelineBasedMeasurementOptions(self):
     tbm_options = timeline_based_measurement.Options()
     loading_metrics_category.AugmentOptionsForLoadingMetrics(tbm_options)
     return tbm_options
diff --git a/tools/ubsan/vptr_blacklist.txt b/tools/ubsan/vptr_blacklist.txt
index 755a48e..c88a77b 100644
--- a/tools/ubsan/vptr_blacklist.txt
+++ b/tools/ubsan/vptr_blacklist.txt
@@ -99,7 +99,7 @@
 #############################################################################
 # LLVM is not UBSan vptr clean.
 src:*third_party/swiftshader/third_party/LLVM*
-src:*third_party/swiftshader/third_party/llvm-subzero*
+src:*third_party/swiftshader/third_party/llvm\-subzero*
 
 #############################################################################
 # UBSan yields false positives in SwiftShader's libEGL when objects created in
diff --git a/ui/android/java/src/org/chromium/ui/UiUtils.java b/ui/android/java/src/org/chromium/ui/UiUtils.java
index 59cfb82..2d36381 100644
--- a/ui/android/java/src/org/chromium/ui/UiUtils.java
+++ b/ui/android/java/src/org/chromium/ui/UiUtils.java
@@ -22,7 +22,7 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodSubtype;
-import android.widget.LinearLayout;
+import android.widget.AbsListView;
 import android.widget.ListAdapter;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -429,8 +429,8 @@
     public static int computeMaxWidthOfListAdapterItems(ListAdapter adapter) {
         final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
-                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+        AbsListView.LayoutParams params = new AbsListView.LayoutParams(
+                AbsListView.LayoutParams.WRAP_CONTENT, AbsListView.LayoutParams.WRAP_CONTENT);
 
         int maxWidth = 0;
         View[] itemViews = new View[adapter.getViewTypeCount()];
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index 0ad11643..465478a 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -289,6 +289,7 @@
     ]
     deps += [
       "//ui/accessibility",
+      "//ui/app_list/vector_icons",
       "//ui/views",
       "//ui/views:test_support",
     ]
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index 12c3ad2..d97a15dc 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -127,6 +127,12 @@
 const int kSearchBoxTopPadding = 24;
 const int kSearchBoxBottomPadding = 21;
 
+// The preferred height of the search box.
+const int kSearchBoxPreferredHeight = 48;
+
+// The background border corner radius of the search box in fullscreen mode.
+const int kSearchBoxBorderCornerRadiusFullscreen = 24;
+
 // Max items allowed in a folder.
 size_t kMaxFolderItems = 16;
 
@@ -160,6 +166,14 @@
 // The height of tiles in search result.
 const int kSearchTileHeight = 92;
 
+// The size of the search icon in the search box.
+const int kSearchIconSize = 24;
+
+// Default color used when wallpaper customized color is not available for
+// searchbox, #000 at 87% opacity.
+const SkColor kDefaultSearchboxColor =
+    SkColorSetARGBMacro(0xDE, 0x00, 0x00, 0x00);
+
 gfx::ShadowValue GetShadowForZHeight(int z_height) {
   if (z_height <= 0)
     return gfx::ShadowValue();
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index 807a31e..36d0be2 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -96,6 +96,8 @@
 APP_LIST_EXPORT extern const int kSearchBoxPadding;
 APP_LIST_EXPORT extern const int kSearchBoxTopPadding;
 APP_LIST_EXPORT extern const int kSearchBoxBottomPadding;
+APP_LIST_EXPORT extern const int kSearchBoxPreferredHeight;
+APP_LIST_EXPORT extern const int kSearchBoxBorderCornerRadiusFullscreen;
 
 APP_LIST_EXPORT extern size_t kMaxFolderItems;
 APP_LIST_EXPORT extern const size_t kNumFolderTopItems;
@@ -110,6 +112,9 @@
 
 APP_LIST_EXPORT extern const int kSearchTileHeight;
 
+APP_LIST_EXPORT extern const int kSearchIconSize;
+APP_LIST_EXPORT extern const SkColor kDefaultSearchboxColor;
+
 // Returns the shadow values for a view at |z_height|.
 APP_LIST_EXPORT gfx::ShadowValue GetShadowForZHeight(int z_height);
 
diff --git a/ui/app_list/test/app_list_test_view_delegate.cc b/ui/app_list/test/app_list_test_view_delegate.cc
index 9202127b..6133b93 100644
--- a/ui/app_list/test/app_list_test_view_delegate.cc
+++ b/ui/app_list/test/app_list_test_view_delegate.cc
@@ -89,5 +89,9 @@
   model_->PopulateApps(item_count);
 }
 
+void AppListTestViewDelegate::SetSearchEngineIsGoogle(bool is_google) {
+  model_->SetSearchEngineIsGoogle(is_google);
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/test/app_list_test_view_delegate.h b/ui/app_list/test/app_list_test_view_delegate.h
index 5cafa04f..d3d73afb 100644
--- a/ui/app_list/test/app_list_test_view_delegate.h
+++ b/ui/app_list/test/app_list_test_view_delegate.h
@@ -47,6 +47,9 @@
   // value to 0.
   int GetStopSpeechRecognitionCountAndReset();
 
+  // Sets whether the search engine is Google or not.
+  void SetSearchEngineIsGoogle(bool is_google);
+
   // AppListViewDelegate overrides:
   AppListModel* GetModel() override;
   SpeechUIModel* GetSpeechUI() override;
diff --git a/ui/app_list/vector_icons/BUILD.gn b/ui/app_list/vector_icons/BUILD.gn
index 9951785..c0f775f 100644
--- a/ui/app_list/vector_icons/BUILD.gn
+++ b/ui/app_list/vector_icons/BUILD.gn
@@ -22,6 +22,8 @@
     "ic_google_black.icon",
     "ic_mic_black.1x.icon",
     "ic_mic_black.icon",
+    "ic_search_engine_not_google.1x.icon",
+    "ic_search_engine_not_google.icon",
   ]
 }
 
diff --git a/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon b/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon
new file mode 100644
index 0000000..5606e25c
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_search_engine_not_google.1x.icon
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+CANVAS_DIMENSIONS, 24,
+MOVE_TO, 15.5f, 14,
+LINE_TO, 14.71f, 14,
+LINE_TO, 14.43f, 13.73f,
+CUBIC_TO, 15.41f, 12.59f, 16, 11.11f, 16, 9.5f,
+CUBIC_TO, 16, 5.91f, 13.09f, 3, 9.5f, 3,
+CUBIC_TO, 5.91f, 3, 3, 5.91f, 3, 9.5f,
+CUBIC_TO, 3, 13.09f, 5.91f, 16, 9.5f, 16,
+CUBIC_TO, 11.11f, 16, 12.59f, 15.41f, 13.73f, 14.43f,
+LINE_TO, 14, 14.71f,
+LINE_TO, 14, 15.5f,
+LINE_TO, 19, 20.49f,
+LINE_TO, 20.49f, 19,
+LINE_TO, 15.5f, 14,
+CLOSE,
+MOVE_TO, 9.5f, 14,
+CUBIC_TO, 7.01f, 14, 5, 11.99f, 5, 9.5f,
+CUBIC_TO, 5, 7.01f, 7.01f, 5, 9.5f, 5,
+CUBIC_TO, 11.99f, 5, 14, 7.01f, 14, 9.5f,
+CUBIC_TO, 14, 11.99f, 11.99f, 14, 9.5f, 14,
+CLOSE,
+END
diff --git a/ui/app_list/vector_icons/ic_search_engine_not_google.icon b/ui/app_list/vector_icons/ic_search_engine_not_google.icon
new file mode 100644
index 0000000..3fd6c52c
--- /dev/null
+++ b/ui/app_list/vector_icons/ic_search_engine_not_google.icon
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+MOVE_TO, 31, 28,
+LINE_TO, 29.42f, 28,
+LINE_TO, 28.86f, 27.46f,
+CUBIC_TO, 30.82f, 25.18f, 32, 22.22f, 32, 19,
+CUBIC_TO, 32, 11.82f, 26.18f, 6, 19, 6,
+CUBIC_TO, 11.82f, 6, 6, 11.82f, 6, 19,
+CUBIC_TO, 6, 26.18f, 11.82f, 32, 19, 32,
+CUBIC_TO, 22.22f, 32, 25.18f, 30.82f, 27.46f, 28.86f,
+LINE_TO, 28, 29.42f,
+LINE_TO, 28, 31,
+LINE_TO, 38, 40.98f,
+LINE_TO, 40.98f, 38,
+LINE_TO, 31, 28,
+CLOSE,
+MOVE_TO, 19, 28,
+CUBIC_TO, 14.02f, 28, 10, 23.98f, 10, 19,
+CUBIC_TO, 10, 14.02f, 14.02f, 10, 19, 10,
+CUBIC_TO, 23.98f, 10, 28, 14.02f, 28, 19,
+CUBIC_TO, 28, 23.98f, 23.98f, 28, 19, 28,
+CLOSE,
+END
diff --git a/ui/app_list/views/app_list_page.h b/ui/app_list/views/app_list_page.h
index d64b615..c20d374f 100644
--- a/ui/app_list/views/app_list_page.h
+++ b/ui/app_list/views/app_list_page.h
@@ -43,6 +43,7 @@
   // Returns the z height of the search box for this page.
   virtual int GetSearchBoxZHeight() const;
 
+  const ContentsView* contents_view() const { return contents_view_; }
   void set_contents_view(ContentsView* contents_view) {
     contents_view_ = contents_view;
   }
diff --git a/ui/app_list/views/contents_view.cc b/ui/app_list/views/contents_view.cc
index 0ab0ae3..23a4465 100644
--- a/ui/app_list/views/contents_view.cc
+++ b/ui/app_list/views/contents_view.cc
@@ -214,10 +214,7 @@
   const bool folder_active = state == AppListModel::STATE_APPS &&
                              apps_container_view_->IsInFolderView();
 
-  if (is_fullscreen_app_list_enabled_) {
-    app_list_main_view_->search_box_view()->UpdateBackground(
-        state == AppListModel::STATE_SEARCH_RESULTS);
-  } else {
+  if (!is_fullscreen_app_list_enabled_) {
     app_list_main_view_->search_box_view()->back_button()->SetVisible(
         state != AppListModel::STATE_START);
     app_list_main_view_->search_box_view()->Layout();
@@ -327,6 +324,8 @@
         gfx::Tween::ColorValueBetween(progress, original_shadow.color(),
                                       target_shadow.color())));
   }
+  if (is_fullscreen_app_list_enabled_)
+    search_box->UpdateBackground(progress, current_state, target_state);
   search_box->GetWidget()->SetBounds(
       search_box->GetViewBoundsForSearchBoxContentsBounds(
           ConvertRectToWidget(search_box_rect)));
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 8d5bf841..b335bf7 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -13,7 +13,6 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
-#include "ui/app_list/app_list_model.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/resources/grit/app_list_resources.h"
@@ -53,22 +52,14 @@
 constexpr int kInnerPadding = 24;
 constexpr int kPreferredWidth = 360;
 constexpr int kPreferredWidthFullscreen = 544;
-constexpr int kPreferredHeight = 48;
 
 constexpr SkColor kHintTextColor = SkColorSetARGBMacro(0xFF, 0xA0, 0xA0, 0xA0);
 
-constexpr int kBackgroundBorderCornerRadius = 2;
-constexpr int kBackgroundBorderCornerRadiusFullscreen = 24;
-constexpr int kBackgroundBorderCornerRadiusSearchResult = 4;
-constexpr int kGoogleIconSize = 24;
+constexpr int kSearchBoxBorderCornerRadius = 2;
+constexpr int kSearchBoxBorderCornerRadiusSearchResult = 4;
 constexpr int kMicIconSize = 24;
 constexpr int kCloseIconSize = 24;
 
-// Default color used when wallpaper customized color is not available for
-// searchbox, #000 at 87% opacity.
-constexpr SkColor kDefaultSearchboxColor =
-    SkColorSetARGBMacro(0xDE, 0x00, 0x00, 0x00);
-
 constexpr int kLightVibrantBlendAlpha = 0xB3;
 
 // Color of placeholder text in zero query state.
@@ -78,45 +69,29 @@
 // A background that paints a solid white rounded rect with a thin grey border.
 class SearchBoxBackground : public views::Background {
  public:
-  explicit SearchBoxBackground(SkColor color) : color_(color) {
-    const int corner_radius = features::IsFullscreenAppListEnabled()
-                                  ? kBackgroundBorderCornerRadiusFullscreen
-                                  : kBackgroundBorderCornerRadius;
-    SetCornerRadius(corner_radius, corner_radius, corner_radius, corner_radius);
-  }
+  explicit SearchBoxBackground(
+      SkColor color,
+      int corner_radius = features::IsFullscreenAppListEnabled()
+                              ? kSearchBoxBorderCornerRadiusFullscreen
+                              : kSearchBoxBorderCornerRadius)
+      : corner_radius_(corner_radius), color_(color) {}
   ~SearchBoxBackground() override {}
 
-  void SetCornerRadius(int top_left,
-                       int top_right,
-                       int bottom_right,
-                       int bottom_left) {
-    DCHECK(top_left >= 0 && top_right >= 0 && bottom_right >= 0 &&
-           bottom_left >= 0);
-    corner_radius_[0] = top_left;
-    corner_radius_[1] = top_right;
-    corner_radius_[2] = bottom_right;
-    corner_radius_[3] = bottom_left;
-  }
+  void set_corner_radius(int corner_radius) { corner_radius_ = corner_radius; }
+  void set_color(SkColor color) { color_ = color; }
 
  private:
   // views::Background overrides:
   void Paint(gfx::Canvas* canvas, views::View* view) const override {
     gfx::Rect bounds = view->GetContentsBounds();
 
-    const SkScalar kRadius[8] = {
-        SkIntToScalar(corner_radius_[0]), SkIntToScalar(corner_radius_[0]),
-        SkIntToScalar(corner_radius_[1]), SkIntToScalar(corner_radius_[1]),
-        SkIntToScalar(corner_radius_[2]), SkIntToScalar(corner_radius_[2]),
-        SkIntToScalar(corner_radius_[3]), SkIntToScalar(corner_radius_[3])};
-    SkPath path;
-    path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
     flags.setColor(color_);
-    canvas->DrawPath(path, flags);
+    canvas->DrawRoundRect(bounds, corner_radius_, flags);
   }
 
-  int corner_radius_[4];
+  int corner_radius_;
   SkColor color_;
 
   DISALLOW_COPY_AND_ASSIGN(SearchBoxBackground);
@@ -181,7 +156,7 @@
   SetPreferredSize(gfx::Size(is_fullscreen_app_list_enabled_
                                  ? kPreferredWidthFullscreen
                                  : kPreferredWidth,
-                             kPreferredHeight));
+                             kSearchBoxPreferredHeight));
   AddChildView(content_container_);
 
   SetShadow(GetShadowForZHeight(2));
@@ -194,7 +169,7 @@
   content_container_->SetLayoutManager(layout);
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_CENTER);
-  layout->set_minimum_cross_axis_size(kPreferredHeight);
+  layout->set_minimum_cross_axis_size(kSearchBoxPreferredHeight);
 
   search_box_->SetBorder(views::NullBorder());
   search_box_->SetTextColor(kSearchTextColor);
@@ -212,11 +187,10 @@
   content_container_->AddChildView(back_button_);
 
   if (is_fullscreen_app_list_enabled_) {
-    google_icon_ = new views::ImageView();
-    google_icon_->SetImage(gfx::CreateVectorIcon(
-        kIcGoogleBlackIcon, kGoogleIconSize, kDefaultSearchboxColor));
-    content_container_->AddChildView(google_icon_);
-
+    search_icon_ = new views::ImageView();
+    UpdateSearchIcon(view_delegate_->GetModel()->search_engine_is_google(),
+                     kDefaultSearchboxColor);
+    content_container_->AddChildView(search_icon_);
     search_box_->set_placeholder_text_color(kDefaultSearchboxColor);
     search_box_->set_placeholder_text_draw_flags(
         gfx::Canvas::TEXT_ALIGN_CENTER);
@@ -253,6 +227,8 @@
 
   model_ = view_delegate_->GetModel();
   DCHECK(model_);
+  if (is_fullscreen_app_list_enabled_)
+    UpdateSearchIcon(model_->search_engine_is_google(), kDefaultSearchboxColor);
   model_->search_box()->AddObserver(this);
   SpeechRecognitionButtonPropChanged();
   HintTextChanged();
@@ -399,7 +375,7 @@
   if (!is_fullscreen_app_list_enabled_)
     return;
 
-  google_icon_->SetVisible(!show_back_button);
+  search_icon_->SetVisible(!show_back_button);
   back_button_->SetVisible(show_back_button);
   content_container_->Layout();
 }
@@ -484,19 +460,47 @@
   HandleSearchBoxEvent(event);
 }
 
-void SearchBoxView::UpdateBackground(bool search_results_state) {
-  if (!search_results_state) {
-    WallpaperProminentColorsChanged();
-    return;
-  }
+int SearchBoxView::GetSearchBoxBorderCornerRadiusForState(
+    AppListModel::State state) {
+  if (state == AppListModel::STATE_SEARCH_RESULTS)
+    return kSearchBoxBorderCornerRadiusSearchResult;
+  return kSearchBoxBorderCornerRadiusFullscreen;
+}
 
+SkColor SearchBoxView::GetSearchBoxColorForState(
+    AppListModel::State state) const {
+  if (state == AppListModel::STATE_SEARCH_RESULTS)
+    return kSearchBoxBackgroundDefault;
+
+  // Uses wallpaper prominent color for other states.
+  const std::vector<SkColor> prominent_colors =
+      model_->search_box()->wallpaper_prominent_colors();
+  if (prominent_colors.empty())
+    return kSearchBoxBackgroundDefault;
+
+  DCHECK_EQ(static_cast<size_t>(ColorProfileType::NUM_OF_COLOR_PROFILES),
+            prominent_colors.size());
+  const SkColor light_vibrant =
+      prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)];
+  const SkColor light_vibrant_mixed = color_utils::AlphaBlend(
+      SK_ColorWHITE, light_vibrant, kLightVibrantBlendAlpha);
+  return SK_ColorTRANSPARENT == light_vibrant ? kSearchBoxBackgroundDefault
+                                              : light_vibrant_mixed;
+}
+
+void SearchBoxView::UpdateBackground(double progress,
+                                     AppListModel::State current_state,
+                                     AppListModel::State target_state) {
   SearchBoxBackground* background =
-      new SearchBoxBackground(kSearchBoxBackgroundDefault);
-  background->SetCornerRadius(kBackgroundBorderCornerRadiusSearchResult,
-                              kBackgroundBorderCornerRadiusSearchResult, 0, 0);
-  content_container_->SetBackground(
-      base::WrapUnique<SearchBoxBackground>(background));
-  search_box_->SetBackgroundColor(kSearchBoxBackgroundDefault);
+      static_cast<SearchBoxBackground*>(content_container_->background());
+  background->set_corner_radius(gfx::Tween::LinearIntValueBetween(
+      progress, GetSearchBoxBorderCornerRadiusForState(current_state),
+      GetSearchBoxBorderCornerRadiusForState(target_state)));
+  const SkColor color = gfx::Tween::ColorValueBetween(
+      progress, GetSearchBoxColorForState(current_state),
+      GetSearchBoxColorForState(target_state));
+  background->set_color(color);
+  search_box_->SetBackgroundColor(color);
 }
 
 void SearchBoxView::UpdateModel() {
@@ -675,35 +679,27 @@
             prominent_colors.size());
   const SkColor dark_muted =
       prominent_colors[static_cast<int>(ColorProfileType::DARK_MUTED)];
-  const bool dark_muted_available = SK_ColorTRANSPARENT != dark_muted;
-  google_icon_->SetImage(gfx::CreateVectorIcon(
-      kIcGoogleBlackIcon, kGoogleIconSize,
-      dark_muted_available ? dark_muted : kDefaultSearchboxColor));
+  const SkColor search_box_color =
+      SK_ColorTRANSPARENT == dark_muted ? kDefaultSearchboxColor : dark_muted;
+  UpdateSearchIcon(model_->search_engine_is_google(), search_box_color);
   speech_button_->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(
-          kIcMicBlackIcon, kMicIconSize,
-          dark_muted_available ? dark_muted : kDefaultSearchboxColor));
+      gfx::CreateVectorIcon(kIcMicBlackIcon, kMicIconSize, search_box_color));
   close_button_->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(
-          kIcCloseIcon, kCloseIconSize,
-          dark_muted_available ? dark_muted : kDefaultSearchboxColor));
-  search_box_->set_placeholder_text_color(
-      dark_muted_available ? dark_muted : kDefaultSearchboxColor);
-
+      gfx::CreateVectorIcon(kIcCloseIcon, kCloseIconSize, search_box_color));
+  search_box_->set_placeholder_text_color(search_box_color);
   const SkColor light_vibrant =
       prominent_colors[static_cast<int>(ColorProfileType::LIGHT_VIBRANT)];
   const SkColor light_vibrant_mixed = color_utils::AlphaBlend(
       SK_ColorWHITE, light_vibrant, kLightVibrantBlendAlpha);
-  const bool light_vibrant_available = SK_ColorTRANSPARENT != light_vibrant;
-  content_container_->SetBackground(base::MakeUnique<SearchBoxBackground>(
-      light_vibrant_available ? light_vibrant_mixed
-                              : kSearchBoxBackgroundDefault));
-  search_box_->SetBackgroundColor(light_vibrant_available
-                                      ? light_vibrant_mixed
-                                      : kSearchBoxBackgroundDefault);
-
+  const SkColor background_color = SK_ColorTRANSPARENT == light_vibrant
+                                       ? kSearchBoxBackgroundDefault
+                                       : light_vibrant_mixed;
+  SearchBoxBackground* background =
+      static_cast<SearchBoxBackground*>(content_container_->background());
+  background->set_color(background_color);
+  search_box_->SetBackgroundColor(background_color);
   SchedulePaint();
 }
 
@@ -713,4 +709,12 @@
   SchedulePaint();
 }
 
+void SearchBoxView::UpdateSearchIcon(bool is_google,
+                                     const SkColor& search_box_color) {
+  const gfx::VectorIcon& icon =
+      is_google ? kIcGoogleBlackIcon : kIcSearchEngineNotGoogleIcon;
+  search_icon_->SetImage(
+      gfx::CreateVectorIcon(icon, kSearchIconSize, search_box_color));
+}
+
 }  // namespace app_list
diff --git a/ui/app_list/views/search_box_view.h b/ui/app_list/views/search_box_view.h
index 63e124f2..bc553da 100644
--- a/ui/app_list/views/search_box_view.h
+++ b/ui/app_list/views/search_box_view.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "ui/app_list/app_list_model.h"
 #include "ui/app_list/search_box_model_observer.h"
 #include "ui/app_list/speech_ui_model_observer.h"
 #include "ui/gfx/shadow_value.h"
@@ -32,7 +33,6 @@
   FOCUS_CONTENTS_VIEW,  // Something outside the SearchBox is selected
 };
 
-class AppListModel;
 class AppListView;
 class AppListViewDelegate;
 class SearchBoxModel;
@@ -109,8 +109,19 @@
   void OnGestureEvent(ui::GestureEvent* event) override;
   void OnMouseEvent(ui::MouseEvent* event) override;
 
-  // Updates the |content_container_|'s background corner radius.
-  void UpdateBackground(bool search_results_state);
+  // Returns background border corner radius in the given state.
+  static int GetSearchBoxBorderCornerRadiusForState(AppListModel::State state);
+
+  // Returns search box color in the given state.
+  SkColor GetSearchBoxColorForState(AppListModel::State state) const;
+
+  // Updates the search box's background corner radius and color.
+  void UpdateBackground(double progress,
+                        AppListModel::State current_state,
+                        AppListModel::State target_state);
+
+  // Used only in the tests to get the current search icon.
+  views::ImageView* get_search_icon_for_test() { return search_icon_; }
 
  private:
   // Updates model text and selection model with current Textfield info.
@@ -119,6 +130,9 @@
   // Fires query change notification.
   void NotifyQueryChanged();
 
+  // Updates the search icon.
+  void UpdateSearchIcon(bool is_google, const SkColor& search_box_color);
+
   // Overridden from views::TextfieldController:
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override;
@@ -149,7 +163,7 @@
 
   // Owned by views hierarchy.
   views::View* content_container_;
-  views::ImageView* google_icon_ = nullptr;
+  views::ImageView* search_icon_ = nullptr;
   SearchBoxImageButton* back_button_ = nullptr;
   SearchBoxImageButton* speech_button_ = nullptr;
   SearchBoxImageButton* close_button_ = nullptr;
diff --git a/ui/app_list/views/search_box_view_unittest.cc b/ui/app_list/views/search_box_view_unittest.cc
index 69cd479..672a5fbd 100644
--- a/ui/app_list/views/search_box_view_unittest.cc
+++ b/ui/app_list/views/search_box_view_unittest.cc
@@ -10,10 +10,16 @@
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/test/app_list_test_view_delegate.h"
+#include "ui/app_list/vector_icons/vector_icons.h"
 #include "ui/app_list/views/app_list_view.h"
 #include "ui/app_list/views/search_box_view_delegate.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_unittest_util.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/test/widget_test.h"
 
@@ -45,6 +51,8 @@
   DISALLOW_COPY_AND_ASSIGN(KeyPressCounterView);
 };
 
+// These tests run with both FullscreenAppList enabled and disabled.
+// TODO(crbug.com/743113) Unify the two test classes.
 class SearchBoxViewTest : public views::test::WidgetTest,
                           public SearchBoxViewDelegate,
                           public testing::WithParamInterface<bool> {
@@ -67,24 +75,26 @@
 
     gfx::NativeView parent = GetContext();
     app_list_view_ = new AppListView(&view_delegate_);
-    app_list_view_->Initialize(parent, 0, false, false);
+    app_list_view()->Initialize(parent, 0, false, false);
 
     widget_ = CreateTopLevelPlatformWidget();
-    view_ = new SearchBoxView(this, &view_delegate_, app_list_view_);
+    view_.reset(new SearchBoxView(this, &view_delegate_, app_list_view()));
     counter_view_ = new KeyPressCounterView();
-    widget_->GetContentsView()->AddChildView(view_);
+    widget_->GetContentsView()->AddChildView(view());
     widget_->GetContentsView()->AddChildView(counter_view_);
-    view_->set_contents_view(counter_view_);
+    view()->set_contents_view(counter_view_);
   }
 
   void TearDown() override {
+    view_.reset();
     app_list_view_->GetWidget()->Close();
     widget_->CloseNow();
     views::test::WidgetTest::TearDown();
   }
 
  protected:
-  SearchBoxView* view() { return view_; }
+  SearchBoxView* view() { return view_.get(); }
+  AppListView* app_list_view() { return app_list_view_; }
 
   bool test_with_fullscreen() { return test_with_fullscreen_; }
 
@@ -107,11 +117,11 @@
 
   void KeyPress(ui::KeyboardCode key_code) {
     ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
-    view_->search_box()->OnKeyEvent(&event);
+    view()->search_box()->OnKeyEvent(&event);
     // Emulates the input method.
     if (::isalnum(static_cast<int>(key_code))) {
       base::char16 character = ::tolower(static_cast<int>(key_code));
-      view_->search_box()->InsertText(base::string16(1, character));
+      view()->search_box()->InsertText(base::string16(1, character));
     }
   }
 
@@ -140,8 +150,8 @@
 
   AppListTestViewDelegate view_delegate_;
   views::Widget* widget_;
-  SearchBoxView* view_;
   AppListView* app_list_view_ = nullptr;
+  std::unique_ptr<SearchBoxView> view_;
   KeyPressCounterView* counter_view_;
   base::string16 last_query_;
   int query_changed_count_ = 0;
@@ -151,6 +161,71 @@
   DISALLOW_COPY_AND_ASSIGN(SearchBoxViewTest);
 };
 
+class SearchBoxViewFullscreenTest : public views::test::WidgetTest,
+                                    public SearchBoxViewDelegate {
+ public:
+  SearchBoxViewFullscreenTest() {}
+  ~SearchBoxViewFullscreenTest() override {}
+
+  // Overridden from testing::Test:
+  void SetUp() override {
+    views::test::WidgetTest::SetUp();
+    scoped_feature_list_.InitAndEnableFeature(
+        app_list::features::kEnableFullscreenAppList);
+
+    gfx::NativeView parent = GetContext();
+    app_list_view_ = new AppListView(&view_delegate_);
+    app_list_view_->Initialize(parent, 0, false, false);
+
+    widget_ = CreateTopLevelPlatformWidget();
+    view_.reset(new SearchBoxView(this, &view_delegate_, app_list_view()));
+    widget_->SetBounds(gfx::Rect(0, 0, 300, 200));
+    widget_->GetContentsView()->AddChildView(view());
+  }
+
+  void TearDown() override {
+    view_.reset();
+    app_list_view_->GetWidget()->Close();
+    widget_->CloseNow();
+    views::test::WidgetTest::TearDown();
+  }
+
+ protected:
+  SearchBoxView* view() { return view_.get(); }
+  AppListView* app_list_view() { return app_list_view_; }
+
+  void SetSearchEngineIsGoogle(bool is_google) {
+    view_delegate_.SetSearchEngineIsGoogle(is_google);
+  }
+
+  void KeyPress(ui::KeyboardCode key_code) {
+    ui::KeyEvent event(ui::ET_KEY_PRESSED, key_code, ui::EF_NONE);
+    view()->search_box()->OnKeyEvent(&event);
+    // Emulates the input method.
+    if (::isalnum(static_cast<int>(key_code))) {
+      base::char16 character = ::tolower(static_cast<int>(key_code));
+      view()->search_box()->InsertText(base::string16(1, character));
+    }
+  }
+
+ private:
+  // Overridden from SearchBoxViewDelegate:
+  void QueryChanged(SearchBoxView* sender) override {}
+
+  void BackButtonPressed() override {}
+
+  void SetSearchResultSelection(bool select) override {}
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  AppListTestViewDelegate view_delegate_;
+  views::Widget* widget_;
+  AppListView* app_list_view_ = nullptr;
+  std::unique_ptr<SearchBoxView> view_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchBoxViewFullscreenTest);
+};
+
 // Instantiate the Boolean which is used to toggle the Fullscreen app list in
 // the parameterized tests.
 INSTANTIATE_TEST_CASE_P(, SearchBoxViewTest, testing::Bool());
@@ -192,10 +267,7 @@
   EXPECT_EQ(base::TimeDelta(), GetAutoLaunchTimeout());
 }
 
-TEST_P(SearchBoxViewTest, CloseButtonTest) {
-  if (!test_with_fullscreen())
-    return;
-
+TEST_F(SearchBoxViewFullscreenTest, CloseButtonTest) {
   KeyPress(ui::VKEY_A);
   EXPECT_TRUE(view()->IsCloseButtonVisible());
 
@@ -203,5 +275,29 @@
   EXPECT_FALSE(view()->IsCloseButtonVisible());
 }
 
+TEST_F(SearchBoxViewFullscreenTest, SearchEngineGoogle) {
+  SetSearchEngineIsGoogle(true);
+  gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+      kIcGoogleBlackIcon, kSearchIconSize, kDefaultSearchboxColor);
+  view()->ModelChanged();
+
+  gfx::ImageSkia actual_icon = view()->get_search_icon_for_test()->GetImage();
+
+  EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
+                                         *actual_icon.bitmap()));
+}
+
+TEST_F(SearchBoxViewFullscreenTest, SearchEngineNotGoogle) {
+  SetSearchEngineIsGoogle(false);
+  gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+      kIcSearchEngineNotGoogleIcon, kSearchIconSize, kDefaultSearchboxColor);
+  view()->ModelChanged();
+
+  gfx::ImageSkia actual_icon = view()->get_search_icon_for_test()->GetImage();
+
+  EXPECT_TRUE(gfx::test::AreBitmapsEqual(*expected_icon.bitmap(),
+                                         *actual_icon.bitmap()));
+}
+
 }  // namespace test
 }  // namespace app_list
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc
index 7388968d..92162c4d 100644
--- a/ui/app_list/views/search_result_page_view.cc
+++ b/ui/app_list/views/search_result_page_view.cc
@@ -13,6 +13,7 @@
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_view_delegate.h"
 #include "ui/app_list/views/app_list_main_view.h"
+#include "ui/app_list/views/contents_view.h"
 #include "ui/app_list/views/search_box_view.h"
 #include "ui/app_list/views/search_result_list_view.h"
 #include "ui/app_list/views/search_result_tile_item_list_view.h"
@@ -37,11 +38,10 @@
 // The z-height of the search box and cards in this view.
 constexpr int kSearchResultZHeight = 1;
 
-constexpr int kBackgroundCornerRadius = 4;
+// The horizontal padding of the separator.
 constexpr int kSeparatorPadding = 12;
 constexpr int kSeparatorThickness = 1;
 
-constexpr SkColor kBackgroundColor = SK_ColorWHITE;
 constexpr SkColor kSeparatorColor = SkColorSetARGBMacro(0x1F, 0x00, 0x00, 0x00);
 
 // A container view that ensures the card background and the shadow are painted
@@ -52,10 +52,10 @@
     if (!features::IsFullscreenAppListEnabled()) {
       SetBorder(base::MakeUnique<views::ShadowBorder>(
           GetShadowForZHeight(kSearchResultZHeight)));
+      content_view->SetBackground(
+          views::CreateSolidBackground(kCardBackgroundColor));
     }
     SetLayoutManager(new views::FillLayout());
-    content_view->SetBackground(
-        views::CreateSolidBackground(kCardBackgroundColor));
     AddChildView(content_view);
   }
 
@@ -78,34 +78,28 @@
 
 class SearchResultPageBackground : public views::Background {
  public:
-  SearchResultPageBackground() {}
+  SearchResultPageBackground(SkColor color, int corner_radius)
+      : color_(color), corner_radius_(corner_radius) {}
   ~SearchResultPageBackground() override {}
 
  private:
   // views::Background overrides:
   void Paint(gfx::Canvas* canvas, views::View* view) const override {
     gfx::Rect bounds = view->GetContentsBounds();
-    const SkScalar kCornerRadiusScalar = SkIntToScalar(kBackgroundCornerRadius);
-    const SkScalar kRadius[8] = {0,
-                                 0,
-                                 0,
-                                 0,
-                                 kCornerRadiusScalar,
-                                 kCornerRadiusScalar,
-                                 kCornerRadiusScalar,
-                                 kCornerRadiusScalar};
-    SkPath path;
-    path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
     cc::PaintFlags flags;
     flags.setAntiAlias(true);
-    flags.setColor(kBackgroundColor);
-    canvas->DrawPath(path, flags);
+    flags.setColor(color_);
+    canvas->DrawRoundRect(bounds, corner_radius_, flags);
 
     // Draws a separator between SearchBoxView and SearchResultPageView.
+    bounds.set_y(kSearchBoxPreferredHeight);
     bounds.set_height(kSeparatorThickness);
     canvas->FillRect(bounds, kSeparatorColor);
   }
 
+  const SkColor color_;
+  const int corner_radius_;
+
   DISALLOW_COPY_AND_ASSIGN(SearchResultPageBackground);
 };
 
@@ -147,7 +141,11 @@
   if (is_fullscreen_app_list_enabled_) {
     contents_view_->SetLayoutManager(
         new views::BoxLayout(views::BoxLayout::kVertical, gfx::Insets(), 0));
-    SetBackground(base::MakeUnique<SearchResultPageBackground>());
+
+    // Hides this view behind the search box by using the same color and
+    // background border corner radius.
+    SetBackground(base::MakeUnique<SearchResultPageBackground>(
+        kSearchBoxBackgroundDefault, kSearchBoxBorderCornerRadiusFullscreen));
   } else {
     gfx::ShadowValue shadow = GetShadowForZHeight(kSearchResultZHeight);
     std::unique_ptr<views::Border> border(new views::ShadowBorder(shadow));
@@ -164,8 +162,9 @@
 
   views::ScrollView* const scroller = new views::ScrollView;
   if (is_fullscreen_app_list_enabled_) {
-    scroller->SetBorder(
-        views::CreateEmptyBorder(gfx::Insets(kSeparatorThickness, 0, 0, 0)));
+    // Leaves a placeholder area for the search box and the separator below it.
+    scroller->SetBorder(views::CreateEmptyBorder(
+        gfx::Insets(kSearchBoxPreferredHeight + kSeparatorThickness, 0, 0, 0)));
   }
   scroller->SetContents(contents_view_);
   // Setting clip height is necessary to make ScrollView take into account its
@@ -348,20 +347,22 @@
 
 gfx::Rect SearchResultPageView::GetPageBoundsForState(
     AppListModel::State state) const {
-  gfx::Rect onscreen_bounds = GetDefaultContentsBounds();
-
-  if (is_fullscreen_app_list_enabled_) {
-    gfx::Rect search_box_bounds = GetSearchBoxBounds();
-    onscreen_bounds.set_y(search_box_bounds.bottom());
-    onscreen_bounds.set_height(kFullscreenHeight - search_box_bounds.height());
+  if (!is_fullscreen_app_list_enabled_) {
+    return (state == AppListModel::STATE_SEARCH_RESULTS
+                ? GetDefaultContentsBounds()
+                : GetAboveContentsOffscreenBounds(
+                      GetDefaultContentsBounds().size()));
   }
 
-  switch (state) {
-    case AppListModel::STATE_SEARCH_RESULTS:
-      return onscreen_bounds;
-    default:
-      return GetAboveContentsOffscreenBounds(onscreen_bounds.size());
+  if (state != AppListModel::STATE_SEARCH_RESULTS) {
+    // Hides this view behind the search box by using the same bounds.
+    return AppListPage::GetSearchBoxBounds();
   }
+
+  gfx::Rect onscreen_bounds(GetDefaultContentsBounds());
+  onscreen_bounds.set_y(AppListPage::GetSearchBoxBounds().y());
+  onscreen_bounds.set_height(kFullscreenHeight);
+  return onscreen_bounds;
 }
 
 void SearchResultPageView::OnAnimationUpdated(double progress,
@@ -372,6 +373,23 @@
     return;
   }
 
+  if (is_fullscreen_app_list_enabled_) {
+    const SearchBoxView* search_box =
+        AppListPage::contents_view()->GetSearchBoxView();
+    const SkColor color = gfx::Tween::ColorValueBetween(
+        progress, search_box->GetSearchBoxColorForState(from_state),
+        search_box->GetSearchBoxColorForState(to_state));
+
+    // Grows this view in the same pace as the search box to make them look
+    // like a single view.
+    SetBackground(base::MakeUnique<SearchResultPageBackground>(
+        color,
+        gfx::Tween::LinearIntValueBetween(
+            progress,
+            SearchBoxView::GetSearchBoxBorderCornerRadiusForState(from_state),
+            SearchBoxView::GetSearchBoxBorderCornerRadiusForState(to_state))));
+  }
+
   gfx::Rect onscreen_bounds(
       GetPageBoundsForState(AppListModel::STATE_SEARCH_RESULTS));
   onscreen_bounds -= bounds().OffsetFromOrigin();
@@ -391,8 +409,9 @@
 gfx::Rect SearchResultPageView::GetSearchBoxBounds() const {
   gfx::Rect rect(AppListPage::GetSearchBoxBounds());
   if (is_fullscreen_app_list_enabled_) {
-    rect.set_x(bounds().x());
-    rect.set_width(bounds().width());
+    gfx::Rect contents_bounds(GetDefaultContentsBounds());
+    rect.set_x(contents_bounds.x());
+    rect.set_width(contents_bounds.width());
   }
   return rect;
 }
diff --git a/ui/app_list/views/search_result_view.cc b/ui/app_list/views/search_result_view.cc
index 67c16872..71aaec5b 100644
--- a/ui/app_list/views/search_result_view.cc
+++ b/ui/app_list/views/search_result_view.cc
@@ -255,7 +255,8 @@
   const bool selected = list_view_->IsResultViewSelected(this);
   const bool hover = state() == STATE_HOVERED || state() == STATE_PRESSED;
 
-  canvas->FillRect(content_rect, kCardBackgroundColor);
+  if (!is_fullscreen_app_list_enabled_)
+    canvas->FillRect(content_rect, kCardBackgroundColor);
 
   // Possibly call FillRect a second time (these colours are partially
   // transparent, so the previous FillRect is not redundant).
diff --git a/ui/aura/mus/window_manager_delegate.h b/ui/aura/mus/window_manager_delegate.h
index fca8b6c..09bb4e1f4 100644
--- a/ui/aura/mus/window_manager_delegate.h
+++ b/ui/aura/mus/window_manager_delegate.h
@@ -103,6 +103,14 @@
       std::vector<ui::mojom::WmViewportMetricsPtr> viewport_metrics,
       int64_t primary_display_id) = 0;
 
+  // Adds |display| as a new display moving |window_tree_host| to the new
+  // display. This results in closing the previous display |window_tree_host|
+  // was associated with.
+  virtual void AddDisplayReusingWindowTreeHost(
+      WindowTreeHostMus* window_tree_host,
+      const display::Display& display,
+      ui::mojom::WmViewportMetricsPtr viewport_metrics) = 0;
+
  protected:
   virtual ~WindowManagerClient() {}
 };
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index f5ee045..4b3ad83 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -1917,6 +1917,25 @@
   }
 }
 
+void WindowTreeClient::AddDisplayReusingWindowTreeHost(
+    WindowTreeHostMus* window_tree_host,
+    const display::Display& display,
+    ui::mojom::WmViewportMetricsPtr viewport_metrics) {
+  DCHECK_NE(display.id(), window_tree_host->display_id());
+  window_tree_host->set_display_id(display.id());
+  if (window_manager_client_) {
+    // NOTE: The value of |is_primary_display| doesn't really matter as shortly
+    // after this SetDisplayConfiguration() is called.
+    const bool is_primary_display = true;
+    WindowMus* display_root_window = WindowMus::Get(window_tree_host->window());
+    window_manager_client_->SetDisplayRoot(
+        display, std::move(viewport_metrics), is_primary_display,
+        display_root_window->server_id(),
+        base::Bind(&WindowTreeClient::OnSetDisplayRootDone,
+                   base::Unretained(this), display_root_window->server_id()));
+  }
+}
+
 void WindowTreeClient::OnWindowTreeHostBoundsWillChange(
     WindowTreeHostMus* window_tree_host,
     const gfx::Rect& bounds) {
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index b8a61205..97261c37 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -496,6 +496,10 @@
       const std::vector<display::Display>& displays,
       std::vector<ui::mojom::WmViewportMetricsPtr> viewport_metrics,
       int64_t primary_display_id) override;
+  void AddDisplayReusingWindowTreeHost(
+      WindowTreeHostMus* window_tree_host,
+      const display::Display& display,
+      ui::mojom::WmViewportMetricsPtr viewport_metrics) override;
 
   // Overriden from WindowTreeHostMusDelegate:
   void OnWindowTreeHostBoundsWillChange(WindowTreeHostMus* window_tree_host,
diff --git a/ui/display/display_observer.cc b/ui/display/display_observer.cc
index b25f1fa8..276c9ab 100644
--- a/ui/display/display_observer.cc
+++ b/ui/display/display_observer.cc
@@ -8,6 +8,10 @@
 
 DisplayObserver::~DisplayObserver() {}
 
+void DisplayObserver::OnWillProcessDisplayChanges() {}
+
+void DisplayObserver::OnDidProcessDisplayChanges() {}
+
 void DisplayObserver::OnDisplayAdded(const Display& new_display) {}
 
 void DisplayObserver::OnDisplayRemoved(const Display& old_display) {}
diff --git a/ui/display/display_observer.h b/ui/display/display_observer.h
index 3398b50..568852d 100644
--- a/ui/display/display_observer.h
+++ b/ui/display/display_observer.h
@@ -28,6 +28,14 @@
     DISPLAY_METRIC_COLOR_SPACE = 1 << 6,
   };
 
+  // This may be called before other methods to signal changes are about to
+  // happen. Not all classes that support DisplayObserver call this.
+  virtual void OnWillProcessDisplayChanges();
+
+  // Called after OnWillProcessDisplayChanges() to indicate display changes have
+  // completed. Not all classes that support DisplayObserver call this.
+  virtual void OnDidProcessDisplayChanges();
+
   // Called when |new_display| has been added.
   virtual void OnDisplayAdded(const Display& new_display);
 
diff --git a/ui/display/manager/display_manager.cc b/ui/display/manager/display_manager.cc
index f8be65d0..e5e3951 100644
--- a/ui/display/manager/display_manager.cc
+++ b/ui/display/manager/display_manager.cc
@@ -140,6 +140,22 @@
 using std::string;
 using std::vector;
 
+DisplayManager::BeginEndNotifier::BeginEndNotifier(
+    DisplayManager* display_manager)
+    : display_manager_(display_manager) {
+  if (display_manager_->notify_depth_++ == 0) {
+    for (auto& observer : display_manager_->observers_)
+      observer.OnWillProcessDisplayChanges();
+  }
+}
+
+DisplayManager::BeginEndNotifier::~BeginEndNotifier() {
+  if (--display_manager_->notify_depth_ == 0) {
+    for (auto& observer : display_manager_->observers_)
+      observer.OnDidProcessDisplayChanges();
+  }
+}
+
 // static
 int64_t DisplayManager::kUnifiedDisplayId = -10;
 
@@ -246,6 +262,8 @@
     std::unique_ptr<DisplayLayout> layout) {
   if (GetNumDisplays() == 1)
     return;
+  BeginEndNotifier notifier(this);
+
   const DisplayIdList list = GetCurrentDisplayIdList();
 
   DCHECK(DisplayLayout::Validate(list, *layout));
@@ -294,14 +312,14 @@
 
 bool DisplayManager::UpdateWorkAreaOfDisplay(int64_t display_id,
                                              const gfx::Insets& insets) {
+  BeginEndNotifier notifier(this);
   Display* display = FindDisplayForId(display_id);
   DCHECK(display);
   gfx::Rect old_work_area = display->work_area();
   display->UpdateWorkAreaFromInsets(insets);
   bool workarea_changed = old_work_area != display->work_area();
-  if (workarea_changed) {
+  if (workarea_changed)
     NotifyMetricsChanged(*display, DisplayObserver::DISPLAY_METRIC_WORK_AREA);
-  }
   return workarea_changed;
 }
 
@@ -680,6 +698,8 @@
 
 void DisplayManager::UpdateDisplaysWith(
     const DisplayInfoList& updated_display_info_list) {
+  BeginEndNotifier notifier(this);
+
 #if defined(OS_WIN)
   DCHECK_EQ(1u, updated_display_info_list.size())
       << ": Multiple display test does not work on Windows bots. Please "
@@ -1130,6 +1150,7 @@
     Display* display = FindDisplayForId(display_id);
     DCHECK(display);
     display->SetSize(display_info_[display_id].size_in_pixel());
+    BeginEndNotifier notifier(this);
     NotifyMetricsChanged(*display, DisplayObserver::DISPLAY_METRIC_BOUNDS);
     return true;
   }
diff --git a/ui/display/manager/display_manager.h b/ui/display/manager/display_manager.h
index 8c28cbf..71d3cc6 100644
--- a/ui/display/manager/display_manager.h
+++ b/ui/display/manager/display_manager.h
@@ -377,6 +377,18 @@
  private:
   friend class test::DisplayManagerTestApi;
 
+  // See description above |notify_depth_| for details.
+  class BeginEndNotifier {
+   public:
+    explicit BeginEndNotifier(DisplayManager* display_manager);
+    ~BeginEndNotifier();
+
+   private:
+    DisplayManager* display_manager_;
+
+    DISALLOW_COPY_AND_ASSIGN(BeginEndNotifier);
+  };
+
   bool software_mirroring_enabled() const {
     return multi_display_mode_ == MIRRORING;
   }
@@ -500,6 +512,11 @@
 
   base::ObserverList<DisplayObserver> observers_;
 
+  // This is incremented whenever a BeginEndNotifier is created and decremented
+  // when destroyed. BeginEndNotifier uses this to track when it should call
+  // OnWillProcessDisplayChanges() and OnDidProcessDisplayChanges().
+  int notify_depth_ = 0;
+
   base::WeakPtrFactory<DisplayManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayManager);
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 278bd5f..e369ae8 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -578,6 +578,8 @@
 static_library("test_support") {
   testonly = true
   sources = [
+    "animation/animation_test_api.cc",
+    "animation/animation_test_api.h",
     "animation/test_animation_delegate.h",
     "geometry/test/rect_test_util.cc",
     "geometry/test/rect_test_util.h",
diff --git a/ui/gfx/animation/animation.h b/ui/gfx/animation/animation.h
index e26bb21..bc5e6461 100644
--- a/ui/gfx/animation/animation.h
+++ b/ui/gfx/animation/animation.h
@@ -19,6 +19,7 @@
 
 class AnimationContainer;
 class AnimationDelegate;
+class AnimationTestApi;
 
 // Base class used in implementing animations. You only need use this class if
 // you're implementing a new animation type, otherwise you'll likely want one of
@@ -92,6 +93,8 @@
   base::TimeDelta GetTimerInterval() const override;
 
  private:
+  friend class AnimationTestApi;
+
   // Interval for the animation.
   const base::TimeDelta timer_interval_;
 
diff --git a/ui/gfx/animation/animation_test_api.cc b/ui/gfx/animation/animation_test_api.cc
new file mode 100644
index 0000000..e2d093f
--- /dev/null
+++ b/ui/gfx/animation/animation_test_api.cc
@@ -0,0 +1,25 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/animation/animation_test_api.h"
+
+#include "base/time/time.h"
+#include "ui/gfx/animation/animation.h"
+
+namespace gfx {
+
+AnimationTestApi::AnimationTestApi(Animation* animation)
+    : animation_(animation) {}
+
+AnimationTestApi::~AnimationTestApi() {}
+
+void AnimationTestApi::SetStartTime(base::TimeTicks ticks) {
+  animation_->SetStartTime(ticks);
+}
+
+void AnimationTestApi::Step(base::TimeTicks ticks) {
+  animation_->Step(ticks);
+}
+
+}  // namespace gfx
diff --git a/ui/gfx/animation/animation_test_api.h b/ui/gfx/animation/animation_test_api.h
new file mode 100644
index 0000000..04e8a67a
--- /dev/null
+++ b/ui/gfx/animation/animation_test_api.h
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_ANIMATION_ANIMATION_TEST_API_H_
+#define UI_GFX_ANIMATION_ANIMATION_TEST_API_H_
+
+#include "base/macros.h"
+#include "ui/gfx/animation/animation.h"
+
+namespace gfx {
+
+// Class to provide access to Animation internals for testing.
+class AnimationTestApi {
+ public:
+  explicit AnimationTestApi(Animation* animation);
+  ~AnimationTestApi();
+
+  // Sets the start of the animation.
+  void SetStartTime(base::TimeTicks ticks);
+
+  // Manually steps the animation forward
+  void Step(base::TimeTicks ticks);
+
+ private:
+  Animation* animation_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnimationTestApi);
+};
+
+}  // namespace gfx
+
+#endif  // UI_GFX_ANIMATION_ANIMATION_TEST_API_H_
diff --git a/ui/gfx/animation/slide_animation_unittest.cc b/ui/gfx/animation/slide_animation_unittest.cc
index 5de1700..2516ec09 100644
--- a/ui/gfx/animation/slide_animation_unittest.cc
+++ b/ui/gfx/animation/slide_animation_unittest.cc
@@ -10,32 +10,14 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/animation/animation_test_api.h"
 #include "ui/gfx/animation/test_animation_delegate.h"
 
 namespace gfx {
 
-// Class to provide access to SlideAnimation internals for testing.
-class SlideAnimation::TestApi {
- public:
-  explicit TestApi(SlideAnimation* animation) : animation_(animation) {}
-
-  void SetStartTime(base::TimeTicks ticks) {
-    animation_->SetStartTime(ticks);
-  }
-
-  void Step(base::TimeTicks ticks) {
-    animation_->Step(ticks);
-  }
-
- private:
-  SlideAnimation* animation_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestApi);
-};
-
 ////////////////////////////////////////////////////////////////////////////////
 // SlideAnimationTest
-class SlideAnimationTest: public testing::Test {
+class SlideAnimationTest : public testing::Test {
  protected:
   SlideAnimationTest()
       : scoped_task_environment_(
@@ -62,7 +44,7 @@
 
 TEST_F(SlideAnimationTest, Basics) {
   SlideAnimation animation(nullptr);
-  SlideAnimation::TestApi test_api(&animation);
+  AnimationTestApi test_api(&animation);
 
   // Use linear tweening to make the math easier below.
   animation.SetTweenType(Tween::LINEAR);
diff --git a/ui/gfx/geometry/point.h b/ui/gfx/geometry/point.h
index bb248d543..b1ba5065 100644
--- a/ui/gfx/geometry/point.h
+++ b/ui/gfx/geometry/point.h
@@ -9,7 +9,7 @@
 #include <string>
 #include <tuple>
 
-#include "base/numerics/saturated_arithmetic.h"
+#include "base/numerics/clamped_math.h"
 #include "build/build_config.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/gfx_export.h"
@@ -56,18 +56,18 @@
   }
 
   void Offset(int delta_x, int delta_y) {
-    x_ = base::SaturatedAddition(x_, delta_x);
-    y_ = base::SaturatedAddition(y_, delta_y);
+    x_ = base::ClampAdd(x_, delta_x);
+    y_ = base::ClampAdd(y_, delta_y);
   }
 
   void operator+=(const Vector2d& vector) {
-    x_ = base::SaturatedAddition(x_, vector.x());
-    y_ = base::SaturatedAddition(y_, vector.y());
+    x_ = base::ClampAdd(x_, vector.x());
+    y_ = base::ClampAdd(y_, vector.y());
   }
 
   void operator-=(const Vector2d& vector) {
-    x_ = base::SaturatedSubtraction(x_, vector.x());
-    y_ = base::SaturatedSubtraction(y_, vector.y());
+    x_ = base::ClampSub(x_, vector.x());
+    y_ = base::ClampSub(y_, vector.y());
   }
 
   void SetToMin(const Point& other);
@@ -116,8 +116,8 @@
 }
 
 inline Vector2d operator-(const Point& lhs, const Point& rhs) {
-  return Vector2d(base::SaturatedSubtraction(lhs.x(), rhs.x()),
-                  base::SaturatedSubtraction(lhs.y(), rhs.y()));
+  return Vector2d(base::ClampSub(lhs.x(), rhs.x()),
+                  base::ClampSub(lhs.y(), rhs.y()));
 }
 
 inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
diff --git a/ui/gfx/geometry/rect.cc b/ui/gfx/geometry/rect.cc
index b5ceda5..a1735d0 100644
--- a/ui/gfx/geometry/rect.cc
+++ b/ui/gfx/geometry/rect.cc
@@ -15,7 +15,7 @@
 #endif
 
 #include "base/logging.h"
-#include "base/numerics/saturated_arithmetic.h"
+#include "base/numerics/clamped_math.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "ui/gfx/geometry/insets.h"
@@ -69,8 +69,8 @@
     return;
   }
 
-  int effective_span = base::SaturatedSubtraction(max, min);
-  int span_loss = base::SaturatedSubtraction(max, min + effective_span);
+  int effective_span = base::ClampSub(max, min);
+  int span_loss = base::ClampSub(max, base::ClampAdd(min, effective_span));
 
   // If the desired width is within the limits of ints, we can just
   // use the simple computations to represent the range precisely.
@@ -83,12 +83,13 @@
   // Now we have to approximate. If one of min or max is close enough
   // to zero we choose to represent that one precisely. The other side is
   // probably practically "infinite", so we move it.
-  if (base::SaturatedAbsolute(max) < std::numeric_limits<int>::max() / 2) {
+  if (base::SafeUnsignedAbs(max) <
+      base::as_unsigned(std::numeric_limits<int>::max() / 2)) {
     // Maintain origin + span == max.
     *span = effective_span;
     *origin = max - effective_span;
-  } else if (base::SaturatedAbsolute(min) <
-             std::numeric_limits<int>::max() / 2) {
+  } else if (base::SafeUnsignedAbs(min) <
+             base::as_unsigned(std::numeric_limits<int>::max() / 2)) {
     // Maintain origin == min.
     *span = effective_span;
     *origin = min;
@@ -116,10 +117,8 @@
   origin_ += Vector2d(left, top);
   // left+right might overflow/underflow, but width() - (left+right) might
   // overflow as well.
-  set_width(base::SaturatedSubtraction(width(),
-                                       base::SaturatedAddition(left, right)));
-  set_height(base::SaturatedSubtraction(height(),
-                                        base::SaturatedAddition(top, bottom)));
+  set_width(base::ClampSub(width(), base::ClampAdd(left, right)));
+  set_height(base::ClampSub(height(), base::ClampAdd(top, bottom)));
 }
 
 void Rect::Offset(int horizontal, int vertical) {
diff --git a/ui/gfx/geometry/rect.h b/ui/gfx/geometry/rect.h
index 1858d44d..4e914b8 100644
--- a/ui/gfx/geometry/rect.h
+++ b/ui/gfx/geometry/rect.h
@@ -227,7 +227,7 @@
 
   // Clamp the size to avoid integer overflow in bottom() and right().
   // This returns the width given an origin and a width.
-  // TODO(enne): this should probably use base::SaturatedAddition, but that
+  // TODO(enne): this should probably use base::ClampAdd, but that
   // function is not a constexpr.
   static constexpr int GetClampedValue(int origin, int size) {
     return AddWouldOverflow(origin, size)
diff --git a/ui/gfx/geometry/size.cc b/ui/gfx/geometry/size.cc
index 6948672..781b84d 100644
--- a/ui/gfx/geometry/size.cc
+++ b/ui/gfx/geometry/size.cc
@@ -12,8 +12,8 @@
 #include <ApplicationServices/ApplicationServices.h>
 #endif
 
+#include "base/numerics/clamped_math.h"
 #include "base/numerics/safe_math.h"
-#include "base/numerics/saturated_arithmetic.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
@@ -58,8 +58,8 @@
 }
 
 void Size::Enlarge(int grow_width, int grow_height) {
-  SetSize(base::SaturatedAddition(width(), grow_width),
-          base::SaturatedAddition(height(), grow_height));
+  SetSize(base::ClampAdd(width(), grow_width),
+          base::ClampAdd(height(), grow_height));
 }
 
 void Size::SetToMin(const Size& other) {
diff --git a/ui/gfx/geometry/vector2d.cc b/ui/gfx/geometry/vector2d.cc
index 2b4875c..0ce3b20b 100644
--- a/ui/gfx/geometry/vector2d.cc
+++ b/ui/gfx/geometry/vector2d.cc
@@ -6,7 +6,7 @@
 
 #include <cmath>
 
-#include "base/numerics/saturated_arithmetic.h"
+#include "base/numerics/clamped_math.h"
 #include "base/strings/stringprintf.h"
 
 namespace gfx {
@@ -16,13 +16,13 @@
 }
 
 void Vector2d::Add(const Vector2d& other) {
-  x_ = base::SaturatedAddition(other.x_, x_);
-  y_ = base::SaturatedAddition(other.y_, y_);
+  x_ = base::ClampAdd(other.x_, x_);
+  y_ = base::ClampAdd(other.y_, y_);
 }
 
 void Vector2d::Subtract(const Vector2d& other) {
-  x_ = base::SaturatedSubtraction(x_, other.x_);
-  y_ = base::SaturatedSubtraction(y_, other.y_);
+  x_ = base::ClampSub(x_, other.x_);
+  y_ = base::ClampSub(y_, other.y_);
 }
 
 int64_t Vector2d::LengthSquared() const {
diff --git a/ui/gfx/native_pixmap.h b/ui/gfx/native_pixmap.h
index 33def81..1677dc0 100644
--- a/ui/gfx/native_pixmap.h
+++ b/ui/gfx/native_pixmap.h
@@ -50,17 +50,6 @@
                                     const gfx::Rect& display_bounds,
                                     const gfx::RectF& crop_rect) = 0;
 
-  // This represents a callback function pointing to processing unit like VPP to
-  // do post-processing operations like scaling and color space conversion on
-  // |source_pixmap| and save processed result to |target_pixmap|.
-  typedef base::Callback<bool(const scoped_refptr<NativePixmap>& source_pixmap,
-                              scoped_refptr<NativePixmap> target_pixmap)>
-      ProcessingCallback;
-
-  // Set callback function for the pixmap used for post processing.
-  virtual void SetProcessingCallback(
-      const ProcessingCallback& processing_callback) = 0;
-
   // Export the buffer for sharing across processes.
   // Any file descriptors in the exported handle are owned by the caller.
   virtual gfx::NativePixmapHandle ExportHandle() = 0;
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index fca7ae8..6cc1392 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -72,8 +72,6 @@
     parent_->OnOverlayScheduled(display_bounds);
     return true;
   }
-  void SetProcessingCallback(
-      const ProcessingCallback& processing_callback) override {}
   gfx::NativePixmapHandle ExportHandle() override {
     return gfx::NativePixmapHandle();
   }
diff --git a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
index 60993857..c3dfd1a 100644
--- a/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/drm_overlay_validator_unittest.cc
@@ -137,8 +137,7 @@
       params.buffer_size);
   ui::OverlayPlane plane(std::move(scanout_buffer), params.plane_z_order,
                          params.transform, params.display_rect,
-                         params.crop_rect,
-                         ui::OverlayPlane::ProcessBufferCallback());
+                         params.crop_rect);
   plane_list_.push_back(plane);
 }
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index 12927573..332f0cc 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -298,12 +298,6 @@
                      const scoped_refptr<GbmBuffer>& buffer)
     : surface_manager_(surface_manager), buffer_(buffer) {}
 
-void GbmPixmap::SetProcessingCallback(
-    const ProcessingCallback& processing_callback) {
-  DCHECK(processing_callback_.is_null());
-  processing_callback_ = processing_callback;
-}
-
 gfx::NativePixmapHandle GbmPixmap::ExportHandle() {
   gfx::NativePixmapHandle handle;
   gfx::BufferFormat format =
@@ -373,44 +367,10 @@
                                      const gfx::Rect& display_bounds,
                                      const gfx::RectF& crop_rect) {
   DCHECK(buffer_->GetFlags() & GBM_BO_USE_SCANOUT);
-  OverlayPlane::ProcessBufferCallback processing_callback;
-  if (!processing_callback_.is_null())
-    processing_callback = base::Bind(&GbmPixmap::ProcessBuffer, this);
-
-  surface_manager_->GetSurface(widget)->QueueOverlayPlane(
-      OverlayPlane(buffer_, plane_z_order, plane_transform, display_bounds,
-                   crop_rect, processing_callback));
+  surface_manager_->GetSurface(widget)->QueueOverlayPlane(OverlayPlane(
+      buffer_, plane_z_order, plane_transform, display_bounds, crop_rect));
 
   return true;
 }
 
-scoped_refptr<ScanoutBuffer> GbmPixmap::ProcessBuffer(const gfx::Size& size,
-                                                      uint32_t format) {
-  DCHECK(GetBufferSize() != size ||
-         buffer_->GetFramebufferPixelFormat() != format);
-
-  if (!processed_pixmap_ || size != processed_pixmap_->GetBufferSize() ||
-      format != processed_pixmap_->buffer()->GetFramebufferPixelFormat()) {
-    // Release any old processed pixmap.
-    processed_pixmap_ = nullptr;
-    scoped_refptr<GbmBuffer> buffer = GbmBuffer::CreateBuffer(
-        buffer_->drm().get(), format, size, buffer_->GetFlags());
-    if (!buffer)
-      return nullptr;
-
-    // ProcessBuffer is called on DrmThread. We could have used
-    // CreateNativePixmap to initialize the pixmap, however it posts a
-    // synchronous task to DrmThread resulting in a deadlock.
-    processed_pixmap_ = new GbmPixmap(surface_manager_, buffer);
-  }
-
-  DCHECK(!processing_callback_.is_null());
-  if (!processing_callback_.Run(this, processed_pixmap_)) {
-    LOG(ERROR) << "Failed processing NativePixmap";
-    return nullptr;
-  }
-
-  return processed_pixmap_->buffer();
-}
-
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.h b/ui/ozone/platform/drm/gpu/gbm_buffer.h
index a8b8476..6715274 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -109,9 +109,6 @@
   GbmPixmap(GbmSurfaceFactory* surface_manager,
             const scoped_refptr<GbmBuffer>& buffer);
 
-  void SetProcessingCallback(
-      const ProcessingCallback& processing_callback) override;
-
   // NativePixmap:
   void* GetEGLClientBuffer() const override;
   bool AreDmaBufFdsValid() const override;
@@ -139,11 +136,6 @@
   GbmSurfaceFactory* surface_manager_;
   scoped_refptr<GbmBuffer> buffer_;
 
-  // OverlayValidator can request scaling or format conversions as needed for
-  // this Pixmap. This holds the processed buffer.
-  scoped_refptr<GbmPixmap> processed_pixmap_;
-  ProcessingCallback processing_callback_;
-
   DISALLOW_COPY_AND_ASSIGN(GbmPixmap);
 };
 
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.cc b/ui/ozone/platform/drm/gpu/overlay_plane.cc
index ceecb6f..e1420720 100644
--- a/ui/ozone/platform/drm/gpu/overlay_plane.cc
+++ b/ui/ozone/platform/drm/gpu/overlay_plane.cc
@@ -32,19 +32,6 @@
 OverlayPlane::~OverlayPlane() {
 }
 
-OverlayPlane::OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
-                           int z_order,
-                           gfx::OverlayTransform plane_transform,
-                           const gfx::Rect& display_bounds,
-                           const gfx::RectF& crop_rect,
-                           const ProcessBufferCallback& processing_callback)
-    : buffer(buffer),
-      z_order(z_order),
-      plane_transform(plane_transform),
-      display_bounds(display_bounds),
-      crop_rect(crop_rect),
-      processing_callback(processing_callback) {}
-
 bool OverlayPlane::operator<(const OverlayPlane& plane) const {
   return std::tie(z_order, display_bounds, crop_rect, plane_transform) <
          std::tie(plane.z_order, plane.display_bounds, plane.crop_rect,
diff --git a/ui/ozone/platform/drm/gpu/overlay_plane.h b/ui/ozone/platform/drm/gpu/overlay_plane.h
index cccf075..4bd0fcab 100644
--- a/ui/ozone/platform/drm/gpu/overlay_plane.h
+++ b/ui/ozone/platform/drm/gpu/overlay_plane.h
@@ -31,19 +31,6 @@
                const gfx::RectF& crop_rect);
   OverlayPlane(const OverlayPlane& other);
 
-  // This represents a callback function which can handle post processing
-  // operations like scaling, format conversion etc of the buffer bound to this
-  // plane and return the processed buffer.
-  typedef base::Callback<scoped_refptr<ScanoutBuffer>(const gfx::Size& size,
-                                                      uint32_t format)>
-      ProcessBufferCallback;
-  OverlayPlane(const scoped_refptr<ScanoutBuffer>& buffer,
-               int z_order,
-               gfx::OverlayTransform plane_transform,
-               const gfx::Rect& display_bounds,
-               const gfx::RectF& crop_rect,
-               const ProcessBufferCallback& processing_callback);
-
   bool operator<(const OverlayPlane& plane) const;
 
   ~OverlayPlane();
@@ -56,8 +43,6 @@
   gfx::OverlayTransform plane_transform;
   gfx::Rect display_bounds;
   gfx::RectF crop_rect;
-  // TODO(dshwang): remove unused |processing_callback|. crbug.com/683347
-  ProcessBufferCallback processing_callback;
 };
 
 }  // namespace ui
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index 56f06819..d3c9f35 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -89,8 +89,6 @@
                             const gfx::RectF& crop_rect) override {
     return true;
   }
-  void SetProcessingCallback(
-      const ProcessingCallback& processing_callback) override {}
   gfx::NativePixmapHandle ExportHandle() override {
     return gfx::NativePixmapHandle();
   }