diff --git a/DEPS b/DEPS
index 5c9c3797..c1da9cc6 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': '91db12d89c214235e24599f3ec18df2f952e99eb',
+  'skia_revision': '287f6512f34d456b593ea030197925dfc5b15c65',
   # 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': '6cddaff4ec73ce23ceec1e77829d12705dfed900',
+  'v8_revision': '409661f21439fcaeb925b0e4b680c7ef4e16ef5c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '750e652668fcfb915d77007f14c5b6befb3a704e',
+  'catapult_revision': '355ca2541b19167eea565d3cad751c3f8c26db51',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -197,7 +197,7 @@
     Var('chromium_git') + '/webm/libvpx.git' + '@' +  'd7f1d60c51b47f6d22be919362caad09469a058b',
 
   'src/third_party/ffmpeg':
-    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '7e5307d753a5a21f6d02663ccccf2acdf7aeae0e',
+    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '16cdcb08bb1cfb0e55a56e9bc2c32dffcf277953',
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + '7f9228152ab3d70e6848cc9c67389a0d4218740e',
diff --git a/ash/common/shelf/wm_shelf.cc b/ash/common/shelf/wm_shelf.cc
index ffa969a..e439381 100644
--- a/ash/common/shelf/wm_shelf.cc
+++ b/ash/common/shelf/wm_shelf.cc
@@ -166,6 +166,19 @@
 void WmShelf::SetAutoHideBehavior(ShelfAutoHideBehavior auto_hide_behavior) {
   DCHECK(shelf_layout_manager_);
 
+  // Force a stack dump when this method is invoked too frequently.
+  // This block is here temporary to help investigate http://crbug.com/665093 .
+  constexpr int kAutoHideRepeatInterval = 10000;
+  constexpr int kMaxAutoHideChangesIn10Seconds = 100;
+  if ((base::TimeTicks::Now() - time_last_auto_hide_change_).InMilliseconds() <
+      kAutoHideRepeatInterval) {
+    if (++count_auto_hide_changes_ > kMaxAutoHideChangesIn10Seconds)
+      CHECK(false);
+  } else {
+    count_auto_hide_changes_ = 0;
+  }
+  time_last_auto_hide_change_ = base::TimeTicks::Now();
+
   if (auto_hide_behavior_ == auto_hide_behavior)
     return;
 
diff --git a/ash/common/shelf/wm_shelf.h b/ash/common/shelf/wm_shelf.h
index 526b9c5..b280077 100644
--- a/ash/common/shelf/wm_shelf.h
+++ b/ash/common/shelf/wm_shelf.h
@@ -11,6 +11,7 @@
 #include "ash/common/shelf/shelf_layout_manager_observer.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "base/observer_list.h"
+#include "base/time/time.h"
 
 namespace gfx {
 class Rect;
@@ -176,6 +177,10 @@
 
   base::ObserverList<WmShelfObserver> observers_;
 
+  // Temporary. Used to investigate http://crbug.com/665093 .
+  base::TimeTicks time_last_auto_hide_change_;
+  int count_auto_hide_changes_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(WmShelf);
 };
 
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc
index 88581e5..9a14336e 100644
--- a/ash/common/wm/window_cycle_list.cc
+++ b/ash/common/wm/window_cycle_list.cc
@@ -18,6 +18,7 @@
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
+#include "ui/gfx/canvas.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/label.h"
@@ -245,10 +246,8 @@
 // A view that shows a collection of windows the user can tab through.
 class WindowCycleView : public views::WidgetDelegateView {
  public:
-  WindowCycleView(const WindowCycleList::WindowList& windows,
-                  WindowCycleController::Direction initial_direction)
-      : initial_direction_(initial_direction),
-        mirror_container_(new views::View()),
+  explicit WindowCycleView(const WindowCycleList::WindowList& windows)
+      : mirror_container_(new views::View()),
         highlight_view_(new views::View()),
         target_window_(nullptr) {
     DCHECK(!windows.empty());
@@ -263,9 +262,6 @@
       layer()->SetOpacity(1.0);
     }
 
-    set_background(views::Background::CreateSolidBackground(
-        SkColorSetA(SK_ColorBLACK, 0xE6)));
-
     const int kInsideBorderPaddingDip = 64;
     const int kBetweenChildPaddingDip = 10;
     views::BoxLayout* layout = new views::BoxLayout(
@@ -347,22 +343,27 @@
     if (first_layout)
       mirror_container_->SizeToPreferredSize();
 
-    // The preview list (|mirror_container_|) starts flush to the left of
-    // the screen but moves to the left (off the edge of the screen) as the use
-    // iterates over the previews. The list will move just enough to ensure the
-    // highlighted preview is at or to the left of the center of the workspace.
     views::View* target_view = window_view_map_[target_window_];
     gfx::RectF target_bounds(target_view->GetLocalBounds());
     views::View::ConvertRectToTarget(target_view, mirror_container_,
                                      &target_bounds);
     gfx::Rect container_bounds(mirror_container_->GetPreferredSize());
-    int x_offset =
-        width() / 2 -
-        mirror_container_->GetMirroredXInView(target_bounds.CenterPoint().x());
-    if (initial_direction_ == WindowCycleController::FORWARD)
+    // Case one: the container is narrower than the screen. Center the
+    // container.
+    int x_offset = (width() - container_bounds.width()) / 2;
+    if (x_offset < 0) {
+      // Case two: the container is wider than the screen. Center the target
+      // view by moving the list just enough to ensure the target view is in the
+      // center.
+      x_offset = width() / 2 -
+                 mirror_container_->GetMirroredXInView(
+                     target_bounds.CenterPoint().x());
+
+      // However, the container must span the screen, i.e. the maximum x is 0
+      // and the minimum for its right boundary is the width of the screen.
       x_offset = std::min(x_offset, 0);
-    else
       x_offset = std::max(x_offset, width() - container_bounds.width());
+    }
     container_bounds.set_x(x_offset);
     mirror_container_->SetBoundsRect(container_bounds);
 
@@ -391,6 +392,13 @@
     WmShell::Get()->window_cycle_controller()->StopCycling();
   }
 
+  void OnPaintBackground(gfx::Canvas* canvas) override {
+    // We can't set a bg on the mirror container itself because the highlight
+    // view needs to be on top of the bg but behind the target windows.
+    canvas->FillRect(mirror_container_->bounds(),
+                     SkColorSetA(SK_ColorBLACK, 0xE6));
+  }
+
   View* GetInitiallyFocusedView() override {
     return window_view_map_[target_window_];
   }
@@ -398,7 +406,6 @@
   WmWindow* target_window() { return target_window_; }
 
  private:
-  WindowCycleController::Direction initial_direction_;
   std::map<WmWindow*, views::View*> window_view_map_;
   views::View* mirror_container_;
   views::View* highlight_view_;
@@ -461,7 +468,6 @@
 WindowCycleList::WindowCycleList(const WindowList& windows)
     : windows_(windows),
       current_index_(0),
-      initial_direction_(WindowCycleController::FORWARD),
       cycle_view_(nullptr),
       cycle_ui_widget_(nullptr),
       screen_observer_(this) {
@@ -516,7 +522,6 @@
   DCHECK(static_cast<size_t>(current_index_) < windows_.size());
 
   if (!cycle_view_ && current_index_ == 0) {
-    initial_direction_ = direction;
     // Special case the situation where we're cycling forward but the MRU window
     // is not active. This occurs when all windows are minimized. The starting
     // window should be the first one rather than the second.
@@ -600,7 +605,7 @@
   if (cycle_view_)
     return;
 
-  cycle_view_ = new WindowCycleView(windows_, initial_direction_);
+  cycle_view_ = new WindowCycleView(windows_);
   cycle_view_->SetTargetWindow(windows_[current_index_]);
 
   views::Widget* widget = new views::Widget;
diff --git a/ash/common/wm/window_cycle_list.h b/ash/common/wm/window_cycle_list.h
index 6e08f25..d4bc8d06 100644
--- a/ash/common/wm/window_cycle_list.h
+++ b/ash/common/wm/window_cycle_list.h
@@ -81,9 +81,6 @@
   // i.e., the position of an active window in a global MRU ordering.
   int current_index_;
 
-  // The first direction the user stepped in (affects layout).
-  WindowCycleController::Direction initial_direction_;
-
   // Wrapper for the window brought to the front.
   // TODO(estade): remove ScopedShowWindow when we know we are happy launching
   // the |cycle_view_| version.
diff --git a/ash/laser/laser_pointer_controller.cc b/ash/laser/laser_pointer_controller.cc
index 5ec3dbf2..3559bad4 100644
--- a/ash/laser/laser_pointer_controller.cc
+++ b/ash/laser/laser_pointer_controller.cc
@@ -7,8 +7,6 @@
 #include "ash/common/system/chromeos/palette/palette_utils.h"
 #include "ash/laser/laser_pointer_view.h"
 #include "ash/shell.h"
-#include "ui/aura/window_event_dispatcher.h"
-#include "ui/aura/window_tree_host.h"
 #include "ui/display/screen.h"
 #include "ui/views/widget/widget.h"
 
@@ -24,15 +22,6 @@
 // |kPointLifeDurationMs| can get removed.
 const int kAddStationaryPointsDelayMs = 5;
 
-aura::Window* GetCurrentRootWindow() {
-  aura::Window::Windows root_windows = Shell::GetAllRootWindows();
-  for (aura::Window* root_window : root_windows) {
-    if (root_window->ContainsPointInRoot(
-            root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot()))
-      return root_window;
-  }
-  return nullptr;
-}
 }  // namespace
 
 LaserPointerController::LaserPointerController()
@@ -58,7 +47,7 @@
     laser_pointer_view_.reset();
 }
 
-void LaserPointerController::OnMouseEvent(ui::MouseEvent* event) {
+void LaserPointerController::OnTouchEvent(ui::TouchEvent* event) {
   if (!enabled_)
     return;
 
@@ -66,41 +55,34 @@
       ui::EventPointerType::POINTER_TYPE_PEN)
     return;
 
-  if (event->type() != ui::ET_MOUSE_DRAGGED &&
-      event->type() != ui::ET_MOUSE_PRESSED &&
-      event->type() != ui::ET_MOUSE_RELEASED)
+  if (event->type() != ui::ET_TOUCH_MOVED &&
+      event->type() != ui::ET_TOUCH_PRESSED &&
+      event->type() != ui::ET_TOUCH_RELEASED)
     return;
 
-  aura::Window* current_window = GetCurrentRootWindow();
-  if (!current_window) {
-    DestroyLaserPointerView();
-    return;
-  }
-
-  // Compute the event coordinate relative to the display it is currently on
-  // (and not the one the event was captured on).
+  // Find the root window that the event was captured on. We never need to
+  // switch between different root windows because it is not physically possible
+  // to seamlessly drag a finger between two displays like it is with a mouse.
   gfx::Point event_location = event->root_location();
-  aura::Window* target = static_cast<aura::Window*>(event->target());
-  aura::Window* event_root = target->GetRootWindow();
-  aura::Window::ConvertPointToTarget(event_root, current_window,
-                                     &event_location);
+  aura::Window* current_window =
+      static_cast<aura::Window*>(event->target())->GetRootWindow();
 
-  // Start a new laser session if the mouse is pressed but not pressed over the
+  // Start a new laser session if the stylus is pressed but not pressed over the
   // palette.
-  if (event->type() == ui::ET_MOUSE_PRESSED &&
+  if (event->type() == ui::ET_TOUCH_PRESSED &&
       !PaletteContainsPointInScreen(event_location)) {
     DestroyLaserPointerView();
     UpdateLaserPointerView(current_window, event_location, event);
   }
 
   // Do not update laser if it is in the process of fading away.
-  if (event->type() == ui::ET_MOUSE_DRAGGED && laser_pointer_view_ &&
+  if (event->type() == ui::ET_TOUCH_MOVED && laser_pointer_view_ &&
       !is_fading_away_) {
     UpdateLaserPointerView(current_window, event_location, event);
     RestartTimer();
   }
 
-  if (event->type() == ui::ET_MOUSE_RELEASED && laser_pointer_view_ &&
+  if (event->type() == ui::ET_TOUCH_RELEASED && laser_pointer_view_ &&
       !is_fading_away_) {
     is_fading_away_ = true;
     UpdateLaserPointerView(current_window, event_location, event);
@@ -116,9 +98,9 @@
     aura::Window* root_window) {
   if (!root_window) {
     DestroyLaserPointerView();
-  } else if (laser_pointer_view_) {
-    laser_pointer_view_->ReparentWidget(root_window);
-  } else if (enabled_) {
+  }
+
+  if (!laser_pointer_view_ && enabled_) {
     laser_pointer_view_.reset(new LaserPointerView(
         base::TimeDelta::FromMilliseconds(kPointLifeDurationMs), root_window));
   }
@@ -127,10 +109,10 @@
 void LaserPointerController::UpdateLaserPointerView(
     aura::Window* current_window,
     const gfx::Point& event_location,
-    ui::MouseEvent* event) {
+    ui::Event* event) {
   SwitchTargetRootWindowIfNeeded(current_window);
-  current_mouse_location_ = event_location;
-  laser_pointer_view_->AddNewPoint(current_mouse_location_);
+  current_stylus_location_ = event_location;
+  laser_pointer_view_->AddNewPoint(current_stylus_location_);
   event->StopPropagation();
 }
 
@@ -154,9 +136,9 @@
   if (is_fading_away_)
     laser_pointer_view_->UpdateTime();
   else
-    laser_pointer_view_->AddNewPoint(current_mouse_location_);
+    laser_pointer_view_->AddNewPoint(current_stylus_location_);
 
-  // We can stop repeating the timer once the mouse has been stationary for
+  // We can stop repeating the timer once the stylus has been stationary for
   // longer than the life of a point.
   if (stationary_timer_repeat_count_ * kAddStationaryPointsDelayMs >=
       kPointLifeDurationMs) {
diff --git a/ash/laser/laser_pointer_controller.h b/ash/laser/laser_pointer_controller.h
index 13a0914..8ccd0f40 100644
--- a/ash/laser/laser_pointer_controller.h
+++ b/ash/laser/laser_pointer_controller.h
@@ -17,10 +17,6 @@
 class Timer;
 }
 
-namespace ui {
-class MouseEvent;
-}
-
 namespace ash {
 
 class LaserPointerView;
@@ -41,17 +37,16 @@
   friend class LaserPointerControllerTestApi;
 
   // ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override;
+  void OnTouchEvent(ui::TouchEvent* event) override;
 
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override;
 
-  // Reparent, recreate or destroy LaserPointerView instance as needed based on
-  // the current window and the widgets window.
+  // Handles monitor disconnect/swap primary.
   void SwitchTargetRootWindowIfNeeded(aura::Window* root_window);
 
-  // Timer callback which adds a point where the mouse was last seen. This
-  // allows the trail to fade away when the mouse is stationary.
+  // Timer callback which adds a point where the stylus was last seen. This
+  // allows the trail to fade away when the stylus is stationary.
   void AddStationaryPoint();
 
   // Updates |laser_pointer_view_| by changing its root window or creating it if
@@ -59,14 +54,14 @@
   // propagation of |event|.
   void UpdateLaserPointerView(aura::Window* current_window,
                               const gfx::Point& event_location,
-                              ui::MouseEvent* event);
+                              ui::Event* event);
 
   // Destroys |laser_pointer_view_|, if it exists.
   void DestroyLaserPointerView();
 
   void RestartTimer();
 
-  // Timer which will add a new stationary point when the mouse stops moving.
+  // Timer which will add a new stationary point when the stylus stops moving.
   // This will remove points that are too old.
   std::unique_ptr<base::Timer> stationary_timer_;
   int stationary_timer_repeat_count_ = 0;
@@ -79,8 +74,8 @@
   // to be destroyed, such as when the stylus is released.
   bool is_fading_away_ = false;
 
-  // The last seen mouse location in screen coordinates.
-  gfx::Point current_mouse_location_;
+  // The last seen stylus location in screen coordinates.
+  gfx::Point current_stylus_location_;
 
   // |laser_pointer_view_| will only hold an instance when the laser pointer is
   // enabled and activated (pressed or dragged).
diff --git a/ash/laser/laser_pointer_controller_unittest.cc b/ash/laser/laser_pointer_controller_unittest.cc
index fd35dc6..84818c7 100644
--- a/ash/laser/laser_pointer_controller_unittest.cc
+++ b/ash/laser/laser_pointer_controller_unittest.cc
@@ -156,7 +156,7 @@
   GetEventGenerator().EnterPenPointerMode();
 
   // When disabled the laser pointer should not be showing.
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(1, 1));
+  GetEventGenerator().MoveTouch(gfx::Point(1, 1));
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
 
   // Verify that by enabling the mode, the laser pointer should still not be
@@ -165,27 +165,27 @@
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
 
   // Verify moving the stylus 4 times will not display the laser pointer.
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(2, 2));
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(3, 3));
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(4, 4));
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(5, 5));
+  GetEventGenerator().MoveTouch(gfx::Point(2, 2));
+  GetEventGenerator().MoveTouch(gfx::Point(3, 3));
+  GetEventGenerator().MoveTouch(gfx::Point(4, 4));
+  GetEventGenerator().MoveTouch(gfx::Point(5, 5));
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
 
   // Verify pressing the stylus will show the laser pointer and add a point but
   // will not activate fading out.
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   EXPECT_TRUE(controller_test_api_.IsShowingLaserPointer());
   EXPECT_FALSE(controller_test_api_.IsFadingAway());
   EXPECT_EQ(1, controller_test_api_.laser_points().GetNumberOfPoints());
 
   // Verify dragging the stylus 2 times will add 2 more points.
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(6, 6));
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(7, 7));
+  GetEventGenerator().MoveTouch(gfx::Point(6, 6));
+  GetEventGenerator().MoveTouch(gfx::Point(7, 7));
   EXPECT_EQ(3, controller_test_api_.laser_points().GetNumberOfPoints());
 
   // Verify releasing the stylus still shows the laser pointer, which is fading
   // away.
-  GetEventGenerator().ReleaseLeftButton();
+  GetEventGenerator().ReleaseTouch();
   EXPECT_TRUE(controller_test_api_.IsShowingLaserPointer());
   EXPECT_TRUE(controller_test_api_.IsFadingAway());
 
@@ -197,27 +197,27 @@
   // display the laser pointer.
   controller_test_api_.SetIsFadingAway(false);
   controller_test_api_.SetEnabled(true);
-  GetEventGenerator().PressLeftButton();
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(6, 6));
+  GetEventGenerator().PressTouch();
+  GetEventGenerator().MoveTouch(gfx::Point(6, 6));
   EXPECT_TRUE(controller_test_api_.IsShowingLaserPointer());
   controller_test_api_.SetEnabled(false);
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
 
   // Verify that the laser pointer does not add points while disabled.
-  GetEventGenerator().PressLeftButton();
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(8, 8));
-  GetEventGenerator().ReleaseLeftButton();
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(9, 9));
+  GetEventGenerator().PressTouch();
+  GetEventGenerator().MoveTouch(gfx::Point(8, 8));
+  GetEventGenerator().ReleaseTouch();
+  GetEventGenerator().MoveTouch(gfx::Point(9, 9));
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
 
   // Verify that the laser pointer does not get shown if points are not coming
   // from the stylus, even when enabled.
   GetEventGenerator().ExitPenPointerMode();
   controller_test_api_.SetEnabled(true);
-  GetEventGenerator().PressLeftButton();
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(10, 10));
-  GetEventGenerator().MoveMouseToInHost(gfx::Point(11, 11));
+  GetEventGenerator().PressTouch();
+  GetEventGenerator().MoveTouch(gfx::Point(10, 10));
+  GetEventGenerator().MoveTouch(gfx::Point(11, 11));
   EXPECT_FALSE(controller_test_api_.IsShowingLaserPointer());
-  GetEventGenerator().ReleaseLeftButton();
+  GetEventGenerator().ReleaseTouch();
 }
 }  // namespace ash
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc
index 0dc19bf..4f3bbe6 100644
--- a/ash/laser/laser_pointer_view.cc
+++ b/ash/laser/laser_pointer_view.cc
@@ -70,21 +70,6 @@
   SchedulePaint();
 }
 
-aura::Window* LaserPointerView::GetRootWindow() {
-  return widget_->GetNativeView()->GetRootWindow();
-}
-
-void LaserPointerView::ReparentWidget(aura::Window* new_root_window) {
-  if (GetRootWindow() != new_root_window) {
-    // TODO(sammiequon): Investigate if we should stop (which removes all
-    // points) or keep the old points. See http://crbug.com/647793.
-    Stop();
-    views::Widget::ReparentNativeView(
-        widget_->GetNativeView(),
-        Shell::GetContainer(new_root_window, kShellWindowId_OverlayContainer));
-  }
-}
-
 void LaserPointerView::AddNewPoint(const gfx::Point& new_point) {
   laser_points_.AddPoint(new_point);
   OnPointsUpdated();
diff --git a/ash/laser/laser_pointer_view.h b/ash/laser/laser_pointer_view.h
index d7e1658..11acfcb 100644
--- a/ash/laser/laser_pointer_view.h
+++ b/ash/laser/laser_pointer_view.h
@@ -37,11 +37,6 @@
   void UpdateTime();
   void Stop();
 
-  aura::Window* GetRootWindow();
-
-  // Reparents the widget if needed.
-  void ReparentWidget(aura::Window* new_root_window);
-
  private:
   friend class LaserPointerControllerTestApi;
 
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc
index 784ed1f5..260d7c3 100644
--- a/ash/magnifier/partial_magnification_controller.cc
+++ b/ash/magnifier/partial_magnification_controller.cc
@@ -233,10 +233,6 @@
   }
 }
 
-void PartialMagnificationController::OnMouseEvent(ui::MouseEvent* event) {
-  OnLocatedEvent(event, event->pointer_details());
-}
-
 void PartialMagnificationController::OnTouchEvent(ui::TouchEvent* event) {
   OnLocatedEvent(event, event->pointer_details());
 }
@@ -283,12 +279,12 @@
   wm::ConvertPointToScreen(event_root, &screen_point);
 
   // If the stylus is pressed on the palette icon or widget, do not activate.
-  if (event->type() == ui::ET_MOUSE_PRESSED &&
+  if (event->type() == ui::ET_TOUCH_PRESSED &&
       !PaletteContainsPointInScreen(screen_point)) {
     SetActive(true);
   }
 
-  if (event->type() == ui::ET_MOUSE_RELEASED)
+  if (event->type() == ui::ET_TOUCH_RELEASED)
     SetActive(false);
 
   if (!is_active_)
diff --git a/ash/magnifier/partial_magnification_controller.h b/ash/magnifier/partial_magnification_controller.h
index 146f672..c6e532b 100644
--- a/ash/magnifier/partial_magnification_controller.h
+++ b/ash/magnifier/partial_magnification_controller.h
@@ -51,7 +51,6 @@
   class ContentMask;
 
   // ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override;
   void OnTouchEvent(ui::TouchEvent* event) override;
 
   // WindowObserver:
diff --git a/ash/magnifier/partial_magnification_controller_unittest.cc b/ash/magnifier/partial_magnification_controller_unittest.cc
index 72ce87a4..f0f571e 100644
--- a/ash/magnifier/partial_magnification_controller_unittest.cc
+++ b/ash/magnifier/partial_magnification_controller_unittest.cc
@@ -71,17 +71,17 @@
   GetEventGenerator().EnterPenPointerMode();
 
   // While disabled no magnifier shows up.
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   EXPECT_FALSE(GetTestApi().is_active());
   EXPECT_FALSE(GetTestApi().host_widget());
-  GetEventGenerator().ReleaseLeftButton();
+  GetEventGenerator().ReleaseTouch();
 
   // While enabled the magnifier is only active while the pointer is down.
   GetController()->SetEnabled(true);
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   EXPECT_TRUE(GetTestApi().is_active());
   EXPECT_TRUE(GetTestApi().host_widget());
-  GetEventGenerator().ReleaseLeftButton();
+  GetEventGenerator().ReleaseTouch();
   EXPECT_FALSE(GetTestApi().is_active());
   EXPECT_FALSE(GetTestApi().host_widget());
 }
@@ -96,8 +96,8 @@
   // Active magnifier with two displays, move it to the second display.
   UpdateDisplay("800x600,800x600");
   GetController()->SetEnabled(true);
-  GetEventGenerator().PressLeftButton();
-  GetEventGenerator().MoveMouseTo(gfx::Point(1200, 300));
+  GetEventGenerator().PressTouch();
+  GetEventGenerator().MoveTouch(gfx::Point(1200, 300));
   EXPECT_TRUE(GetTestApi().is_active());
   EXPECT_TRUE(GetTestApi().host_widget());
 
@@ -113,7 +113,7 @@
   GetEventGenerator().EnterPenPointerMode();
 
   GetController()->SetEnabled(true);
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   EXPECT_TRUE(GetTestApi().is_active());
 
   GetController()->SetEnabled(false);
@@ -124,7 +124,6 @@
 // The magnifier only activates for pointer events.
 TEST_F(PartialMagnificationControllerTest, ActivatesOnlyForPointer) {
   GetController()->SetEnabled(true);
-  GetEventGenerator().PressRightButton();
   GetEventGenerator().PressTouch();
   EXPECT_FALSE(GetTestApi().is_active());
 }
@@ -136,29 +135,29 @@
 
   // The window does not have to be centered on the press; compute the initial
   // window placement offset. Use a Vector2d for the + operator overload.
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   gfx::Vector2d offset(GetTestApi().GetWidgetOrigin().x(),
                        GetTestApi().GetWidgetOrigin().y());
 
   // Move the pointer around, make sure the window follows it.
-  GetEventGenerator().MoveMouseTo(gfx::Point(32, 32));
+  GetEventGenerator().MoveTouch(gfx::Point(32, 32));
   EXPECT_EQ(GetEventGenerator().current_location() + offset,
             GetTestApi().GetWidgetOrigin());
 
-  GetEventGenerator().MoveMouseTo(gfx::Point(0, 10));
+  GetEventGenerator().MoveTouch(gfx::Point(0, 10));
   EXPECT_EQ(GetEventGenerator().current_location() + offset,
             GetTestApi().GetWidgetOrigin());
 
-  GetEventGenerator().MoveMouseTo(gfx::Point(10, 0));
+  GetEventGenerator().MoveTouch(gfx::Point(10, 0));
   EXPECT_EQ(GetEventGenerator().current_location() + offset,
             GetTestApi().GetWidgetOrigin());
 
-  GetEventGenerator().ReleaseLeftButton();
+  GetEventGenerator().ReleaseTouch();
 
   // Make sure the window is initially placed correctly.
   GetEventGenerator().set_current_location(gfx::Point(50, 20));
   EXPECT_FALSE(GetTestApi().is_active());
-  GetEventGenerator().PressLeftButton();
+  GetEventGenerator().PressTouch();
   EXPECT_EQ(GetEventGenerator().current_location() + offset,
             GetTestApi().GetWidgetOrigin());
 }
diff --git a/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
index a27af600..4acd482 100644
--- a/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
+++ b/ash/system/chromeos/power/tablet_power_button_controller_unittest.cc
@@ -308,10 +308,12 @@
   generator_->set_flags(ui::EF_NONE);
   EXPECT_TRUE(GetBacklightsForcedOff());
 
-  // Stylus mouse event should not SetBacklightsForcedOff(false).
+  // Stylus event should not SetBacklightsForcedOff(false).
   EXPECT_TRUE(GetBacklightsForcedOff());
   generator_->EnterPenPointerMode();
-  generator_->MoveMouseBy(1, 1);
+  generator_->PressTouch();
+  generator_->MoveTouch(gfx::Point(1, 1));
+  generator_->ReleaseTouch();
   EXPECT_TRUE(GetBacklightsForcedOff());
   generator_->ExitPenPointerMode();
 }
diff --git a/ash/utility/screenshot_controller_unittest.cc b/ash/utility/screenshot_controller_unittest.cc
index a507685..3653982c 100644
--- a/ash/utility/screenshot_controller_unittest.cc
+++ b/ash/utility/screenshot_controller_unittest.cc
@@ -179,14 +179,14 @@
 
   generator.EnterPenPointerMode();
   generator.set_current_location(gfx::Point(100, 100));
-  generator.PressLeftButton();
+  generator.PressTouch();
   EXPECT_EQ(0, test_delegate->handle_take_partial_screenshot_count());
   EXPECT_EQ(gfx::Point(100, 100), GetStartPosition());
 
-  generator.MoveMouseBy(200, 200);
+  generator.MoveTouch(gfx::Point(300, 300));
   EXPECT_EQ(0, test_delegate->handle_take_partial_screenshot_count());
 
-  generator.ReleaseLeftButton();
+  generator.ReleaseTouch();
   EXPECT_EQ(gfx::Rect(100, 100, 200, 200),
             GetScreenshotDelegate()->last_rect());
   EXPECT_EQ(1, GetScreenshotDelegate()->handle_take_partial_screenshot_count());
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 3d21aa4..91667d16 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -251,6 +251,7 @@
     "build_time.cc",
     "build_time.h",
     "callback.h",
+    "callback_forward.h",
     "callback_helpers.cc",
     "callback_helpers.h",
     "callback_internal.cc",
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 07b78aa..f0918cd 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -135,20 +135,6 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
   };
 
-  // Constructing a ScopedAllowSingleton temporarily allows accessing for the
-  // current thread.  Doing this is almost always incorrect.
-  class BASE_EXPORT ScopedAllowSingleton {
-   public:
-    ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
-    ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
-   private:
-    // Whether singleton use is allowed when the ScopedAllowSingleton was
-    // constructed.
-    bool previous_value_;
-
-    DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
-  };
-
 #if DCHECK_IS_ON()
   // Set whether the current thread to make IO calls.
   // Threads start out in the *allowed* state.
diff --git a/blimp/engine/app/blimp_engine_crash_keys.cc b/blimp/engine/app/blimp_engine_crash_keys.cc
index 42bcdb7..d678788 100644
--- a/blimp/engine/app/blimp_engine_crash_keys.cc
+++ b/blimp/engine/app/blimp_engine_crash_keys.cc
@@ -33,6 +33,7 @@
       { "channel_error_bt", crash_keys::kMediumSize },
       { "discardable-memory-allocated", crash_keys::kSmallSize },
       { "discardable-memory-free", crash_keys::kSmallSize },
+      { "mojo-message-error", crash_keys::kMediumSize },
       { "ppapi_path", crash_keys::kMediumSize },
       { "remove_route_bt", crash_keys::kMediumSize },
       { "rwhvm_window", crash_keys::kMediumSize },
diff --git a/build/android/PRESUBMIT.py b/build/android/PRESUBMIT.py
index 54552b3..fcbe716 100644
--- a/build/android/PRESUBMIT.py
+++ b/build/android/PRESUBMIT.py
@@ -63,6 +63,8 @@
           J('pylib', 'results', 'json_results_test.py'),
           J('pylib', 'symbols', 'elf_symbolizer_unittest.py'),
           J('pylib', 'utils', 'device_dependencies_test.py'),
+          J('pylib', 'utils', 'dexdump_test.py'),
+          J('pylib', 'utils', 'proguard_test.py'),
       ],
       env=pylib_test_env))
 
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index daaa1f9..c11fd5f 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -18,6 +18,7 @@
 from pylib.constants import host_paths
 from pylib.instrumentation import test_result
 from pylib.instrumentation import instrumentation_parser
+from pylib.utils import dexdump
 from pylib.utils import proguard
 
 with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
@@ -61,7 +62,7 @@
         ', '.join('@' + a for a in _VALID_ANNOTATIONS))
 
 
-class ProguardPickleException(test_exception.TestException):
+class TestListPickleException(test_exception.TestException):
   pass
 
 
@@ -281,11 +282,11 @@
   return filtered_tests
 
 
-def GetAllTests(test_jar):
+def GetAllTestsFromJar(test_jar):
   pickle_path = '%s-proguard.pickle' % test_jar
   try:
     tests = _GetTestsFromPickle(pickle_path, test_jar)
-  except ProguardPickleException as e:
+  except TestListPickleException as e:
     logging.info('Could not get tests from pickle: %s', e)
     logging.info('Getting tests from JAR via proguard.')
     tests = _GetTestsFromProguard(test_jar)
@@ -293,11 +294,23 @@
   return tests
 
 
+def GetAllTestsFromApk(test_apk):
+  pickle_path = '%s-dexdump.pickle' % test_apk
+  try:
+    tests = _GetTestsFromPickle(pickle_path, test_apk)
+  except TestListPickleException as e:
+    logging.info('Could not get tests from pickle: %s', e)
+    logging.info('Getting tests from dex via dexdump.')
+    tests = _GetTestsFromDexdump(test_apk)
+    _SaveTestsToPickle(pickle_path, test_apk, tests)
+  return tests
+
+
 def _GetTestsFromPickle(pickle_path, jar_path):
   if not os.path.exists(pickle_path):
-    raise ProguardPickleException('%s does not exist.' % pickle_path)
+    raise TestListPickleException('%s does not exist.' % pickle_path)
   if os.path.getmtime(pickle_path) <= os.path.getmtime(jar_path):
-    raise ProguardPickleException(
+    raise TestListPickleException(
         '%s newer than %s.' % (jar_path, pickle_path))
 
   with open(pickle_path, 'r') as pickle_file:
@@ -305,9 +318,9 @@
   jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
 
   if pickle_data['VERSION'] != _PICKLE_FORMAT_VERSION:
-    raise ProguardPickleException('PICKLE_FORMAT_VERSION has changed.')
+    raise TestListPickleException('PICKLE_FORMAT_VERSION has changed.')
   if pickle_data['JAR_MD5SUM'] != jar_md5:
-    raise ProguardPickleException('JAR file MD5 sum differs.')
+    raise TestListPickleException('JAR file MD5 sum differs.')
   return pickle_data['TEST_METHODS']
 
 
@@ -341,6 +354,30 @@
           if is_test_class(c)]
 
 
+def _GetTestsFromDexdump(test_apk):
+  d = dexdump.Dump(test_apk)
+  tests = []
+
+  def get_test_methods(methods):
+    return [
+        {
+          'method': m,
+          # No annotation info is available from dexdump.
+          # Set MediumTest annotation for default.
+          'annotations': {'MediumTest': None},
+        } for m in methods if m.startswith('test')]
+
+  for package_name, package_info in d.iteritems():
+    for class_name, class_info in package_info['classes'].iteritems():
+      if class_name.endswith('Test'):
+        tests.append({
+            'class': '%s.%s' % (package_name, class_name),
+            'annotations': {},
+            'methods': get_test_methods(class_info['methods']),
+        })
+  return tests
+
+
 def _SaveTestsToPickle(pickle_path, jar_path, tests):
   jar_md5 = md5sum.CalculateHostMd5Sums(jar_path)[jar_path]
   pickle_data = {
@@ -497,7 +534,11 @@
 
     if not os.path.exists(self._test_apk.path):
       error_func('Unable to find test APK: %s' % self._test_apk.path)
-    if not self._test_jar or not os.path.exists(self._test_jar):
+    if not self._test_jar:
+      logging.warning('Test jar not specified. Test runner will not have '
+                      'Java annotation info available. May not handle test '
+                      'timeouts correctly.')
+    elif not os.path.exists(self._test_jar):
       error_func('Unable to find test JAR: %s' % self._test_jar)
 
     self._test_package = self._test_apk.GetPackageName()
@@ -692,7 +733,10 @@
     return self._data_deps
 
   def GetTests(self):
-    tests = GetAllTests(self.test_jar)
+    if self.test_jar:
+      tests = GetAllTestsFromJar(self.test_jar)
+    else:
+      tests = GetAllTestsFromApk(self.test_apk.path)
     inflated_tests = self._ParametrizeTestsWithFlags(self._InflateTests(tests))
     filtered_tests = FilterTests(
         inflated_tests, self._test_filter, self._annotations,
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
index 8c0870e..c7f609ca 100755
--- a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
@@ -94,6 +94,7 @@
       },
     ]
 
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -131,6 +132,7 @@
     ]
 
     o._test_filter = 'org.chromium.test.SampleTest.testMethod1'
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -178,6 +180,7 @@
     ]
 
     o._test_filter = 'org.chromium.test.SampleTest2.*'
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -216,7 +219,7 @@
 
     o._GetTestsFromPickle = mock.MagicMock(return_value=raw_tests)
     o._test_filter = '*-org.chromium.test.SampleTest.testMethod1'
-
+    o._test_jar = 'path/to/test.jar'
     expected_tests = [
       {
         'annotations': {
@@ -288,6 +291,7 @@
     ]
 
     o._annotations = [('SmallTest', None)]
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -335,6 +339,7 @@
     ]
 
     o._excluded_annotations = [('SmallTest', None)]
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -392,6 +397,7 @@
     ]
 
     o._annotations = [('TestValue', '1')]
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -439,6 +445,7 @@
     ]
 
     o._annotations = [('Feature', 'Bar')]
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
@@ -497,6 +504,7 @@
     ]
 
     o._annotations = [('Feature', 'Bar'), ('Feature', 'Baz')]
+    o._test_jar = 'path/to/test.jar'
     with mock.patch(_INSTRUMENTATION_TEST_INSTANCE_PATH % '_GetTestsFromPickle',
                     return_value=raw_tests):
       actual_tests = o.GetTests()
diff --git a/build/android/pylib/local/device/local_device_environment.py b/build/android/pylib/local/device/local_device_environment.py
index 149eccf7..a200ca2 100644
--- a/build/android/pylib/local/device/local_device_environment.py
+++ b/build/android/pylib/local/device/local_device_environment.py
@@ -187,9 +187,14 @@
       # so that an invalid cache can be flushed just by disabling it for one
       # run.
       cache_path = _DeviceCachePath(d)
-      with open(cache_path, 'w') as f:
-        f.write(d.DumpCacheData())
-        logging.info('Wrote device cache: %s', cache_path)
+      if os.path.exists(os.path.dirname(cache_path)):
+        with open(cache_path, 'w') as f:
+          f.write(d.DumpCacheData())
+          logging.info('Wrote device cache: %s', cache_path)
+      else:
+        logging.warning(
+            'Unable to write device cache as %s directory does not exist',
+            os.path.dirname(cache_path))
 
     self.parallel_devices.pMap(tear_down_device)
 
diff --git a/build/android/pylib/utils/dexdump.py b/build/android/pylib/utils/dexdump.py
new file mode 100644
index 0000000..972a22d49
--- /dev/null
+++ b/build/android/pylib/utils/dexdump.py
@@ -0,0 +1,110 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import shutil
+import tempfile
+from xml.etree import ElementTree
+
+from devil.utils import cmd_helper
+from pylib import constants
+
+DEXDUMP_PATH = os.path.join(constants.ANDROID_SDK_TOOLS, 'dexdump')
+
+
+def Dump(apk_path):
+  """Dumps class and method information from a APK into a dict via dexdump.
+
+  Args:
+    apk_path: An absolute path to an APK file to dump.
+  Returns:
+    A dict in the following format:
+      {
+        <package_name>: {
+          'classes': {
+            <class_name>: {
+              'methods': [<method_1>, <method_2>]
+            }
+          }
+        }
+      }
+  """
+  # TODO(mikecase): Support multi-dex
+  try:
+    dexfile_dir = tempfile.mkdtemp()
+    # Python zipfile module is unable to unzip APKs.
+    cmd_helper.RunCmd(['unzip', apk_path, 'classes.dex'], cwd=dexfile_dir)
+    dexfile = os.path.join(dexfile_dir, 'classes.dex')
+    output_xml = cmd_helper.GetCmdOutput([DEXDUMP_PATH, '-l', 'xml', dexfile])
+    return _ParseRootNode(ElementTree.fromstring(output_xml))
+  finally:
+    shutil.rmtree(dexfile_dir)
+
+
+def _ParseRootNode(root):
+  """Parses the XML output of dexdump. This output is in the following format.
+
+  This is a subset of the information contained within dexdump output.
+
+  <api>
+    <package name="foo.bar">
+      <class name="Class" extends="foo.bar.SuperClass">
+        <field name="Field">
+        </field>
+        <constructor name="Method">
+          <parameter name="Param" type="int">
+          </parameter>
+        </constructor>
+        <method name="Method">
+          <parameter name="Param" type="int">
+          </parameter>
+        </method>
+      </class>
+    </package>
+  </api>
+  """
+  results = {}
+  for child in root:
+    if child.tag == 'package':
+      results[child.attrib['name']] = _ParsePackageNode(child)
+  return results
+
+
+def _ParsePackageNode(package_node):
+  """Parses a <package> node from the dexdump xml output.
+
+  Returns:
+    A dict in the format:
+      {
+        'classes': {
+          <class_1>: {
+            'methods': [<method_1>, <method_2>]
+          },
+          <class_2>: {
+            'methods': [<method_1>, <method_2>]
+          },
+        }
+      }
+  """
+  classes = {}
+  for child in package_node:
+    if child.tag == 'class':
+      classes[child.attrib['name']] = _ParseClassNode(child)
+  return {'classes': classes}
+
+
+def _ParseClassNode(class_node):
+  """Parses a <class> node from the dexdump xml output.
+
+  Returns:
+    A dict in the format:
+      {
+        'methods': [<method_1>, <method_2>]
+      }
+  """
+  methods = []
+  for child in class_node:
+    if child.tag == 'method':
+      methods.append(child.attrib['name'])
+  return {'methods': methods}
diff --git a/build/android/pylib/utils/dexdump_test.py b/build/android/pylib/utils/dexdump_test.py
new file mode 100755
index 0000000..b8b7964
--- /dev/null
+++ b/build/android/pylib/utils/dexdump_test.py
@@ -0,0 +1,136 @@
+#! /usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+from xml.etree import ElementTree
+
+from pylib.utils import dexdump
+
+# pylint: disable=protected-access
+
+
+class DexdumpXMLParseTest(unittest.TestCase):
+
+  def testParseRootXmlNode(self):
+    example_xml_string = (
+        '<api>'
+        '<package name="com.foo.bar1">'
+        '<class'
+        '  name="Class1"'
+        '  extends="java.lang.Object"'
+        '  abstract="false"'
+        '  static="false"'
+        '  final="true"'
+        '  visibility="public">'
+        '<method'
+        '  name="class1Method1"'
+        '  return="java.lang.String"'
+        '  abstract="false"'
+        '  native="false"'
+        '  synchronized="false"'
+        '  static="false"'
+        '  final="false"'
+        '  visibility="public">'
+        '</method>'
+        '<method'
+        '  name="class1Method2"'
+        '  return="viod"'
+        '  abstract="false"'
+        '  native="false"'
+        '  synchronized="false"'
+        '  static="false"'
+        '  final="false"'
+        '  visibility="public">'
+        '</method>'
+        '</class>'
+        '<class'
+        '  name="Class2"'
+        '  extends="java.lang.Object"'
+        '  abstract="false"'
+        '  static="false"'
+        '  final="true"'
+        '  visibility="public">'
+        '<method'
+        '  name="class2Method1"'
+        '  return="java.lang.String"'
+        '  abstract="false"'
+        '  native="false"'
+        '  synchronized="false"'
+        '  static="false"'
+        '  final="false"'
+        '  visibility="public">'
+        '</method>'
+        '</class>'
+        '</package>'
+        '<package name="com.foo.bar2">'
+        '</package>'
+        '<package name="com.foo.bar3">'
+        '</package>'
+        '</api>')
+
+    actual = dexdump._ParseRootNode(
+        ElementTree.fromstring(example_xml_string))
+
+    expected = {
+      'com.foo.bar1' : {
+        'classes': {
+          'Class1': {
+            'methods': ['class1Method1', 'class1Method2'],
+          },
+          'Class2': {
+            'methods': ['class2Method1'],
+          }
+        },
+      },
+      'com.foo.bar2' : {'classes': {}},
+      'com.foo.bar3' : {'classes': {}},
+    }
+    self.assertEquals(expected, actual)
+
+  def testParsePackageNode(self):
+    example_xml_string = (
+        '<package name="com.foo.bar">'
+        '<class name="Class1">'
+        '</class>'
+        '<class name="Class2">'
+        '</class>'
+        '</package>')
+
+
+    actual = dexdump._ParsePackageNode(
+        ElementTree.fromstring(example_xml_string))
+
+    expected = {
+      'classes': {
+        'Class1': {
+          'methods': [],
+        },
+        'Class2': {
+          'methods': [],
+        },
+      },
+    }
+    self.assertEquals(expected, actual)
+
+  def testParseClassNode(self):
+    example_xml_string = (
+        '<class name="Class1">'
+        '<method name="method1">'
+        '</method>'
+        '<method name="method2">'
+        '</method>'
+        '</class>')
+
+    actual = dexdump._ParseClassNode(
+        ElementTree.fromstring(example_xml_string))
+
+    expected = {
+      'methods': ['method1', 'method2'],
+    }
+    self.assertEquals(expected, actual)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/pylib/utils/proguard_test.py b/build/android/pylib/utils/proguard_test.py
old mode 100644
new mode 100755
index 497e12d..7672476
--- a/build/android/pylib/utils/proguard_test.py
+++ b/build/android/pylib/utils/proguard_test.py
@@ -1,3 +1,4 @@
+#! /usr/bin/env python
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
@@ -488,3 +489,7 @@
       ]
     }
     self.assertEquals(expected, actual)
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 8bf0120..505bd2a 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -355,7 +355,7 @@
                      help='Path or name of the apk containing the tests '
                           '(name is without the .apk extension; '
                           'e.g. "ContentShellTest").')
-  group.add_argument('--test-jar', required=True,
+  group.add_argument('--test-jar',
                      help='Path of jar containing test java files.')
   group.add_argument('--test-apk-incremental-install-script',
                      type=os.path.realpath,
diff --git a/build/android/test_runner.pydeps b/build/android/test_runner.pydeps
index 9ee98fa..03aa0174 100644
--- a/build/android/test_runner.pydeps
+++ b/build/android/test_runner.pydeps
@@ -130,6 +130,7 @@
 pylib/results/report_results.py
 pylib/utils/__init__.py
 pylib/utils/device_dependencies.py
+pylib/utils/dexdump.py
 pylib/utils/proguard.py
 pylib/utils/repo_utils.py
 pylib/valgrind_tools.py
diff --git a/build/config/nacl/rules.gni b/build/config/nacl/rules.gni
index 0d6d0364..c8956b4 100644
--- a/build/config/nacl/rules.gni
+++ b/build/config/nacl/rules.gni
@@ -82,7 +82,11 @@
       if (current_cpu != "x86" && current_cpu != "x64") {
         nmfflags +=
             [ "--library-path=" + rebase_path("${nacl_toolchain_tooldir}/lib") ]
-        data += [ "${lib_path}/lib/" ]
+        if (current_cpu == "arm") {
+          data += [ "${lib_path}/libarm/" ]
+        } else {
+          data += [ "${lib_path}/lib/" ]
+        }
       } else {
         # For x86-32, the lib/ directory is called lib32/ instead.
         if (current_cpu == "x86") {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 093fd5e..933492fc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -47,8 +47,9 @@
     public static final int ENTER_VR_NOT_NECESSARY = 0;
     public static final int ENTER_VR_CANCELLED = 1;
     public static final int ENTER_VR_REQUESTED = 2;
+    public static final int ENTER_VR_SUCCEEDED = 3;
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED})
+    @IntDef({ENTER_VR_NOT_NECESSARY, ENTER_VR_CANCELLED, ENTER_VR_REQUESTED, ENTER_VR_SUCCEEDED })
     public @interface EnterVRResult {}
 
     // TODO(bshe): These should be replaced by string provided by NDK. Currently, it only available
@@ -229,19 +230,15 @@
         if (MultiWindowUtils.getInstance().isInMultiWindowMode(mActivity)) {
             return false;
         }
-        // crbug.com/667908
-        if (!mVrDaydreamApi.isDaydreamCurrentViewer()) {
-            return false;
-        }
         return true;
     }
 
     @CalledByNative
-    private void presentRequested(boolean inWebVR) {
+    private void presentRequested() {
         // TODO(mthiesse): There's a GVR bug where they're not calling us back with the intent we
         // ask them to when we call DaydreamApi#launchInVr. As a temporary hack, remember locally
         // that we want to enter webVR.
-        mRequestedWebVR = inWebVR;
+        mRequestedWebVR = true;
         switch (enterVRIfNecessary()) {
             case ENTER_VR_NOT_NECESSARY:
                 mVrShell.setWebVrModeEnabled(true);
@@ -254,6 +251,12 @@
                 break;
             case ENTER_VR_REQUESTED:
                 break;
+            case ENTER_VR_SUCCEEDED:
+                nativeSetPresentResult(mNativeVrShellDelegate, true);
+                mRequestedWebVR = false;
+                break;
+            default:
+                Log.e(TAG, "Unexpected enum.");
         }
     }
 
@@ -266,7 +269,13 @@
         if (mInVr) return ENTER_VR_NOT_NECESSARY;
         if (!canEnterVR(mActivity.getActivityTab())) return ENTER_VR_CANCELLED;
 
-        if (!mVrDaydreamApi.launchInVr(getPendingEnterVRIntent())) return ENTER_VR_CANCELLED;
+        if (!mVrDaydreamApi.isDaydreamCurrentViewer()) {
+            // Avoid using launchInVr which would trigger DON flow regardless current viewer type
+            // due to the lack of support for unexported activities.
+            return enterVR() ? ENTER_VR_SUCCEEDED : ENTER_VR_CANCELLED;
+        } else {
+            if (!mVrDaydreamApi.launchInVr(getPendingEnterVRIntent())) return ENTER_VR_CANCELLED;
+        }
         return ENTER_VR_REQUESTED;
     }
 
diff --git a/chrome/app/chrome_crash_reporter_client_win.cc b/chrome/app/chrome_crash_reporter_client_win.cc
index b44fc84..f8616ea 100644
--- a/chrome/app/chrome_crash_reporter_client_win.cc
+++ b/chrome/app/chrome_crash_reporter_client_win.cc
@@ -110,6 +110,7 @@
       {"discardable-memory-allocated", kSmallSize},
       {"discardable-memory-free", kSmallSize},
       {kFontKeyName, kSmallSize},
+      { "mojo-message-error", kMediumSize },
       {"ppapi_path", kMediumSize},
       {"subresource_url", kLargeSize},
       {"total-discardable-memory-allocated", kSmallSize},
diff --git a/chrome/app/chrome_main.cc b/chrome/app/chrome_main.cc
index e24c46752..57dfdaf 100644
--- a/chrome/app/chrome_main.cc
+++ b/chrome/app/chrome_main.cc
@@ -46,14 +46,6 @@
 int ChromeMain(int argc, const char** argv) {
   int64_t exe_entry_point_ticks = 0;
 #endif
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
-  // VS2013 only checks the existence of FMA3 instructions, not the enabled-ness
-  // of them at the OS level (this is fixed in VS2015). We force off usage of
-  // FMA3 instructions in the CRT to avoid using that path and hitting illegal
-  // instructions when running on CPUs that support FMA3, but OSs that don't.
-  // See http://crbug.com/436603.
-  _set_FMA3_enable(0);
-#endif  // WIN && ARCH_CPU_X86_64
 
 #if defined(OS_WIN)
   install_static::InstallDetails::InitializeFromPrimaryModule(
diff --git a/chrome/app/media_router_strings.grdp b/chrome/app/media_router_strings.grdp
index db2315f11..80c62614 100644
--- a/chrome/app/media_router_strings.grdp
+++ b/chrome/app/media_router_strings.grdp
@@ -9,7 +9,7 @@
    Display on another screen
   </message>
   <message name="IDS_MEDIA_ROUTER_MENU_ITEM_TITLE" desc="Title of menu item for Media Router, which appears in the overflow menu and page contextual menus.">
-    Cast...
+    &amp;Cast...
   </message>
   <message name="IDS_MEDIA_ROUTER_LEARN_MORE" desc="Text of a menu item or link which, on click, opens a page with more information or relevant help center page.">
    Learn more
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index f7f2674..098a818 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -168,6 +168,33 @@
     </message>
   </if>
 
+  <if expr="chromeos">
+    <!-- Android Apps Page -->
+    <message name="IDS_SETTINGS_ANDROID_APPS_TITLE" desc="The title of Google Play Store (Arc++ / Android Apps) section.">
+      Google Play Store (beta)
+    </message>
+    <message name="IDS_SETTINGS_ANDROID_APPS_ENABLE" desc="Label for the checkbox that enables Google Play Store (Arc++) apps.">
+      Enable Google Play Store on your Chromebook.
+    </message>
+    <message name="IDS_SETTINGS_ANDROID_APPS_MANAGE_APPS" desc="Label for launching Android apps settings.">
+      Manage your Android preferences
+    </message>
+    <message name="IDS_SETTINGS_ANDROID_APPS_LEARN_MORE" desc="Link for more informaiton about installing Android apps on Chrome OS.">
+      Learn more.
+    </message>
+
+    <message name="IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_TITLE" desc="Title of the confirmation dialog for disabling android apps.">
+      Remove Android apps?
+    </message>
+    <message name="IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_MESSAGE" desc="Describes what will happen if the user opts out of android apps.">
+      Apps you’ve downloaded from Google Play will be deleted from this Chromebook.
+      <ph name="LINE_BREAKS1">&lt;br&gt;&lt;br&gt;</ph>
+      Content you’ve purchased such as movies, TV shows, music, books, or other in-app purchases may also be deleted.
+      <ph name="LINE_BREAKS2">&lt;br&gt;&lt;br&gt;</ph>
+      This doesn’t affect apps or content on other devices.
+    </message>
+  </if>
+
   <!-- Appearance Page -->
   <message name="IDS_SETTINGS_APPEARANCE" desc="Name of the settings page which displays appearance preferences.">
     Appearance
@@ -1026,9 +1053,6 @@
     <message name="IDS_SETTINGS_INTERNET_NETWORK_SHARED" desc="Settings > Internet > Network details: Text to show when a network is shared.">
       This network is shared with other users.
     </message>
-    <message name="IDS_SETTINGS_INTERNET_NETWORK_PROXY_CONTROLLED_EXTENSION" desc="Settings > Internet > Network details: Text to show when a network proxy is controlled by an extension.">
-      The network proxy is controlled by an extension.
-    </message>
     <message name="IDS_SETTINGS_INTERNET_NETWORK_PROXY_ENFORCED_POLICY" desc="Settings > Internet > Network details: Text to show when a network proxy is policy enforced.">
       This proxy is enforced by your administrator.
     </message>
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index 00671fb..01b70d1b 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -94,7 +94,7 @@
 
   // If/When VRShell is ready for use it will call SetPresentResult.
   JNIEnv* env = AttachCurrentThread();
-  Java_VrShellDelegate_presentRequested(env, j_vr_shell_delegate_.obj(), true);
+  Java_VrShellDelegate_presentRequested(env, j_vr_shell_delegate_.obj());
 }
 
 void VrShellDelegate::ExitWebVRPresent() {
diff --git a/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chrome/browser/extensions/api/settings_private/prefs_util.cc
index 508ddf8..fe8bc3f 100644
--- a/chrome/browser/extensions/api/settings_private/prefs_util.cc
+++ b/chrome/browser/extensions/api/settings_private/prefs_util.cc
@@ -239,6 +239,10 @@
   (*s_whitelist)[::prefs::kAccessibilityMonoAudioEnabled] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
 
+  // Android Apps.
+  (*s_whitelist)[::prefs::kArcEnabled] =
+      settings_private::PrefType::PREF_TYPE_BOOLEAN;
+
   // Misc.
   (*s_whitelist)[::prefs::kUse24HourClock] =
       settings_private::PrefType::PREF_TYPE_BOOLEAN;
diff --git a/chrome/browser/extensions/chrome_test_extension_loader.cc b/chrome/browser/extensions/chrome_test_extension_loader.cc
index 9a44002..f4c04bbc 100644
--- a/chrome/browser/extensions/chrome_test_extension_loader.cc
+++ b/chrome/browser/extensions/chrome_test_extension_loader.cc
@@ -57,8 +57,14 @@
     return nullptr;
 
   extension_id_ = extension->id();
-  extension = nullptr;
-  CheckPermissions(extension_id_);
+  // Trying to reload a shared module (as we do when adjusting extension
+  // permissions) causes ExtensionService to crash. Only adjust permissions for
+  // non-shared modules.
+  // TODO(devlin): That's not good; we shouldn't be crashing.
+  if (!SharedModuleInfo::IsSharedModule(extension.get())) {
+    extension = nullptr;
+    CheckPermissions(extension_id_);
+  }
 
   if (!install_param_.empty()) {
     ExtensionPrefs::Get(browser_context_)
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 5d3f902..5273d99 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -912,6 +912,7 @@
       new net::HttpNetworkSession(system_params));
   globals->system_http_transaction_factory.reset(
       new net::HttpNetworkLayer(globals->system_http_network_session.get()));
+  context->set_name("system");
   context->set_http_transaction_factory(
       globals->system_http_transaction_factory.get());
 
@@ -1059,6 +1060,7 @@
   globals->proxy_script_fetcher_http_transaction_factory.reset(
       new net::HttpNetworkLayer(
           globals->proxy_script_fetcher_http_network_session.get()));
+  context->set_name("proxy");
   context->set_http_transaction_factory(
       globals->proxy_script_fetcher_http_transaction_factory.get());
 
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h
index a550715..f72bb59 100644
--- a/chrome/browser/media/router/media_router.h
+++ b/chrome/browser/media/router/media_router.h
@@ -181,6 +181,10 @@
   // This will terminate all incognito media routes.
   virtual void OnIncognitoProfileShutdown() = 0;
 
+  // Returns the media routes that currently exist. To get notified whenever
+  // there is a change to the media routes, subclass MediaRoutesObserver.
+  virtual std::vector<MediaRoute> GetCurrentRoutes() const = 0;
+
  private:
   friend class IssuesObserver;
   friend class MediaSinksObserver;
diff --git a/chrome/browser/media/router/media_router_base.cc b/chrome/browser/media/router/media_router_base.cc
index aeffeeb..821b346 100644
--- a/chrome/browser/media/router/media_router_base.cc
+++ b/chrome/browser/media/router/media_router_base.cc
@@ -27,6 +27,7 @@
   void OnRoutesUpdated(
       const std::vector<MediaRoute>& routes,
       const std::vector<MediaRoute::Id>& joinable_route_ids) override {
+    current_routes = routes;
     incognito_route_ids.clear();
     // TODO(crbug.com/611486): Have the MRPM pass a list of joinable route ids
     // via |joinable_route_ids|, and check here if it is non-empty.
@@ -38,6 +39,7 @@
   }
 
   bool has_route;
+  std::vector<MediaRoute> current_routes;
   std::vector<MediaRoute::Id> incognito_route_ids;
 
  private:
@@ -72,6 +74,10 @@
     TerminateRoute(route_id);
 }
 
+std::vector<MediaRoute> MediaRouterBase::GetCurrentRoutes() const {
+  return internal_routes_observer_->current_routes;
+}
+
 MediaRouterBase::MediaRouterBase() : initialized_(false) {}
 
 // static
diff --git a/chrome/browser/media/router/media_router_base.h b/chrome/browser/media/router/media_router_base.h
index 45c0f261..c1b46e9 100644
--- a/chrome/browser/media/router/media_router_base.h
+++ b/chrome/browser/media/router/media_router_base.h
@@ -32,6 +32,8 @@
   // This will terminate all incognito media routes.
   void OnIncognitoProfileShutdown() override;
 
+  std::vector<MediaRoute> GetCurrentRoutes() const override;
+
  protected:
   FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
                            PresentationConnectionStateChangedCallback);
@@ -66,6 +68,7 @@
       presentation_connection_state_callbacks_;
 
  private:
+  friend class MediaRouterBaseTest;
   friend class MediaRouterFactory;
   friend class MediaRouterMojoTest;
 
diff --git a/chrome/browser/media/router/media_router_base_unittest.cc b/chrome/browser/media/router/media_router_base_unittest.cc
index 2003585..651569bd 100644
--- a/chrome/browser/media/router/media_router_base_unittest.cc
+++ b/chrome/browser/media/router/media_router_base_unittest.cc
@@ -11,6 +11,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using testing::_;
+using testing::SaveArg;
 
 namespace media_router {
 
@@ -33,9 +34,29 @@
   void OnIncognitoProfileShutdown() override {
     MediaRouterBase::OnIncognitoProfileShutdown();
   }
+
+  std::vector<MediaRoute> GetCurrentRoutes() const override {
+    return MediaRouterBase::GetCurrentRoutes();
+  }
 };
 
-TEST(MediaRouterBaseTest, CreatePresentationIds) {
+class MediaRouterBaseTest : public testing::Test {
+ public:
+  void SetUp() override {
+    EXPECT_CALL(router_, RegisterMediaRoutesObserver(_))
+        .WillOnce(SaveArg<0>(&routes_observer_));
+    router_.Initialize();
+  }
+
+  void TearDown() override { router_.Shutdown(); }
+
+ protected:
+  content::TestBrowserThreadBundle thread_bundle_;
+  MockMediaRouterBase router_;
+  MediaRoutesObserver* routes_observer_;
+};
+
+TEST_F(MediaRouterBaseTest, CreatePresentationIds) {
   std::string id1 = MediaRouterBase::CreatePresentationId();
   std::string id2 = MediaRouterBase::CreatePresentationId();
   EXPECT_NE(id1, "");
@@ -43,22 +64,18 @@
   EXPECT_NE(id1, id2);
 }
 
-TEST(MediaRouterBaseTest, NotifyCallbacks) {
-  content::TestBrowserThreadBundle thread_bundle_;
-  MockMediaRouterBase router;
-  router.Initialize();
-
+TEST_F(MediaRouterBaseTest, NotifyCallbacks) {
   MediaRoute::Id route_id1("id1");
   MediaRoute::Id route_id2("id2");
   MockPresentationConnectionStateChangedCallback callback1;
   MockPresentationConnectionStateChangedCallback callback2;
   std::unique_ptr<PresentationConnectionStateSubscription> subscription1 =
-      router.AddPresentationConnectionStateChangedCallback(
+      router_.AddPresentationConnectionStateChangedCallback(
           route_id1,
           base::Bind(&MockPresentationConnectionStateChangedCallback::Run,
                      base::Unretained(&callback1)));
   std::unique_ptr<PresentationConnectionStateSubscription> subscription2 =
-      router.AddPresentationConnectionStateChangedCallback(
+      router_.AddPresentationConnectionStateChangedCallback(
           route_id2,
           base::Bind(&MockPresentationConnectionStateChangedCallback::Run,
                      base::Unretained(&callback2)));
@@ -74,32 +91,50 @@
   change_info_closed.message = "Test message";
 
   EXPECT_CALL(callback1, Run(StateChangeInfoEquals(change_info_connected)));
-  router.NotifyPresentationConnectionStateChange(
+  router_.NotifyPresentationConnectionStateChange(
       route_id1, content::PRESENTATION_CONNECTION_STATE_CONNECTED);
 
   EXPECT_CALL(callback2, Run(StateChangeInfoEquals(change_info_connected)));
-  router.NotifyPresentationConnectionStateChange(
+  router_.NotifyPresentationConnectionStateChange(
       route_id2, content::PRESENTATION_CONNECTION_STATE_CONNECTED);
 
   EXPECT_CALL(callback1, Run(StateChangeInfoEquals(change_info_closed)));
-  router.NotifyPresentationConnectionClose(
+  router_.NotifyPresentationConnectionClose(
       route_id1, change_info_closed.close_reason, change_info_closed.message);
 
   // After removing a subscription, the corresponding callback should no longer
   // be called.
   subscription1.reset();
-  router.NotifyPresentationConnectionStateChange(
+  router_.NotifyPresentationConnectionStateChange(
       route_id1, content::PRESENTATION_CONNECTION_STATE_TERMINATED);
 
   EXPECT_CALL(callback2, Run(StateChangeInfoEquals(change_info_terminated)));
-  router.NotifyPresentationConnectionStateChange(
+  router_.NotifyPresentationConnectionStateChange(
       route_id2, content::PRESENTATION_CONNECTION_STATE_TERMINATED);
 
   subscription2.reset();
-  router.NotifyPresentationConnectionStateChange(
+  router_.NotifyPresentationConnectionStateChange(
       route_id2, content::PRESENTATION_CONNECTION_STATE_TERMINATED);
+}
 
-  router.Shutdown();
+TEST_F(MediaRouterBaseTest, GetCurrentRoutes) {
+  MediaSource source1("source_1");
+  MediaSource source2("source_1");
+  MediaRoute route1("route_1", source1, "sink_1", "", false, "", false);
+  MediaRoute route2("route_2", source2, "sink_2", "", true, "", false);
+  std::vector<MediaRoute> routes = {route1, route2};
+  std::vector<MediaRoute::Id> joinable_route_ids = {"route_1"};
+
+  EXPECT_TRUE(router_.GetCurrentRoutes().empty());
+  routes_observer_->OnRoutesUpdated(routes, joinable_route_ids);
+  std::vector<MediaRoute> current_routes = router_.GetCurrentRoutes();
+  ASSERT_EQ(current_routes.size(), 2u);
+  EXPECT_TRUE(current_routes[0].Equals(route1));
+  EXPECT_TRUE(current_routes[1].Equals(route2));
+
+  routes_observer_->OnRoutesUpdated(std::vector<MediaRoute>(),
+                                    std::vector<MediaRoute::Id>());
+  EXPECT_TRUE(router_.GetCurrentRoutes().empty());
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/mock_media_router.h b/chrome/browser/media/router/mock_media_router.h
index fcd406f..e949fac 100644
--- a/chrome/browser/media/router/mock_media_router.h
+++ b/chrome/browser/media/router/mock_media_router.h
@@ -85,6 +85,7 @@
     OnAddPresentationConnectionStateChangedCallbackInvoked(callback);
     return connection_state_callbacks_.Add(callback);
   }
+  MOCK_CONST_METHOD0(GetCurrentRoutes, std::vector<MediaRoute>());
 
   MOCK_METHOD0(OnIncognitoProfileShutdown, void());
   MOCK_METHOD1(OnAddPresentationConnectionStateChangedCallbackInvoked,
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index 28b4ede..d0d1a19 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -12,6 +12,7 @@
 #include "base/containers/small_map.h"
 #include "base/guid.h"
 #include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/media/router/create_presentation_connection_request.h"
 #include "chrome/browser/media/router/media_route.h"
@@ -51,13 +52,18 @@
 
 // Gets the last committed URL for the render frame specified by
 // |render_frame_host_id|.
-GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id) {
+GURL GetLastCommittedURLForFrame(RenderFrameHostId render_frame_host_id,
+                                 content::WebContents* web_contents) {
   RenderFrameHost* render_frame_host = RenderFrameHost::FromID(
       render_frame_host_id.first, render_frame_host_id.second);
+  // crbug.com/663740: The RFH may not be associated with the frame tree; in
+  // that case, GetLastCommittedOrigin() may crash.
+  if (!render_frame_host ||
+      !base::ContainsValue(web_contents->GetAllFrames(), render_frame_host))
+    return GURL();
+
   // TODO(crbug.com/632623): Use url::Origin in place of GURL for origins
-  return render_frame_host
-             ? render_frame_host->GetLastCommittedOrigin().GetURL()
-             : GURL();
+  return render_frame_host->GetLastCommittedOrigin().GetURL();
 }
 
 // Observes messages originating from the MediaSink connected to a MediaRoute
@@ -170,7 +176,7 @@
   RenderFrameHostId render_frame_host_id_;
 
   // References to the owning WebContents, and the corresponding MediaRouter.
-  const content::WebContents* web_contents_;
+  content::WebContents* web_contents_;
   MediaRouter* router_;
 
   DelegateObserver* delegate_observer_;
@@ -225,7 +231,8 @@
 
   sinks_observer.reset(new PresentationMediaSinksObserver(
       router_, listener, source,
-      GetLastCommittedURLForFrame(render_frame_host_id_).GetOrigin()));
+      GetLastCommittedURLForFrame(render_frame_host_id_, web_contents_)
+          .GetOrigin()));
 
   if (!sinks_observer->Init()) {
     url_to_sinks_observer_.erase(source.id());
@@ -549,7 +556,8 @@
     ClearDefaultPresentationRequest();
   } else {
     DCHECK(!callback.is_null());
-    GURL frame_url(GetLastCommittedURLForFrame(render_frame_host_id));
+    GURL frame_url(
+        GetLastCommittedURLForFrame(render_frame_host_id, web_contents_));
     PresentationRequest request(render_frame_host_id,
                                 std::vector<GURL>({default_presentation_url}),
                                 frame_url);
@@ -795,7 +803,7 @@
   std::unique_ptr<CreatePresentationConnectionRequest> request(
       new CreatePresentationConnectionRequest(
           render_frame_host_id, presentation_url,
-          GetLastCommittedURLForFrame(render_frame_host_id),
+          GetLastCommittedURLForFrame(render_frame_host_id, web_contents_),
           base::Bind(&PresentationServiceDelegateImpl::OnStartSessionSucceeded,
                      weak_factory_.GetWeakPtr(), render_process_id,
                      render_frame_id, success_cb),
@@ -834,7 +842,7 @@
   router_->JoinRoute(
       MediaSourceForPresentationUrl(presentation_url).id(), presentation_id,
       GetLastCommittedURLForFrame(
-          RenderFrameHostId(render_process_id, render_frame_id))
+          RenderFrameHostId(render_process_id, render_frame_id), web_contents_)
           .GetOrigin(),
       web_contents_, route_response_callbacks, base::TimeDelta(), incognito);
 }
diff --git a/chrome/browser/password_manager/OWNERS b/chrome/browser/password_manager/OWNERS
index 7dad41b1..d4667ce4 100644
--- a/chrome/browser/password_manager/OWNERS
+++ b/chrome/browser/password_manager/OWNERS
@@ -1,7 +1,6 @@
 dvadym@chromium.org
 engedy@chromium.org
 gcasto@chromium.org
-isherman@chromium.org
 melandory@chromium.org
 mkwst@chromium.org
 vabr@chromium.org
diff --git a/chrome/browser/permissions/permission_uma_util_unittest.cc b/chrome/browser/permissions/permission_uma_util_unittest.cc
index 79252c9..90aea64 100644
--- a/chrome/browser/permissions/permission_uma_util_unittest.cc
+++ b/chrome/browser/permissions/permission_uma_util_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "chrome/browser/permissions/permission_uma_util.h"
 
+#include <memory>
+
 #include "base/test/scoped_command_line.h"
 #include "chrome/browser/signin/fake_signin_manager_builder.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -18,7 +20,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/sync_prefs.h"
-#include "components/sync/driver/glue/sync_backend_host_mock.h"
+#include "components/sync/engine/fake_sync_engine.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index e76199d..f8838be9 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -358,7 +358,8 @@
 net::URLRequestContext*
 OffTheRecordProfileIOData::InitializeMediaRequestContext(
     net::URLRequestContext* original_context,
-    const StoragePartitionDescriptor& partition_descriptor) const {
+    const StoragePartitionDescriptor& partition_descriptor,
+    const std::string& name) const {
   NOTREACHED();
   return NULL;
 }
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.h b/chrome/browser/profiles/off_the_record_profile_io_data.h
index 7d540f2..eaef398c 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.h
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_PROFILES_OFF_THE_RECORD_PROFILE_IO_DATA_H_
 
 #include <memory>
+#include <string>
 
 #include "base/callback.h"
 #include "base/containers/hash_tables.h"
@@ -125,7 +126,8 @@
       const override;
   net::URLRequestContext* InitializeMediaRequestContext(
       net::URLRequestContext* original_context,
-      const StoragePartitionDescriptor& partition_descriptor) const override;
+      const StoragePartitionDescriptor& partition_descriptor,
+      const std::string& name) const override;
   net::URLRequestContext* AcquireMediaRequestContext() const override;
   net::URLRequestContext* AcquireIsolatedAppRequestContext(
       net::URLRequestContext* main_context,
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 88da0c7..87e8b89 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -574,9 +574,8 @@
   // Create a media request context based on the main context, but using a
   // media cache.  It shares the same job factory as the main context.
   StoragePartitionDescriptor details(profile_path_, false);
-  media_request_context_.reset(InitializeMediaRequestContext(main_context,
-                                                             details));
-
+  media_request_context_.reset(
+      InitializeMediaRequestContext(main_context, details, "main_media"));
   lazy_params_.reset();
 }
 
@@ -716,12 +715,12 @@
   return context;
 }
 
-net::URLRequestContext*
-ProfileImplIOData::InitializeMediaRequestContext(
+net::URLRequestContext* ProfileImplIOData::InitializeMediaRequestContext(
     net::URLRequestContext* original_context,
-    const StoragePartitionDescriptor& partition_descriptor) const {
+    const StoragePartitionDescriptor& partition_descriptor,
+    const std::string& name) const {
   // Copy most state from the original context.
-  MediaRequestContext* context = new MediaRequestContext();
+  MediaRequestContext* context = new MediaRequestContext(name);
   context->CopyFrom(original_context);
 
   // For in-memory context, return immediately after creating the new
@@ -791,8 +790,8 @@
     net::URLRequestContext* app_context,
     const StoragePartitionDescriptor& partition_descriptor) const {
   // We create per-app media contexts on demand, unlike the others above.
-  net::URLRequestContext* media_request_context =
-      InitializeMediaRequestContext(app_context, partition_descriptor);
+  net::URLRequestContext* media_request_context = InitializeMediaRequestContext(
+      app_context, partition_descriptor, "isolated_media");
   DCHECK(media_request_context);
   return media_request_context;
 }
diff --git a/chrome/browser/profiles/profile_impl_io_data.h b/chrome/browser/profiles/profile_impl_io_data.h
index 1b4563f..dedb29afb 100644
--- a/chrome/browser/profiles/profile_impl_io_data.h
+++ b/chrome/browser/profiles/profile_impl_io_data.h
@@ -179,7 +179,8 @@
       const override;
   net::URLRequestContext* InitializeMediaRequestContext(
       net::URLRequestContext* original_context,
-      const StoragePartitionDescriptor& partition_descriptor) const override;
+      const StoragePartitionDescriptor& partition_descriptor,
+      const std::string& name) const override;
   net::URLRequestContext* AcquireMediaRequestContext() const override;
   net::URLRequestContext* AcquireIsolatedAppRequestContext(
       net::URLRequestContext* main_context,
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 7f94c7ef..1520bd36 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -554,7 +554,9 @@
   BrowserContext::EnsureResourceContextInitialized(profile);
 }
 
-ProfileIOData::MediaRequestContext::MediaRequestContext() {
+ProfileIOData::MediaRequestContext::MediaRequestContext(
+    const std::string& name) {
+  set_name(name);
 }
 
 void ProfileIOData::MediaRequestContext::SetHttpTransactionFactory(
@@ -568,6 +570,7 @@
 }
 
 ProfileIOData::AppRequestContext::AppRequestContext() {
+  set_name("app_request");
 }
 
 void ProfileIOData::AppRequestContext::SetCookieStore(
@@ -1022,6 +1025,8 @@
   main_request_context_storage_.reset(
       new net::URLRequestContextStorage(main_request_context_.get()));
   extensions_request_context_.reset(new net::URLRequestContext());
+  main_request_context_->set_name("main");
+  extensions_request_context_->set_name("extensions");
 
   main_request_context_->set_enable_brotli(io_thread_globals->enable_brotli);
 
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index ab8d0270..888c97f 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -271,7 +271,10 @@
   // it is deleted.
   class MediaRequestContext : public net::URLRequestContext {
    public:
-    MediaRequestContext();
+    // |name| is used to describe this context. Currently there are two kinds of
+    // media request context -- main media request context ("main_meda") and
+    // isolated app media request context ("isolated_media").
+    explicit MediaRequestContext(const std::string& name);
 
     void SetHttpTransactionFactory(
         std::unique_ptr<net::HttpTransactionFactory> http_factory);
@@ -492,7 +495,8 @@
   // isolated app.
   virtual net::URLRequestContext* InitializeMediaRequestContext(
       net::URLRequestContext* original_context,
-      const StoragePartitionDescriptor& details) const = 0;
+      const StoragePartitionDescriptor& details,
+      const std::string& name) const = 0;
 
   // These functions are used to transfer ownership of the lazily initialized
   // context from ProfileIOData to the URLRequestContextGetter.
diff --git a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
index 06103e04..6f075aa92 100644
--- a/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
+++ b/chrome/browser/renderer_host/chrome_render_widget_host_view_mac_delegate.mm
@@ -160,7 +160,7 @@
     content::WebContents* webContents =
         content::WebContents::FromRenderViewHost(
             RenderViewHost::From(renderWidgetHost_));
-    webContents->Replace(base::SysNSStringToUTF16(newWord));
+    webContents->ReplaceMisspelling(base::SysNSStringToUTF16(newWord));
   }
 }
 
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.html b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.html
new file mode 100644
index 0000000..d95f5e7
--- /dev/null
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.html
@@ -0,0 +1,2 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<script src="/android_apps_page/android_apps_browser_proxy.js"></script>
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js
new file mode 100644
index 0000000..2fe9e78fc
--- /dev/null
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_browser_proxy.js
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A helper object used by the "Google Play Store" (Arc++) section
+ * to retrieve information about android apps.
+ */
+
+/**
+ * @typedef {{appReady: boolean}}
+ * @see chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
+ */
+var AndroidAppsInfo;
+
+cr.define('settings', function() {
+  /** @interface */
+  function AndroidAppsBrowserProxy() {
+  }
+
+  AndroidAppsBrowserProxy.prototype = {
+    requestAndroidAppsInfo: function() {},
+
+    /**
+     * @param {boolean} keyboardAction True if the app was opened using a
+     *     keyboard action.
+     */
+    showAndroidAppsSettings: function(keyboardAction) {},
+  };
+
+  /**
+   * @constructor
+   * @implements {settings.AndroidAppsBrowserProxy}
+   */
+  function AndroidAppsBrowserProxyImpl() {
+  }
+
+  // The singleton instance_ can be replaced with a test version of this wrapper
+  // during testing.
+  cr.addSingletonGetter(AndroidAppsBrowserProxyImpl);
+
+  AndroidAppsBrowserProxyImpl.prototype = {
+    /** @override */
+    requestAndroidAppsInfo: function() {
+      chrome.send('requestAndroidAppsInfo');
+    },
+
+    /** @override */
+    showAndroidAppsSettings: function(keyboardAction) {
+      chrome.send('showAndroidAppsSettings', [keyboardAction]);
+    },
+  };
+
+  return {
+    AndroidAppsBrowserProxy: AndroidAppsBrowserProxy,
+    AndroidAppsBrowserProxyImpl: AndroidAppsBrowserProxyImpl,
+  };
+});
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_page.html b/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
new file mode 100644
index 0000000..85e8c2b1
--- /dev/null
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_page.html
@@ -0,0 +1,62 @@
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="/android_apps_page/android_apps_browser_proxy.html">
+<link rel="import" href="/controls/settings_checkbox.html">
+<link rel="import" href="/i18n_setup.html">
+<link rel="import" href="/prefs/prefs_behavior.html">
+<link rel="import" href="/settings_shared_css.html">
+
+<dom-module id="settings-android-apps-page">
+  <template>
+    <style include="settings-shared">
+      a {
+        -webkit-margin-start: 4px;
+        height: var(--checkbox-size);
+      }
+
+      .indented {
+        -webkit-margin-start: 36px;
+      }
+    </style>
+
+    <div class="settings-box first">
+      <settings-checkbox id="enabledCheckbox" pref="{{prefs.arc.enabled}}"
+          label="$i18n{androidAppsEnabled}"
+          no-set-pref on-change="onArcEnabledChange_">
+      </settings-checkbox>
+      <a href="$i18nRaw{androidAppsLearnMoreUrl}" target="_blank">
+        $i18n{androidAppsLearnMore}
+      </a>
+    </div>
+
+    <div id="manageApps" class="settings-box continuation indented"
+        on-keydown="onManageAndroidAppsKeydown_"
+        on-tap="onManageAndroidAppsTap_" actionable
+        hidden="[[!androidAppsInfo_.appReady]]">
+      <div class="start">
+        <div>$i18n{androidAppsManageApps}</div>
+      </div>
+      <button class="icon-external" is="paper-icon-button-light">
+      </button>
+    </div>
+
+    <!-- Confirm disable android apps dialog -->
+    <dialog is="cr-dialog" id="confirmDisableDialog"
+        on-cancel="onConfirmDisableDialogCancel_">
+      <div class="title">$i18n{androidAppsDisableDialogTitle}</div>
+      <div class="body" inner-h-t-m-l="[[getDialogBody_()]]"></div>
+      <div class="button-container">
+        <paper-button class="cancel-button"
+            on-tap="onConfirmDisableDialogCancel_">
+          $i18n{cancel}
+        </paper-button>
+        <paper-button class="action-button"
+            on-tap="onConfirmDisableDialogConfirm_">
+          $i18n{confirm}
+        </paper-button>
+      </div>
+    </dialog>
+  </template>
+  <script src="android_apps_page.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/settings/android_apps_page/android_apps_page.js b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
new file mode 100644
index 0000000..44ece83
--- /dev/null
+++ b/chrome/browser/resources/settings/android_apps_page/android_apps_page.js
@@ -0,0 +1,105 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview
+ * 'android-apps-page' is the settings page for enabling android apps.
+ */
+
+Polymer({
+  is: 'settings-android-apps-page',
+
+  behaviors: [I18nBehavior, PrefsBehavior],
+
+  properties: {
+    /** Preferences state. */
+    prefs: Object,
+
+    /** @private {!AndroidAppsInfo|undefined} */
+    androidAppsInfo_: Object,
+  },
+
+  /** @private {?settings.AndroidAppsBrowserProxy} */
+  browserProxy_: null,
+
+  /** @override */
+  created: function() {
+    this.browserProxy_ = settings.AndroidAppsBrowserProxyImpl.getInstance();
+  },
+
+  /** @override */
+  ready: function() {
+    cr.addWebUIListener(
+        'android-apps-info-update', this.androidAppsInfoUpdate_.bind(this));
+    this.browserProxy_.requestAndroidAppsInfo();
+  },
+
+  /**
+   * @param {AndroidAppsInfo} info
+   * @private
+   */
+  androidAppsInfoUpdate_: function(info) {
+    this.androidAppsInfo_ = info;
+  },
+
+  /**
+   * @param {Event} event
+   * @private
+   */
+  onManageAndroidAppsKeydown_: function(event) {
+    if (event.key != 'Enter' && event.key != ' ')
+      return;
+    this.browserProxy_.showAndroidAppsSettings(true  /** keyboardAction */);
+    event.stopPropagation();
+  },
+
+  /** @private */
+  onManageAndroidAppsTap_: function(event) {
+    this.browserProxy_.showAndroidAppsSettings(false /** keyboardAction */);
+  },
+
+  /**
+   * @return {string}
+   * @private
+   */
+  getDialogBody_: function() {
+    return this.i18nAdvanced(
+        'androidAppsDisableDialogMessage', {substitutions: [], tags: ['br']});
+  },
+
+  /**
+   * Handles the change event for the arc.enabled checkbox. Shows a
+   * confirmation dialog when disabling the preference.
+   * @param {Event} event
+   * @private
+   */
+  onArcEnabledChange_: function(event) {
+    if (event.target.checked) {
+      /** @type {!SettingsCheckboxElement} */ (event.target).sendPrefChange();
+      return;
+    }
+    this.$.confirmDisableDialog.showModal();
+  },
+
+  /**
+   * Handles the shared proxy confirmation dialog 'Confirm' button.
+   * @private
+   */
+  onConfirmDisableDialogConfirm_: function() {
+    /** @type {!SettingsCheckboxElement} */ (this.$.enabledCheckbox)
+        .sendPrefChange();
+    this.$.confirmDisableDialog.close();
+  },
+
+  /**
+   * Handles the shared proxy confirmation dialog 'Cancel' button or a cancel
+   * event.
+   * @private
+   */
+  onConfirmDisableDialogCancel_: function() {
+    /** @type {!SettingsCheckboxElement} */ (this.$.enabledCheckbox)
+        .resetToPrefValue();
+    this.$.confirmDisableDialog.close();
+  },
+});
diff --git a/chrome/browser/resources/settings/android_apps_page/compiled_resources2.gyp b/chrome/browser/resources/settings/android_apps_page/compiled_resources2.gyp
new file mode 100644
index 0000000..655b3eb
--- /dev/null
+++ b/chrome/browser/resources/settings/android_apps_page/compiled_resources2.gyp
@@ -0,0 +1,26 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'android_apps_browser_proxy',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'android_apps_page',
+      'dependencies': [
+        '../controls/compiled_resources2.gyp:settings_checkbox',
+        '../prefs/compiled_resources2.gyp:prefs_behavior',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+        'android_apps_browser_proxy',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 61068faf..73b5e03 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -10,6 +10,7 @@
 <link rel="import" href="/settings_page_css.html">
 
 <if expr="chromeos">
+<link rel="import" href="/android_apps_page/android_apps_page.html">
 <link rel="import" href="/device_page/device_page.html">
 <link rel="import" href="/internet_page/internet_page.html">
 </if>
@@ -61,6 +62,17 @@
           <settings-search-page prefs="[[prefs]]"></settings-search-page>
         </settings-section>
       </template>
+<if expr="chromeos">
+      <template is="dom-if"
+          if="[[shouldShowAndroidApps_(showAndroidApps, pageVisibility)]]"
+          restamp>
+        <settings-section page-title="$i18n{androidAppsPageTitle}"
+            section="androidApps">
+          <settings-android-apps-page prefs="{{prefs}}">
+          </settings-android-apps-page>
+        </settings-section>
+      </template>
+</if>
 <if expr="not chromeos">
       <template is="dom-if" if="[[showPage(pageVisibility.defaultBrowser)]]"
           restamp>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js
index 7facd9f..873aa2d 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.js
+++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -18,6 +18,8 @@
       notify: true,
     },
 
+    showAndroidApps: Boolean,
+
     /**
      * True if the basic page should currently display the reset profile banner.
      * @private {boolean}
@@ -30,7 +32,18 @@
     },
   },
 
+  /** @private */
   onResetDone_: function() {
     this.showResetProfileBanner_ = false;
   },
+
+  /**
+   * @return {boolean}
+   * @private
+   */
+  shouldShowAndroidApps_: function() {
+    var visibility = /** @type {boolean|undefined} */ (
+        this.get('pageVisibility.androidApps'));
+    return this.showAndroidApps && this.showPage(visibility);
+  },
 });
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index e383ecd0..a5cce78 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -57,6 +57,7 @@
         'a11y_page/compiled_resources2.gyp:*',
         'about_page/compiled_resources2.gyp:*',
         'advanced_page/compiled_resources2.gyp:*',
+        'android_apps_page/compiled_resources2.gyp:*',
         'animation/compiled_resources2.gyp:*',
         'appearance_page/compiled_resources2.gyp:*',
         'basic_page/compiled_resources2.gyp:*',
diff --git a/chrome/browser/resources/settings/icons.html b/chrome/browser/resources/settings/icons.html
index cb3e8392..1724407 100644
--- a/chrome/browser/resources/settings/icons.html
+++ b/chrome/browser/resources/settings/icons.html
@@ -26,6 +26,7 @@
       <g id="access-time"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
 </if>
       <g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"></path></g>
+      <g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"></path></g>
       <g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"></path></g>
       <g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"></path></g>
       <g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"></path></g>
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index a5d8f57..abc617130 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -91,6 +91,13 @@
             connected$="[[isConnectedState_(networkProperties)]]">
           [[getStateText_(networkProperties)]]
         </div>
+        <template is="dom-if"
+            if="[[isPolicySource(networkProperties.Source))]]">
+          <cr-policy-network-indicator
+              indicator-type="[[getIndicatorTypeForSource(
+                  networkProperties.Source)]]">
+          </cr-policy-network-indicator>
+        </template>
       </div>
       <div id="buttonDiv" class="layout horizontal center">
         <paper-button class="secondary-button" on-tap="onForgetTap_"
@@ -144,7 +151,9 @@
       <!-- Autoconnect. -->
       <template is="dom-if" if="[[showAutoConnect_(networkProperties)]]">
         <div class="settings-box">
-          <paper-checkbox checked="{{autoConnect_}}">
+          <paper-checkbox checked="{{autoConnect_}}"
+              disabled="[[isNetworkPolicyEnforced(
+                  getManagedAutoConnect_(networkProperties))]]">
             $i18n{networkAutoConnect}
           </paper-checkbox>
           <cr-policy-network-indicator
diff --git a/chrome/browser/resources/settings/internet_page/internet_shared_css.html b/chrome/browser/resources/settings/internet_page/internet_shared_css.html
index 0b7852b..d86354f 100644
--- a/chrome/browser/resources/settings/internet_page/internet_shared_css.html
+++ b/chrome/browser/resources/settings/internet_page/internet_shared_css.html
@@ -13,6 +13,10 @@
         margin-bottom: 0;
         margin-top: -9px;
       }
+
+      .settings-box.indent {
+        @apply(--settings-list-frame-padding);
+      }
     </style>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/settings/internet_page/network_nameservers.html b/chrome/browser/resources/settings/internet_page/network_nameservers.html
index d58bb82..4b8e7167 100644
--- a/chrome/browser/resources/settings/internet_page/network_nameservers.html
+++ b/chrome/browser/resources/settings/internet_page/network_nameservers.html
@@ -21,7 +21,7 @@
       </div>
     </div>
 
-    <div class="settings-box continuation single-column"
+    <div class="settings-box continuation single-column indent"
         hidden$="[[!nameservers_.length]]">
       <template is="dom-repeat" items="[[nameservers_]]">
         <paper-input-container no-label-float>
diff --git a/chrome/browser/resources/settings/internet_page/network_property_list.html b/chrome/browser/resources/settings/internet_page/network_property_list.html
index eccd35d..80ccedd 100644
--- a/chrome/browser/resources/settings/internet_page/network_property_list.html
+++ b/chrome/browser/resources/settings/internet_page/network_property_list.html
@@ -23,6 +23,10 @@
       .settings-box:first-of-type {
         border-top: none;
       }
+
+      cr-policy-network-indicator {
+        padding: 0 var(--cr-icon-padding);
+      }
     </style>
     <template is="dom-repeat" items="[[fields]]"
         filter="[[computeFilter_(propertyDict, editFieldTypes)]]">
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.html b/chrome/browser/resources/settings/internet_page/network_proxy.html
index 56b59a1f..2314d795 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.html
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.html
@@ -2,7 +2,6 @@
 <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/md_select_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
@@ -10,6 +9,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html">
+<link rel="import" href="/controls/extension_controlled_indicator.html">
 <link rel="import" href="/controls/settings_checkbox.html">
 <link rel="import" href="/i18n_setup.html">
 <link rel="import" href="/prefs/prefs_behavior.html">
@@ -21,11 +21,15 @@
 <dom-module id="network-proxy">
   <template>
     <style include="internet-shared md-select">
-      cr-policy-network-indicator,
-      cr-policy-pref-indicator {
+      cr-policy-network-indicator {
         -webkit-margin-end: 10px;
       }
 
+      extension-controlled-indicator {
+        -webkit-margin-start: 0;
+        width: 100%;
+      }
+
       network-proxy-input {
         margin-bottom: 10px;
       }
@@ -35,10 +39,6 @@
         flex: none;
       }
 
-      .settings-box.indent {
-        @apply(--settings-list-frame-padding);
-      }
-
       #exceptionsDiv {
         padding: 10px 0;
       }
@@ -52,28 +52,33 @@
       }
     </style>
 
-    <!-- Policy indicator -->
-    <div class="settings-box first single-column"
-        hidden$="[[!isControlled(networkProperties.ProxySettings.Type)]]">
-      <div class="layout horizontal center"
-          hidden$="[[!getShowNetworkPolicyIndicator_(networkProperties)]]">
-        <cr-policy-network-indicator
-            property="[[networkProperties.ProxySettings.Type]]">
-        </cr-policy-network-indicator>
-        <div>$i18n{networkProxyEnforcedPolicy}</div>
+    <!-- Policy indicator. Only one dom-if below will be shown. -->
+    <template is="dom-if"
+        if="[[shouldShowNetworkPolicyIndicator_(networkProperties)]]">
+      <div class="settings-box continuation single-column">
+        <div class="layout horizontal center">
+          <cr-policy-network-indicator
+              property="[[networkProperties.ProxySettings.Type]]">
+          </cr-policy-network-indicator>
+          <div>$i18n{networkProxyEnforcedPolicy}</div>
+        </div>
       </div>
-      <div class="layout horizontal center"
-          hidden$="[[!getShowPrefPolicyIndicator_(networkProperties)]]">
-        <cr-policy-pref-indicator pref="[[prefs.proxy]]">
-        </cr-policy-pref-indicator>
-        <div>$i18n{networkProxyControlledExtension}</div>
+    </template>
+    <template is="dom-if"
+        if="[[shouldShowExtensionIndicator_(networkProperties)]]">
+      <div class="settings-box continuation single-column">
+        <extension-controlled-indicator
+            extension-id="[[prefs.proxy.extensionId]]"
+            extension-name="[[prefs.proxy.controlledByName]]"
+            extension-can-be-disabled="[[prefs.proxy.extensionCanBeDisabled]]">
+        </extension-controlled-indicator>
       </div>
-    </div>
+    </template>
 
     <!-- Allow shared proxies -->
     <div class="settings-box continuation"
-        hidden$="[[!getShowAllowShared_(
-                 networkProperties.ProxySettings.Type)]]">
+        hidden$="[[!shouldShowAllowShared_(
+            networkProperties.ProxySettings.Type)]]">
       <settings-checkbox id="allowShared"
           pref="{{prefs.settings.use_shared_proxies}}"
           no-set-pref label="$i18n{networkProxyAllowShared}"
@@ -88,7 +93,7 @@
         <select id="proxyType" class="md-select" on-change="onTypeChange_"
             value="[[proxy.Type]]"
             disabled="[[!isProxyEditable_(networkProperties, editable,
-                      useSharedProxies_)]]">
+                useSharedProxies_)]]">
           <template is="dom-repeat" items="[[proxyTypes_]]">
             <option value="[[item]]">[[getProxyTypeDesc_(item)]]</option>
           </template>
@@ -103,7 +108,7 @@
       <div>$i18n{networkProxyAutoConfig}</div>
       <paper-input no-label-float class="middle" value="{{proxy.PAC}}"
           disabled="[[!isEditable_(networkProperties.ProxySettings.PAC,
-                    useSharedProxies_)]]"
+              useSharedProxies_)]]"
           on-blur="onProxyInputChange_">
       </paper-input>
     </div>
@@ -127,8 +132,8 @@
         <network-proxy-input 
             on-proxy-change="onProxyInputChange_"
             editable="[[isEditable_(
-                      networkProperties.ProxySettings.Manual.HTTPProxy.Host,
-                      editable, useSharedProxies_)]]"
+                networkProperties.ProxySettings.Manual.HTTPProxy.Host,
+                editable, useSharedProxies_)]]"
             value="{{proxy.Manual.HTTPProxy}}"
             label="$i18n{networkProxy}">
         </network-proxy-input>
@@ -137,32 +142,32 @@
         <network-proxy-input
             on-proxy-change="onProxyInputChange_"
             editable="[[isEditable_(
-                      networkProperties.ProxySettings.Manual.HTTPProxy.Host,
-                      editable, useSharedProxies_)]]"
+                networkProperties.ProxySettings.Manual.HTTPProxy.Host,
+                editable, useSharedProxies_)]]"
             value="{{proxy.Manual.HTTPProxy}}"
             label="$i18n{networkProxyHttp}">
         </network-proxy-input>
         <network-proxy-input
             on-proxy-change="onProxyInputChange_"
             editable="[[isEditable_(
-                      networkProperties.ProxySettings.Manual.SecureHTTPProxy.Host,
-                      editable, useSharedProxies_)]]"
+                networkProperties.ProxySettings.Manual.SecureHTTPProxy.Host,
+                editable, useSharedProxies_)]]"
             value="{{proxy.Manual.SecureHTTPProxy}}"
             label="$i18n{networkProxyShttp}">
         </network-proxy-input>
         <network-proxy-input
             on-proxy-change="onProxyInputChange_"
             editable="[[isEditable_(
-                      networkProperties.ProxySettings.Manual.FTPProxy.Host,
-                      editable, useSharedProxies_)]]"
+                networkProperties.ProxySettings.Manual.FTPProxy.Host,
+                editable, useSharedProxies_)]]"
             value="{{proxy.Manual.FTPProxy}}"
             label="$i18n{networkProxyFtp}">
         </network-proxy-input>
         <network-proxy-input
             on-proxy-change="onProxyInputChange_"
             editable="[[isEditable_(
-                      networkProperties.ProxySettings.Manual.SOCKS.Host,
-                      editable, useSharedProxies_)]]"
+                networkProperties.ProxySettings.Manual.SOCKS.Host,
+                editable, useSharedProxies_)]]"
             value="{{proxy.Manual.SOCKS}}"
             label="$i18n{networkProxySocks}">
         </network-proxy-input>
@@ -170,7 +175,7 @@
 
       <div id="exceptionsDiv"
           hidden="[[!isProxyEditable_(networkProperties, editable,
-                  useSharedProxies_)]]">
+              useSharedProxies_)]]">
         <div>$i18n{networkProxyExceptionList}</div>
         <network-proxy-exclusions on-proxy-change="onProxyExclusionsChange_"
             exclusions="{{proxy.ExcludeDomains}}">
diff --git a/chrome/browser/resources/settings/internet_page/network_proxy.js b/chrome/browser/resources/settings/internet_page/network_proxy.js
index 974de27c..e3defda 100644
--- a/chrome/browser/resources/settings/internet_page/network_proxy.js
+++ b/chrome/browser/resources/settings/internet_page/network_proxy.js
@@ -336,7 +336,7 @@
    * @return {boolean}
    * @private
    */
-  getShowNetworkPolicyIndicator_: function() {
+  shouldShowNetworkPolicyIndicator_: function() {
     let property = this.getProxySettingsTypeProperty_();
     return !!property && !this.isExtensionControlled(property) &&
         this.isNetworkPolicyEnforced(property);
@@ -346,7 +346,7 @@
    * @return {boolean}
    * @private
    */
-  getShowPrefPolicyIndicator_: function() {
+  shouldShowExtensionIndicator_: function() {
     let property = this.getProxySettingsTypeProperty_();
     return !!property && this.isExtensionControlled(property);
   },
@@ -356,7 +356,7 @@
    * @return {boolean}
    * @private
    */
-  getShowAllowShared_: function(property) {
+  shouldShowAllowShared_: function(property) {
     return !this.isControlled(property) && this.isShared_();
   },
 
@@ -389,7 +389,7 @@
    */
   isProxyEditable_: function() {
     let property = this.getProxySettingsTypeProperty_();
-    return !!property && this.isEditable_(property);
+    return !property || this.isEditable_(property);
   },
 
   /**
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index 11201905..fa4de37 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -57,7 +57,7 @@
       <div id="details" selectable
           no-flex$="[[showSimInfo_(deviceState)]]"
           on-tap="onDetailsTap_" tabindex$="[[getTabIndex_(deviceState)]]">
-        <cr-network-list-item item="[[activeNetworkState]]">
+        <cr-network-list-item item="[[activeNetworkState]]" class="flex">
         </cr-network-list-item>
         <paper-spinner active="[[scanningIsActive_(deviceState, expanded_)]]"
             hidden$="[[!scanningIsVisible_(deviceState)]]">
diff --git a/chrome/browser/resources/settings/route.js b/chrome/browser/resources/settings/route.js
index 5f6750f..2e888f6 100644
--- a/chrome/browser/resources/settings/route.js
+++ b/chrome/browser/resources/settings/route.js
@@ -115,6 +115,10 @@
   r.SEARCH = r.BASIC.createSection('/search', 'search');
   r.SEARCH_ENGINES = r.SEARCH.createChild('/searchEngines');
 
+<if expr="chromeos">
+  r.ANDROID_APPS = r.BASIC.createSection('/androidApps', 'androidApps');
+</if>
+
   r.ON_STARTUP = r.BASIC.createSection('/onStartup', 'onStartup');
 
   r.PEOPLE = r.BASIC.createSection('/people', 'people');
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html
index 97c3c7a7..6e4fad5 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.html
+++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -68,6 +68,7 @@
         showPages_.basic, inSearchMode_, hasExpandedSection_)]]">
       <settings-basic-page prefs="{{prefs}}"
           page-visibility="[[pageVisibility]]"
+          show-android-apps="[[showAndroidApps]]"
           on-subpage-expand="onSubpageExpand_">
       </settings-basic-page>
     </template>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js
index 5d9dd81c..b5f524a 100644
--- a/chrome/browser/resources/settings/settings_main/settings_main.js
+++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -86,6 +86,8 @@
       type: Object,
       value: function() { return {}; },
     },
+
+    showAndroidApps: Boolean,
   },
 
   /** @override */
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index a07a457..c53e02b 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -126,6 +126,13 @@
             <iron-icon icon="cr:search"></iron-icon>
             $i18n{searchPageTitle}
           </div>
+<if expr="chromeos">
+           <div data-path="/androidApps" on-tap="openPage_"
+               hidden="[[!showAndroidApps]]">
+             <iron-icon icon="settings:android"></iron-icon>
+             $i18n{androidAppsPageTitle}
+           </div>
+</if>
 <if expr="not chromeos">
           <div data-path="/defaultBrowser" on-tap="openPage_"
               hidden="[[!pageVisibility.defaultBrowser]]">
diff --git a/chrome/browser/resources/settings/settings_page/settings_page_visibility.js b/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
index 3dcfce2d..848d96f9 100644
--- a/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
+++ b/chrome/browser/resources/settings/settings_page/settings_page_visibility.js
@@ -36,7 +36,7 @@
   },
 
   /**
-   * @param {boolean} visibility
+   * @param {boolean|undefined} visibility
    * @return {boolean}
    */
   showPage: function(visibility) {
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 4f04c09..551f7c52 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -974,6 +974,22 @@
                  file="site_settings/zoom_levels.js"
                  type="chrome_html" />
       <if expr="chromeos">
+        <structure name="IDR_SETTINGS_ANDROID_APPS_PAGE_HTML"
+                   file="android_apps_page/android_apps_page.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_ANDROID_APPS_PAGE_JS"
+                   file="android_apps_page/android_apps_page.js"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_ANDROID_APPS_BROWSER_PROXY_JS"
+                   file="android_apps_page/android_apps_browser_proxy.js"
+                   type="chrome_html"
+                   flattenhtml="true"
+                   allowexternalscript="true" />
+        <structure name="IDR_SETTINGS_ANDROID_APPS_BROWSER_PROXY_HTML"
+                   file="android_apps_page/android_apps_browser_proxy.html"
+                   type="chrome_html"
+                   flattenhtml="true"
+                   allowexternalscript="true" />
         <structure name="IDR_SETTINGS_BLUETOOTH_DEVICE_DIALOG_HTML"
                    file="bluetooth_page/bluetooth_device_dialog.html"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 0f852d06..50002a1 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -377,8 +377,7 @@
       }
 
       .settings-box paper-item iron-icon {
-        /* Same padding as paper-icon-button. */
-        padding: 8px;
+        padding: var(--cr-icon-padding);
       }
 
       /* Helper for a list frame to automatically avoid the separator line. */
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 7f24d2f4..2afab9c 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -100,6 +100,7 @@
       <div class="drawer-content">
         <template is="dom-if" id="drawerTemplate">
           <settings-menu page-visibility="[[pageVisibility_]]"
+              show-android-apps="[[showAndroidApps_]]"
               on-iron-activate="onIronActivate_"
               advanced-opened="{{advancedOpened_}}">
           </settings-menu>
@@ -110,6 +111,7 @@
       <settings-main id="main" prefs="{{prefs}}"
           toolbar-spinner-active="{{toolbarSpinnerActive_}}"
           page-visibility="[[pageVisibility_]]"
+          show-android-apps="[[showAndroidApps_]]"
           advanced-toggle-expanded="{{advancedOpened_}}">
       </settings-main>
     </paper-header-panel>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index c035dfb..be772c1 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -54,6 +54,9 @@
     pageVisibility_: Object,
 
     /** @private */
+    showAndroidApps_: Boolean,
+
+    /** @private */
     lastSearchQuery_: {
       type: String,
       value: '',
@@ -115,6 +118,9 @@
 </if>
       };
     }
+
+    this.showAndroidApps_ = loadTimeData.valueExists('androidAppsAllowed') &&
+        loadTimeData.getBoolean('androidAppsAllowed');
   },
 
   /** @override */
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index b755372d..88badbfd 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -217,6 +217,7 @@
       safe_browsing_request_context_->set_http_transaction_factory(
           http_transaction_factory_.get());
     }
+    safe_browsing_request_context_->set_name("safe_browsing");
   }
 
   return safe_browsing_request_context_.get();
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index aa2800b..63d7d7c4 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -308,7 +308,7 @@
 void ChromeSigninClient::PreSignOut(const base::Callback<void()>& sign_out) {
 #if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
   if (is_force_signin_enabled_ && !profile_->IsSystemProfile() &&
-      !profile_->IsGuestSession()) {
+      !profile_->IsGuestSession() && !profile_->IsSupervised()) {
     BrowserList::CloseAllBrowsersWithProfile(
         profile_, base::Bind(&ChromeSigninClient::OnCloseBrowsersSuccess,
                              base::Unretained(this), sign_out),
diff --git a/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc b/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc
index 5b69a37..acdb5a5 100644
--- a/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc
+++ b/chrome/browser/ssl/chrome_expect_ct_reporter_unittest.cc
@@ -301,19 +301,21 @@
 class ChromeExpectCTReporterWaitTest : public ::testing::Test {
  public:
   ChromeExpectCTReporterWaitTest()
-      : context_(true),
-        thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
-    context_.set_network_delegate(&network_delegate_);
-    context_.Init();
-  }
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
-  void SetUp() override { net::URLRequestFailedJob::AddUrlHandler(); }
+  void SetUp() override {
+    // Initializes URLRequestContext after the thread is set up.
+    context_.reset(new net::TestURLRequestContext(true));
+    context_->set_network_delegate(&network_delegate_);
+    context_->Init();
+    net::URLRequestFailedJob::AddUrlHandler();
+  }
 
   void TearDown() override {
     net::URLRequestFilter::GetInstance()->ClearHandlers();
   }
 
-  net::TestURLRequestContext* context() { return &context_; }
+  net::TestURLRequestContext* context() { return context_.get(); }
 
  protected:
   void SendReport(ChromeExpectCTReporter* reporter,
@@ -329,7 +331,7 @@
 
  private:
   TestExpectCTNetworkDelegate network_delegate_;
-  net::TestURLRequestContext context_;
+  std::unique_ptr<net::TestURLRequestContext> context_;
   content::TestBrowserThreadBundle thread_bundle_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeExpectCTReporterWaitTest);
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
index 8938e4e3..daafc9a 100644
--- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -192,7 +192,7 @@
   ASSERT_FALSE(notification_ui_manager_->FindById(
       kNotificationId, NotificationUIManager::GetProfileID(profile_)));
 
-  syncer::SyncBackendHost::Status status;
+  syncer::SyncEngine::Status status;
   EXPECT_CALL(*service_, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
 
diff --git a/chrome/browser/sync/sync_global_error_unittest.cc b/chrome/browser/sync/sync_global_error_unittest.cc
index eac710a..ebe10da 100644
--- a/chrome/browser/sync/sync_global_error_unittest.cc
+++ b/chrome/browser/sync/sync_global_error_unittest.cc
@@ -143,7 +143,7 @@
       GlobalErrorServiceFactory::GetForProfile(profile()), login_ui_service,
       &error, &service);
 
-  syncer::SyncBackendHost::Status status;
+  syncer::SyncEngine::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
 
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc
index 4f7fea3..7ff529a1d2 100644
--- a/chrome/browser/sync/sync_ui_util_unittest.cc
+++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -95,7 +95,7 @@
   std::unique_ptr<Profile> profile = MakeSignedInTestingProfile();
   ProfileSyncServiceMock service(
       CreateProfileSyncServiceParamsForTest(profile.get()));
-  syncer::SyncBackendHost::Status status;
+  syncer::SyncEngine::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
   EXPECT_CALL(service, IsPassphraseRequired())
@@ -115,7 +115,7 @@
   std::unique_ptr<Profile> profile(MakeSignedInTestingProfile());
   ProfileSyncServiceMock service(
       CreateProfileSyncServiceParamsForTest(profile.get()));
-  syncer::SyncBackendHost::Status status;
+  syncer::SyncEngine::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
 
@@ -145,7 +145,7 @@
       CreateProfileSyncServiceParamsForTest(profile.get());
   NiceMock<ProfileSyncServiceMock> service(&init_params);
 
-  syncer::SyncBackendHost::Status status;
+  syncer::SyncEngine::Status status;
   EXPECT_CALL(service, QueryDetailedSyncStatus(_))
               .WillRepeatedly(Return(false));
 
@@ -220,7 +220,7 @@
           .WillRepeatedly(Return(false));
       EXPECT_CALL(*service, IsFirstSetupInProgress())
           .WillRepeatedly(Return(true));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       return;
@@ -232,7 +232,7 @@
           .WillRepeatedly(Return(false));
       EXPECT_CALL(*service, HasUnrecoverableError())
           .WillRepeatedly(Return(true));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       return;
@@ -243,7 +243,7 @@
       EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
       EXPECT_CALL(*service, IsPassphraseRequired())
           .WillRepeatedly(Return(false));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       EXPECT_CALL(*service, HasUnrecoverableError())
@@ -257,7 +257,7 @@
       EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
       EXPECT_CALL(*service, IsPassphraseRequired())
           .WillRepeatedly(Return(false));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       provider->SetAuthError(
@@ -275,7 +275,7 @@
           .WillRepeatedly(Return(false));
       syncer::SyncProtocolError protocolError;
       protocolError.action = syncer::UPGRADE_CLIENT;
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       status.sync_protocol_error = protocolError;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
@@ -287,7 +287,7 @@
       EXPECT_CALL(*service, IsFirstSetupComplete())
           .WillRepeatedly(Return(true));
       EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       EXPECT_CALL(*service, HasUnrecoverableError())
@@ -304,7 +304,7 @@
       EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true));
       EXPECT_CALL(*service, IsPassphraseRequired())
           .WillRepeatedly(Return(false));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       EXPECT_CALL(*service, HasUnrecoverableError())
@@ -320,7 +320,7 @@
       EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(false));
       EXPECT_CALL(*service, IsPassphraseRequired())
           .WillRepeatedly(Return(false));
-      syncer::SyncBackendHost::Status status;
+      syncer::SyncEngine::Status status;
       EXPECT_CALL(*service, QueryDetailedSyncStatus(_))
           .WillRepeatedly(DoAll(SetArgPointee<0>(status), Return(false)));
       EXPECT_CALL(*service, HasUnrecoverableError())
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 7fa6560..49f5809 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1077,6 +1077,8 @@
       "webui/settings/browser_lifetime_handler.h",
       "webui/settings/chromeos/accessibility_handler.cc",
       "webui/settings/chromeos/accessibility_handler.h",
+      "webui/settings/chromeos/android_apps_handler.cc",
+      "webui/settings/chromeos/android_apps_handler.h",
       "webui/settings/chromeos/change_picture_handler.cc",
       "webui/settings/chromeos/change_picture_handler.h",
       "webui/settings/chromeos/cups_printers_handler.cc",
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index bc3bbab..ac235af9 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -4,42 +4,22 @@
 
 #include "chrome/browser/ui/webui/extensions/extension_settings_browsertest.h"
 
-#include <stddef.h>
-#include <utility>
-
-#include "base/files/file_path.h"
 #include "base/path_service.h"
-#include "base/strings/string_number_conversions.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/extensions/crx_installer.h"
-#include "chrome/browser/extensions/extension_error_reporter.h"
-#include "chrome/browser/extensions/extension_install_prompt.h"
-#include "chrome/browser/extensions/extension_install_prompt_show_params.h"
-#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/web_contents_sizer.h"
 #include "chrome/common/chrome_paths.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/test/browser_test_utils.h"
-#include "content/public/test/test_utils.h"
-#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/extension_dialog_auto_confirm.h"
 #include "extensions/browser/extension_system.h"
-#include "extensions/browser/test_extension_registry_observer.h"
-#include "extensions/common/extension_set.h"
 
 using extensions::Extension;
 using extensions::TestManagementPolicyProvider;
 
 ExtensionSettingsUIBrowserTest::ExtensionSettingsUIBrowserTest()
-    : profile_(nullptr),
-      policy_provider_(TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS |
+    : policy_provider_(TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS |
                        TestManagementPolicyProvider::MUST_REMAIN_ENABLED |
                        TestManagementPolicyProvider::MUST_REMAIN_INSTALLED) {
   CHECK(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_));
@@ -48,57 +28,40 @@
 
 ExtensionSettingsUIBrowserTest::~ExtensionSettingsUIBrowserTest() {}
 
-Profile* ExtensionSettingsUIBrowserTest::GetProfile() {
-  if (!profile_) {
-    profile_ = browser() ? browser()->profile() :
-                           ProfileManager::GetActiveUserProfile();
-  }
-  return profile_;
-}
-
-void ExtensionSettingsUIBrowserTest::SetUpOnMainThread() {
-  WebUIBrowserTest::SetUpOnMainThread();
-  observer_.reset(
-      new extensions::ChromeExtensionTestNotificationObserver(browser()));
-}
-
 void ExtensionSettingsUIBrowserTest::InstallGoodExtension() {
   EXPECT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx")));
 }
 
 void ExtensionSettingsUIBrowserTest::InstallErrorsExtension() {
-  EXPECT_TRUE(InstallUnpackedExtension(
-      test_data_dir_.AppendASCII("error_console")
-                    .AppendASCII("runtime_and_manifest_errors")));
+  EXPECT_TRUE(
+      InstallExtension(test_data_dir_.AppendASCII("error_console")
+                           .AppendASCII("runtime_and_manifest_errors")));
 }
 
 void ExtensionSettingsUIBrowserTest::InstallSharedModule() {
   base::FilePath shared_module_path =
       test_data_dir_.AppendASCII("api_test").AppendASCII("shared_module");
-  EXPECT_TRUE(InstallUnpackedExtension(
-      shared_module_path.AppendASCII("shared")));
-  EXPECT_TRUE(InstallUnpackedExtension(
-      shared_module_path.AppendASCII("import_pass")));
+  EXPECT_TRUE(InstallExtension(shared_module_path.AppendASCII("shared")));
+  EXPECT_TRUE(InstallExtension(shared_module_path.AppendASCII("import_pass")));
 }
 
 void ExtensionSettingsUIBrowserTest::InstallPackagedApp() {
-  EXPECT_TRUE(InstallUnpackedExtension(
-      test_data_dir_.AppendASCII("packaged_app")));
+  EXPECT_TRUE(InstallExtension(test_data_dir_.AppendASCII("packaged_app")));
 }
 
 void ExtensionSettingsUIBrowserTest::InstallHostedApp() {
-  EXPECT_TRUE(InstallUnpackedExtension(
-      test_data_dir_.AppendASCII("hosted_app")));
+  EXPECT_TRUE(InstallExtension(test_data_dir_.AppendASCII("hosted_app")));
 }
 
 void ExtensionSettingsUIBrowserTest::InstallPlatformApp() {
-  EXPECT_TRUE(InstallUnpackedExtension(
+  EXPECT_TRUE(InstallExtension(
       test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal")));
 }
 
 void ExtensionSettingsUIBrowserTest::AddManagedPolicyProvider() {
-  auto* extension_service = extensions::ExtensionSystem::Get(GetProfile());
-  extension_service->management_policy()->RegisterProvider(&policy_provider_);
+  extensions::ExtensionSystem* extension_system =
+      extensions::ExtensionSystem::Get(browser()->profile());
+  extension_system->management_policy()->RegisterProvider(&policy_provider_);
 }
 
 void ExtensionSettingsUIBrowserTest::SetAutoConfirmUninstall() {
@@ -118,88 +81,9 @@
   ResizeWebContents(web_contents, gfx::Rect(0, 0, 400, 400));
 }
 
-const Extension* ExtensionSettingsUIBrowserTest::InstallUnpackedExtension(
-    const base::FilePath& path) {
-  if (path.empty())
-    return nullptr;
-
-  Profile* profile = GetProfile();
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  service->set_show_extensions_prompts(false);
-  extensions::ExtensionRegistry* registry =
-      extensions::ExtensionRegistry::Get(profile);
-  extensions::TestExtensionRegistryObserver observer(registry);
-  extensions::UnpackedInstaller::Create(service)->Load(path);
-  base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
-  const Extension* extension = nullptr;
-  do {
-    extension = observer.WaitForExtensionLoaded();
-  } while (extension->path() != extension_path);
-
-  return extension;
-}
-
 const Extension* ExtensionSettingsUIBrowserTest::InstallExtension(
     const base::FilePath& path) {
-  Profile* profile = GetProfile();
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile)->extension_service();
-  extensions::ExtensionRegistry* registry =
-      extensions::ExtensionRegistry::Get(profile);
-  service->set_show_extensions_prompts(false);
-  size_t num_before = registry->enabled_extensions().size();
-  {
-    extensions::ScopedTestDialogAutoConfirm auto_confirm(
-        extensions::ScopedTestDialogAutoConfirm::ACCEPT);
-    std::unique_ptr<ExtensionInstallPrompt> install_ui(
-        new ExtensionInstallPrompt(
-            browser()->tab_strip_model()->GetActiveWebContents()));
-
-    base::FilePath crx_path = path;
-    DCHECK(crx_path.Extension() == FILE_PATH_LITERAL(".crx"));
-    if (crx_path.empty())
-      return nullptr;
-
-    scoped_refptr<extensions::CrxInstaller> installer(
-        extensions::CrxInstaller::Create(service, std::move(install_ui)));
-    installer->set_expected_id(std::string());
-    installer->set_is_gallery_install(false);
-    installer->set_install_source(extensions::Manifest::INTERNAL);
-    installer->set_install_immediately(true);
-    installer->set_off_store_install_allow_reason(
-        extensions::CrxInstaller::OffStoreInstallAllowedInTest);
-
-    observer_->Watch(
-        extensions::NOTIFICATION_CRX_INSTALLER_DONE,
-        content::Source<extensions::CrxInstaller>(installer.get()));
-
-    installer->InstallCrx(crx_path);
-
-    observer_->Wait();
-  }
-
-  size_t num_after = registry->enabled_extensions().size();
-  if (num_before + 1 != num_after) {
-    VLOG(1) << "Num extensions before: " << base::SizeTToString(num_before)
-            << " num after: " << base::SizeTToString(num_after)
-            << " Installed extensions follow:";
-
-    for (const scoped_refptr<const Extension>& extension :
-         registry->enabled_extensions())
-      VLOG(1) << "  " << extension->id();
-
-    VLOG(1) << "Errors follow:";
-    const std::vector<base::string16>* errors =
-        ExtensionErrorReporter::GetInstance()->GetErrors();
-    for (std::vector<base::string16>::const_iterator iter = errors->begin();
-         iter != errors->end(); ++iter)
-      VLOG(1) << *iter;
-
-    return nullptr;
-  }
-
-  if (!observer_->WaitForExtensionViewsToLoad())
-    return nullptr;
-  return service->GetExtensionById(last_loaded_extension_id(), false);
+  extensions::ChromeTestExtensionLoader loader(browser()->profile());
+  loader.set_ignore_manifest_warnings(true);
+  return loader.LoadExtension(path).get();
 }
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
index 87718bd..1abb1df 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
@@ -5,16 +5,18 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_SETTINGS_BROWSERTEST_H_
 #define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_EXTENSION_SETTINGS_BROWSERTEST_H_
 
-#include "base/macros.h"
-#include "chrome/browser/extensions/chrome_extension_test_notification_observer.h"
-#include "chrome/test/base/web_ui_browser_test.h"
-#include "extensions/browser/extension_dialog_auto_confirm.h"
-#include "extensions/browser/test_management_policy.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/feature_switch.h"
-#include "extensions/common/features/feature_channel.h"
+#include <memory>
 
-class Profile;
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "chrome/test/base/web_ui_browser_test.h"
+#include "extensions/browser/test_management_policy.h"
+#include "extensions/common/feature_switch.h"
+
+namespace extensions {
+class Extension;
+class ScopedTestDialogAutoConfirm;
+}
 
 // C++ test fixture used by extension_settings_browsertest.js.
 class ExtensionSettingsUIBrowserTest : public WebUIBrowserTest {
@@ -23,15 +25,6 @@
   ~ExtensionSettingsUIBrowserTest() override;
 
  protected:
-  // Get the profile to use.
-  Profile* GetProfile();
-
-  const std::string& last_loaded_extension_id() {
-    return observer_->last_loaded_extension_id();
-  }
-
-  void SetUpOnMainThread() override;
-
   void InstallGoodExtension();
 
   void InstallErrorsExtension();
@@ -55,17 +48,8 @@
   void ShrinkWebContentsView();
 
  private:
-  bool WaitForExtensionViewsToLoad();
-  const extensions::Extension* InstallUnpackedExtension(
-      const base::FilePath& path);
   const extensions::Extension* InstallExtension(const base::FilePath& path);
 
-  std::unique_ptr<extensions::ChromeExtensionTestNotificationObserver>
-      observer_;
-
-  // The default profile to be used.
-  Profile* profile_;
-
   // Used to simulate managed extensions (by being registered as a provider).
   extensions::TestManagementPolicyProvider policy_provider_;
 
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index 5689862..737608e6 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -139,29 +139,7 @@
 void MediaRouterUI::UIMediaRoutesObserver::OnRoutesUpdated(
     const std::vector<MediaRoute>& routes,
     const std::vector<MediaRoute::Id>& joinable_route_ids) {
-  std::vector<MediaRoute> routes_for_display;
-  std::vector<MediaRoute::Id> joinable_route_ids_for_display;
-  for (const MediaRoute& route : routes) {
-    if (route.for_display()) {
-#ifndef NDEBUG
-      for (const MediaRoute& existing_route : routes_for_display) {
-        if (existing_route.media_sink_id() == route.media_sink_id()) {
-          DVLOG(2) << "Received another route for display with the same sink"
-                   << " id as an existing route. " << route.media_route_id()
-                   << " has the same sink id as "
-                   << existing_route.media_sink_id() << ".";
-        }
-      }
-#endif
-      if (base::ContainsValue(joinable_route_ids, route.media_route_id())) {
-        joinable_route_ids_for_display.push_back(route.media_route_id());
-      }
-
-      routes_for_display.push_back(route);
-    }
-  }
-
-  callback_.Run(routes_for_display, joinable_route_ids_for_display);
+  callback_.Run(routes, joinable_route_ids);
 }
 
 MediaRouterUI::MediaRouterUI(content::WebUI* web_ui)
@@ -301,7 +279,12 @@
     query_result_manager_->SetSourcesForCastMode(MediaCastMode::TAB_MIRROR,
                                                  {mirroring_source}, origin);
   }
+
   UpdateCastModes();
+
+  // Get the current list of media routes, so that the WebUI will have routes
+  // information at initialization.
+  OnRoutesUpdated(router_->GetCurrentRoutes(), std::vector<MediaRoute::Id>());
 }
 
 void MediaRouterUI::InitForTest(
@@ -354,6 +337,25 @@
   }
 }
 
+void MediaRouterUI::UpdateRoutesToCastModesMapping() {
+  std::unordered_map<MediaSource::Id, MediaCastMode> available_source_map;
+  for (const auto& cast_mode : cast_modes_) {
+    for (const auto& source :
+         query_result_manager_->GetSourcesForCastMode(cast_mode)) {
+      available_source_map.insert(std::make_pair(source.id(), cast_mode));
+    }
+  }
+
+  routes_and_cast_modes_.clear();
+  for (const auto& route : routes_) {
+    auto source_entry = available_source_map.find(route.media_source().id());
+    if (source_entry != available_source_map.end()) {
+      routes_and_cast_modes_.insert(
+          std::make_pair(route.media_route_id(), source_entry->second));
+    }
+  }
+}
+
 void MediaRouterUI::Close() {
   ConstrainedWebDialogDelegate* delegate = GetConstrainedDelegate();
   if (delegate) {
@@ -563,28 +565,33 @@
 void MediaRouterUI::OnRoutesUpdated(
     const std::vector<MediaRoute>& routes,
     const std::vector<MediaRoute::Id>& joinable_route_ids) {
-  routes_ = routes;
-  joinable_route_ids_ = joinable_route_ids;
+  routes_.clear();
+  joinable_route_ids_.clear();
 
-  std::unordered_map<MediaSource::Id, MediaCastMode> available_source_map;
-  for (const auto& cast_mode : cast_modes_) {
-    for (const auto& source :
-         query_result_manager_->GetSourcesForCastMode(cast_mode)) {
-      available_source_map.insert(std::make_pair(source.id(), cast_mode));
+  for (const MediaRoute& route : routes) {
+    if (route.for_display()) {
+#ifndef NDEBUG
+      for (const MediaRoute& existing_route : routes_) {
+        if (existing_route.media_sink_id() == route.media_sink_id()) {
+          DVLOG(2) << "Received another route for display with the same sink"
+                   << " id as an existing route. " << route.media_route_id()
+                   << " has the same sink id as "
+                   << existing_route.media_sink_id() << ".";
+        }
+      }
+#endif
+      if (base::ContainsValue(joinable_route_ids, route.media_route_id())) {
+        joinable_route_ids_.push_back(route.media_route_id());
+      }
+
+      routes_.push_back(route);
     }
   }
-
-  current_cast_modes_.clear();
-  for (const auto& route : routes) {
-    auto source_entry = available_source_map.find(route.media_source().id());
-    if (source_entry != available_source_map.end()) {
-      current_cast_modes_.insert(
-          std::make_pair(route.media_route_id(), source_entry->second));
-    }
-  }
+  UpdateRoutesToCastModesMapping();
 
   if (ui_initialized_)
-    handler_->UpdateRoutes(routes_, joinable_route_ids_, current_cast_modes_);
+    handler_->UpdateRoutes(routes_, joinable_route_ids_,
+                           routes_and_cast_modes_);
 }
 
 void MediaRouterUI::OnRouteResponseReceived(
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 040f480d..c78740e 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -146,9 +146,9 @@
     return joinable_route_ids_;
   }
   const std::set<MediaCastMode>& cast_modes() const { return cast_modes_; }
-  const std::unordered_map<MediaRoute::Id, MediaCastMode>& current_cast_modes()
-      const {
-    return current_cast_modes_;
+  const std::unordered_map<MediaRoute::Id, MediaCastMode>&
+  routes_and_cast_modes() const {
+    return routes_and_cast_modes_;
   }
   const content::WebContents* initiator() const { return initiator_; }
 
@@ -171,10 +171,8 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SortedSinks);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, SortSinksByIconType);
-  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
-                           UIMediaRoutesObserverFiltersNonDisplayRoutes);
-  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
-      UIMediaRoutesObserverFiltersNonDisplayJoinableRoutes);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, FilterNonDisplayRoutes);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, FilterNonDisplayJoinableRoutes);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
       UIMediaRoutesObserverAssignsCurrentCastModes);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
@@ -278,6 +276,10 @@
   // |handler_|.
   void UpdateCastModes();
 
+  // Updates the routes-to-cast-modes mapping in |routes_and_cast_modes_| to
+  // match the value of |routes_|.
+  void UpdateRoutesToCastModesMapping();
+
   // Returns the default presentation request's frame URL if there is one.
   // Otherwise returns an empty GURL.
   GURL GetFrameURL() const;
@@ -313,7 +315,7 @@
   std::vector<MediaRoute> routes_;
   std::vector<MediaRoute::Id> joinable_route_ids_;
   CastModeSet cast_modes_;
-  std::unordered_map<MediaRoute::Id, MediaCastMode> current_cast_modes_;
+  std::unordered_map<MediaRoute::Id, MediaCastMode> routes_and_cast_modes_;
 
   std::unique_ptr<QueryResultManager> query_result_manager_;
 
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
index b98b15a..924c143 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
@@ -65,6 +65,11 @@
 
 class MediaRouterUITest : public ChromeRenderViewHostTestHarness {
  public:
+  MediaRouterUITest() {
+    ON_CALL(mock_router_, GetCurrentRoutes())
+        .WillByDefault(Return(std::vector<MediaRoute>()));
+  }
+
   void TearDown() override {
     EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_))
         .Times(AnyNumber());
@@ -279,16 +284,10 @@
   EXPECT_EQ(sink3.sink.id(), sorted_sinks[5].sink.id());
 }
 
-TEST_F(MediaRouterUITest, UIMediaRoutesObserverFiltersNonDisplayRoutes) {
-  EXPECT_CALL(mock_router_, RegisterMediaRoutesObserver(_)).Times(1);
-  MediaSource media_source("mediaSource");
-  MockRoutesUpdatedCallback mock_callback;
-  std::unique_ptr<MediaRouterUI::UIMediaRoutesObserver> observer(
-      new MediaRouterUI::UIMediaRoutesObserver(
-          &mock_router_, media_source.id(),
-          base::Bind(&MockRoutesUpdatedCallback::OnRoutesUpdated,
-                     base::Unretained(&mock_callback))));
+TEST_F(MediaRouterUITest, FilterNonDisplayRoutes) {
+  CreateMediaRouterUI(profile());
 
+  MediaSource media_source("mediaSource");
   MediaRoute display_route_1("routeId1", media_source, "sinkId1", "desc 1",
                              true, "", true);
   MediaRoute non_display_route_1("routeId2", media_source, "sinkId2", "desc 2",
@@ -300,32 +299,18 @@
   routes.push_back(non_display_route_1);
   routes.push_back(display_route_2);
 
-  std::vector<MediaRoute> filtered_routes;
-  EXPECT_CALL(mock_callback, OnRoutesUpdated(_, _))
-      .WillOnce(SaveArg<0>(&filtered_routes));
-  observer->OnRoutesUpdated(routes, std::vector<MediaRoute::Id>());
-
-  ASSERT_EQ(2u, filtered_routes.size());
-  EXPECT_TRUE(display_route_1.Equals(filtered_routes[0]));
-  EXPECT_TRUE(filtered_routes[0].for_display());
-  EXPECT_TRUE(display_route_2.Equals(filtered_routes[1]));
-  EXPECT_TRUE(filtered_routes[1].for_display());
-
-  EXPECT_CALL(mock_router_, UnregisterMediaRoutesObserver(_)).Times(1);
-  observer.reset();
+  media_router_ui_->OnRoutesUpdated(routes, std::vector<MediaRoute::Id>());
+  ASSERT_EQ(2u, media_router_ui_->routes_.size());
+  EXPECT_TRUE(display_route_1.Equals(media_router_ui_->routes_[0]));
+  EXPECT_TRUE(media_router_ui_->routes_[0].for_display());
+  EXPECT_TRUE(display_route_2.Equals(media_router_ui_->routes_[1]));
+  EXPECT_TRUE(media_router_ui_->routes_[1].for_display());
 }
 
-TEST_F(MediaRouterUITest,
-    UIMediaRoutesObserverFiltersNonDisplayJoinableRoutes) {
-  EXPECT_CALL(mock_router_, RegisterMediaRoutesObserver(_)).Times(1);
-  MediaSource media_source("mediaSource");
-  MockRoutesUpdatedCallback mock_callback;
-  std::unique_ptr<MediaRouterUI::UIMediaRoutesObserver> observer(
-      new MediaRouterUI::UIMediaRoutesObserver(
-          &mock_router_, media_source.id(),
-          base::Bind(&MockRoutesUpdatedCallback::OnRoutesUpdated,
-                     base::Unretained(&mock_callback))));
+TEST_F(MediaRouterUITest, FilterNonDisplayJoinableRoutes) {
+  CreateMediaRouterUI(profile());
 
+  MediaSource media_source("mediaSource");
   MediaRoute display_route_1("routeId1", media_source, "sinkId1", "desc 1",
                              true, "", true);
   MediaRoute non_display_route_1("routeId2", media_source, "sinkId2", "desc 2",
@@ -342,18 +327,12 @@
   joinable_route_ids.push_back("routeId2");
   joinable_route_ids.push_back("routeId3");
 
-  std::vector<MediaRoute::Id> filtered_joinable_route_ids;
-  // Save the filtered joinable routes.
-  EXPECT_CALL(mock_callback, OnRoutesUpdated(_, _))
-      .WillOnce(SaveArg<1>(&filtered_joinable_route_ids));
-  observer->OnRoutesUpdated(routes, joinable_route_ids);
-
-  ASSERT_EQ(2u, filtered_joinable_route_ids.size());
-  EXPECT_EQ(display_route_1.media_route_id(), filtered_joinable_route_ids[0]);
-  EXPECT_EQ(display_route_2.media_route_id(), filtered_joinable_route_ids[1]);
-
-  EXPECT_CALL(mock_router_, UnregisterMediaRoutesObserver(_)).Times(1);
-  observer.reset();
+  media_router_ui_->OnRoutesUpdated(routes, joinable_route_ids);
+  ASSERT_EQ(2u, media_router_ui_->joinable_route_ids_.size());
+  EXPECT_EQ(display_route_1.media_route_id(),
+            media_router_ui_->joinable_route_ids_[0]);
+  EXPECT_EQ(display_route_2.media_route_id(),
+            media_router_ui_->joinable_route_ids_[1]);
 }
 
 TEST_F(MediaRouterUITest, UIMediaRoutesObserverAssignsCurrentCastModes) {
@@ -389,7 +368,7 @@
   EXPECT_TRUE(display_route_2.Equals(filtered_routes[1]));
   EXPECT_TRUE(filtered_routes[1].for_display());
 
-  const auto& current_cast_modes = media_router_ui_->current_cast_modes();
+  const auto& current_cast_modes = media_router_ui_->routes_and_cast_modes();
   ASSERT_EQ(2u, current_cast_modes.size());
   auto cast_mode_entry =
       current_cast_modes.find(display_route_1.media_route_id());
@@ -438,7 +417,7 @@
   EXPECT_TRUE(display_route_2.Equals(filtered_routes[1]));
   EXPECT_TRUE(filtered_routes[1].for_display());
 
-  const auto& current_cast_modes = media_router_ui_->current_cast_modes();
+  const auto& current_cast_modes = media_router_ui_->routes_and_cast_modes();
   ASSERT_EQ(1u, current_cast_modes.size());
   auto cast_mode_entry =
       current_cast_modes.find(display_route_1.media_route_id());
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
index 89fb3ee..925d47a 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
@@ -274,7 +274,7 @@
   DVLOG(2) << "OnCreateRouteResponseReceived";
   if (route) {
     int current_cast_mode = CurrentCastModeForRouteId(
-        route->media_route_id(), media_router_ui_->current_cast_modes());
+        route->media_route_id(), media_router_ui_->routes_and_cast_modes());
     std::unique_ptr<base::DictionaryValue> route_value(RouteToValue(
         *route, false, media_router_ui_->GetRouteProviderExtensionId(),
         incognito_, current_cast_mode));
@@ -412,7 +412,7 @@
 
   std::unique_ptr<base::ListValue> routes(RoutesToValue(
       media_router_ui_->routes(), media_router_ui_->joinable_route_ids(),
-      media_router_ui_->current_cast_modes()));
+      media_router_ui_->routes_and_cast_modes()));
   initial_data.Set("routes", routes.release());
 
   const std::set<MediaCastMode> cast_modes = media_router_ui_->cast_modes();
diff --git a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
new file mode 100644
index 0000000..3dbd8c6
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.cc
@@ -0,0 +1,100 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
+
+#include "base/values.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"  // kSettingsAppId
+#include "ui/events/event_constants.h"
+
+namespace chromeos {
+namespace settings {
+
+AndroidAppsHandler::AndroidAppsHandler(Profile* profile)
+    : arc_prefs_observer_(this), profile_(profile), weak_ptr_factory_(this) {}
+
+AndroidAppsHandler::~AndroidAppsHandler() {}
+
+void AndroidAppsHandler::RegisterMessages() {
+  web_ui()->RegisterMessageCallback(
+      "requestAndroidAppsInfo",
+      base::Bind(&AndroidAppsHandler::HandleRequestAndroidAppsInfo,
+                 weak_ptr_factory_.GetWeakPtr()));
+  web_ui()->RegisterMessageCallback(
+      "showAndroidAppsSettings",
+      base::Bind(&AndroidAppsHandler::ShowAndroidAppsSettings,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void AndroidAppsHandler::OnJavascriptAllowed() {
+  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
+  if (arc_prefs)
+    arc_prefs_observer_.Add(arc_prefs);
+}
+
+void AndroidAppsHandler::OnJavascriptDisallowed() {
+  arc_prefs_observer_.RemoveAll();
+}
+
+void AndroidAppsHandler::OnAppRegistered(
+    const std::string& app_id,
+    const ArcAppListPrefs::AppInfo& app_info) {
+  OnAppChanged(app_id);
+}
+
+void AndroidAppsHandler::OnAppRemoved(const std::string& app_id) {
+  OnAppChanged(app_id);
+}
+
+void AndroidAppsHandler::OnAppReadyChanged(const std::string& app_id,
+                                           bool ready) {
+  OnAppChanged(app_id);
+}
+
+void AndroidAppsHandler::OnAppChanged(const std::string& app_id) {
+  if (app_id != arc::kSettingsAppId)
+    return;
+  SendAndroidAppsInfo();
+}
+
+std::unique_ptr<base::DictionaryValue>
+AndroidAppsHandler::BuildAndroidAppsInfo() {
+  std::unique_ptr<base::DictionaryValue> info(new base::DictionaryValue);
+  bool app_ready = false;
+  if (arc::ArcSessionManager::Get()->IsArcEnabled()) {
+    std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+        ArcAppListPrefs::Get(profile_)->GetApp(arc::kSettingsAppId);
+    app_ready = app_info && app_info->ready;
+  }
+  info->SetBoolean("appReady", app_ready);
+  return info;
+}
+
+void AndroidAppsHandler::HandleRequestAndroidAppsInfo(
+    const base::ListValue* args) {
+  SendAndroidAppsInfo();
+}
+
+void AndroidAppsHandler::SendAndroidAppsInfo() {
+  AllowJavascript();
+  std::unique_ptr<base::DictionaryValue> info = BuildAndroidAppsInfo();
+  CallJavascriptFunction("cr.webUIListenerCallback",
+                         base::StringValue("android-apps-info-update"), *info);
+}
+
+void AndroidAppsHandler::ShowAndroidAppsSettings(const base::ListValue* args) {
+  CHECK_EQ(1U, args->GetSize());
+  bool activated_from_keyboard = false;
+  args->GetBoolean(0, &activated_from_keyboard);
+  int flags = activated_from_keyboard ? ui::EF_NONE : ui::EF_LEFT_MOUSE_BUTTON;
+
+  // Settings in secondary profile cannot access ARC.
+  CHECK(arc::ArcSessionManager::IsAllowedForProfile(profile_));
+  arc::LaunchAndroidSettingsApp(profile_, flags);
+}
+
+}  // namespace settings
+}  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h
new file mode 100644
index 0000000..7180bb1
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h
@@ -0,0 +1,60 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ANDROID_APPS_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ANDROID_APPS_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/scoped_observer.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+
+class Profile;
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace chromeos {
+namespace settings {
+
+class AndroidAppsHandler : public ::settings::SettingsPageUIHandler,
+                           public ArcAppListPrefs::Observer {
+ public:
+  explicit AndroidAppsHandler(Profile* profile);
+  ~AndroidAppsHandler() override;
+
+  // SettingsPageUIHandler
+  void RegisterMessages() override;
+  void OnJavascriptAllowed() override;
+  void OnJavascriptDisallowed() override;
+
+  // ArcAppListPrefs::Observer
+  void OnAppReadyChanged(const std::string& app_id, bool ready) override;
+  void OnAppRemoved(const std::string& app_id) override;
+  void OnAppRegistered(const std::string& app_id,
+                       const ArcAppListPrefs::AppInfo& app_info) override;
+
+ private:
+  std::unique_ptr<base::DictionaryValue> BuildAndroidAppsInfo();
+  void OnAppChanged(const std::string& app_id);
+  void HandleRequestAndroidAppsInfo(const base::ListValue* args);
+  void SendAndroidAppsInfo();
+  void ShowAndroidAppsSettings(const base::ListValue* args);
+
+  ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
+      arc_prefs_observer_;
+  Profile* profile_;  // unowned
+  base::WeakPtrFactory<AndroidAppsHandler> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AndroidAppsHandler);
+};
+
+}  // namespace settings
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_ANDROID_APPS_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 5843541..df9faab 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -258,6 +258,23 @@
   chromeos::AddAccountUITweaksLocalizedValues(&localized_values, profile);
   html_source->AddLocalizedStrings(localized_values);
 }
+
+void AddAndroidAppStrings(content::WebUIDataSource* html_source) {
+  LocalizedString localized_strings[] = {
+      {"androidAppsPageTitle", IDS_SETTINGS_ANDROID_APPS_TITLE},
+      {"androidAppsEnabled", IDS_SETTINGS_ANDROID_APPS_ENABLE},
+      {"androidAppsManageApps", IDS_SETTINGS_ANDROID_APPS_MANAGE_APPS},
+      {"androidAppsLearnMore", IDS_SETTINGS_ANDROID_APPS_LEARN_MORE},
+      {"androidAppsDisableDialogTitle",
+       IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_TITLE},
+      {"androidAppsDisableDialogMessage",
+       IDS_SETTINGS_ANDROID_APPS_DISABLE_DIALOG_MESSAGE},
+  };
+  AddLocalizedStringsBulk(html_source, localized_strings,
+                          arraysize(localized_strings));
+  html_source->AddString("androidAppsLearnMoreUrl",
+                         chrome::kAndroidAppsLearnMoreURL);
+}
 #endif
 
 void AddAppearanceStrings(content::WebUIDataSource* html_source,
@@ -801,8 +818,6 @@
        IDS_SETTINGS_INTERNET_NETWORK_PROXY_AUTO_CONFIG},
       {"networkProxyConnectionType",
        IDS_SETTINGS_INTERNET_NETWORK_PROXY_CONNECTION_TYPE},
-      {"networkProxyControlledExtension",
-       IDS_SETTINGS_INTERNET_NETWORK_PROXY_CONTROLLED_EXTENSION},
       {"networkProxyEnforcedPolicy",
        IDS_SETTINGS_INTERNET_NETWORK_PROXY_ENFORCED_POLICY},
       {"networkProxyExceptionList",
@@ -1814,6 +1829,7 @@
 
 #if defined(OS_CHROMEOS)
   AddAccountUITweaksStrings(html_source, profile);
+  AddAndroidAppStrings(html_source);
   AddBluetoothStrings(html_source);
   AddCrNetworkStrings(html_source);
   AddDateTimeStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index e8764b2..51c7a5d 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -42,8 +42,10 @@
 
 #if defined(OS_CHROMEOS)
 #include "ash/common/system/chromeos/palette/palette_utils.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
 #include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
+#include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/cups_printers_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h"
@@ -102,6 +104,7 @@
 #if defined(OS_CHROMEOS)
   AddSettingsPageUIHandler(new chromeos::settings::AccessibilityHandler(
       web_ui));
+  AddSettingsPageUIHandler(new chromeos::settings::AndroidAppsHandler(profile));
   AddSettingsPageUIHandler(new chromeos::settings::ChangePictureHandler());
   AddSettingsPageUIHandler(new chromeos::settings::CupsPrintersHandler(web_ui));
   AddSettingsPageUIHandler(new chromeos::settings::KeyboardHandler(web_ui));
@@ -135,6 +138,10 @@
   html_source->AddBoolean("stylusAllowed", ash::IsPaletteFeatureEnabled());
   html_source->AddBoolean("pinUnlockEnabled",
                           chromeos::IsPinUnlockEnabled(profile->GetPrefs()));
+  html_source->AddBoolean(
+      "androidAppsAllowed",
+      arc::ArcSessionManager::IsAllowedForProfile(profile) &&
+          !arc::ArcSessionManager::IsOptInVerificationDisabled());
 #endif
 
   AddSettingsPageUIHandler(AboutHandler::Create(html_source, profile));
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index db8e714..ff0dc83 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -135,6 +135,7 @@
     { "discardable-memory-allocated", kSmallSize },
     { "discardable-memory-free", kSmallSize },
     { kFontKeyName, kSmallSize},
+    { "mojo-message-error", kMediumSize },
     { "ppapi_path", kMediumSize },
     { "subresource_url", kLargeSize },
     { "total-discardable-memory-allocated", kSmallSize },
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index f3cc9a36..91a4d33c 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -599,11 +599,10 @@
 #if defined(OS_CHROMEOS)
 const char kNaturalScrollHelpURL[] =
     "https://support.google.com/chromebook/?p=simple_scrolling";
-#endif
-
-#if defined(OS_CHROMEOS)
 const char kLearnMoreEnterpriseURL[] =
     "https://support.google.com/chromebook/?p=managed";
+const char kAndroidAppsLearnMoreURL[] =
+    "https://support.google.com/chromebook/?p=playapps";
 #endif
 
 const char kRemoveNonCWSExtensionURL[] =
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index 29fde059..bc43563 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -500,6 +500,9 @@
 
 // The URL for the Learn More page about enterprise enrolled devices.
 extern const char kLearnMoreEnterpriseURL[];
+
+// The URL fo the "learn more" link for Google Play Store (Arc++) settings.
+extern const char kAndroidAppsLearnMoreURL[];
 #endif
 
 // The URL for the Learn More link of the non-CWS bubble.
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h
index babf456..251e526 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.h
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h
@@ -47,7 +47,7 @@
   virtual void OnXmppPingUpdated(int ping_timeout) = 0;
 
  protected:
-  // Don't delete through SyncFrontend interface.
+  // Don't delete through CloudPrintProxyFrontend interface.
   virtual ~CloudPrintProxyFrontend() {}
 
  private:
@@ -79,7 +79,8 @@
   bool PostCoreTask(const tracked_objects::Location& from_here,
                     const base::Closure& task);
 
-  // The real guts of SyncBackendHost, to keep the public client API clean.
+  // The real guts of CloudPrintProxyBackend, to keep the public client API
+  // clean.
   class Core;
 
   // A thread dedicated for use to perform initialization and authentication.
@@ -90,7 +91,7 @@
   scoped_refptr<Core> core_;
 
   // A reference to the TaskRunner used to construct |this|, so we know how to
-  // safely talk back to the SyncFrontend.
+  // safely talk back to the CloudPrintProxyFrontend.
   const scoped_refptr<base::SingleThreadTaskRunner> frontend_task_runner_;
 
   // The frontend which is responsible for displaying UI and updating Prefs.
diff --git a/chrome/test/data/webui/settings/android_apps_page_test.js b/chrome/test/data/webui/settings/android_apps_page_test.js
new file mode 100644
index 0000000..52d8bc41
--- /dev/null
+++ b/chrome/test/data/webui/settings/android_apps_page_test.js
@@ -0,0 +1,115 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @constructor
+ * @implements {settings.AndroidAppsBrowserProxy}
+ * @extends {settings.TestBrowserProxy}
+ */
+function TestAndroidAppsBrowserProxy() {
+  settings.TestBrowserProxy.call(this, [
+    'requestAndroidAppsInfo',
+    'showAndroidAppsSettings',
+  ]);
+
+  /** @private {!AndroidAppsInfo} */
+  this.androidAppsInfo_ = {appReady: false};
+}
+
+TestAndroidAppsBrowserProxy.prototype = {
+  __proto__: settings.TestBrowserProxy.prototype,
+
+  /** @override */
+  requestAndroidAppsInfo: function() {
+    this.methodCalled('requestAndroidAppsInfo');
+  },
+
+  /** override */
+  showAndroidAppsSettings: function(keyboardAction) {
+    this.methodCalled('showAndroidAppsSettings');
+  },
+};
+
+/** @type {?SettingsAndroidAppsPageElement} */
+var androidAppsPage = null;
+
+/** @type {?TestAndroidAppsBrowserProxy} */
+var androidAppsBrowserProxy = null;
+
+suite('AndroidAppsPageTests', function() {
+  setup(function() {
+    androidAppsBrowserProxy = new TestAndroidAppsBrowserProxy();
+    settings.AndroidAppsBrowserProxyImpl.instance_ = androidAppsBrowserProxy;
+    PolymerTest.clearBody();
+    androidAppsPage = document.createElement('settings-android-apps-page');
+    document.body.appendChild(androidAppsPage);
+  });
+
+  teardown(function() { androidAppsPage.remove(); });
+
+  test('Enable', function() {
+    return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
+        .then(function() {
+          androidAppsPage.prefs = {
+            arc: {
+              enabled: {
+                value: false,
+              },
+            },
+          };
+          cr.webUIListenerCallback(
+              'android-apps-info-update', {appReady: false});
+          Polymer.dom.flush();
+          var checkbox = androidAppsPage.$$('#enabledCheckbox');
+          assertTrue(!!checkbox);
+          assertFalse(checkbox.disabled);
+          assertFalse(checkbox.checked);
+          var managed = androidAppsPage.$$('#manageApps');
+          assertTrue(!!managed);
+          assertTrue(managed.hidden);
+
+          MockInteractions.tap(checkbox.$.checkbox);
+          Polymer.dom.flush();
+          assertTrue(checkbox.checked);
+        });
+  });
+
+  test('Disable', function() {
+    return androidAppsBrowserProxy.whenCalled('requestAndroidAppsInfo')
+        .then(function() {
+          androidAppsPage.prefs = {
+            arc: {
+              enabled: {
+                value: true,
+              },
+            },
+          };
+          cr.webUIListenerCallback(
+              'android-apps-info-update', {appReady: true});
+          Polymer.dom.flush();
+          var checkbox = androidAppsPage.$$('#enabledCheckbox');
+          assertTrue(!!checkbox);
+          assertFalse(checkbox.disabled);
+          assertTrue(checkbox.checked);
+          var managed = androidAppsPage.$$('#manageApps');
+          assertTrue(!!managed);
+          assertFalse(managed.hidden);
+
+          MockInteractions.tap(checkbox.$.checkbox);
+          cr.webUIListenerCallback(
+              'android-apps-info-update', {appReady: false});
+          Polymer.dom.flush();
+          var dialog = androidAppsPage.$$('#confirmDisableDialog');
+          assertTrue(!!dialog);
+          assertTrue(dialog.open);
+          var actionButton =
+              androidAppsPage.$$('dialog paper-button.action-button');
+          assertTrue(!!actionButton);
+          MockInteractions.tap(actionButton);
+          Polymer.dom.flush();
+          assertFalse(checkbox.checked);
+          assertTrue(managed.hidden);
+        });
+  });
+});
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index eb87a61..f2ebd53 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1090,9 +1090,35 @@
 });
 
 GEN('#endif');
+
 GEN('#if defined(OS_CHROMEOS)');
 
 /**
+ * Test fixture for the Google Play Store (Arc++) page.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsAndroidAppsPageTest() {}
+
+CrSettingsAndroidAppsPageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload:
+      'chrome://md-settings/android_apps_page/android_apps_page.html',
+
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    ROOT_PATH + 'ui/webui/resources/js/promise_resolver.js',
+    'test_browser_proxy.js',
+    'android_apps_page_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsAndroidAppsPageTest', 'AndroidAppsPageTest', function() {
+  mocha.run();
+});
+
+/**
  * Test fixture for the Date and Time page.
  * @constructor
  * @extends {CrSettingsBrowserTest}
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc
index 4d82fe1..c8f79d70 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -31,15 +31,15 @@
 
 namespace {
 
-class SyncBackendHostForProfileSyncTest : public SyncBackendHostImpl {
+class SyncEngineForProfileSyncTest : public SyncBackendHostImpl {
  public:
-  SyncBackendHostForProfileSyncTest(
+  SyncEngineForProfileSyncTest(
       const base::FilePath& temp_dir,
       syncer::SyncClient* sync_client,
       invalidation::InvalidationService* invalidator,
       const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
       const base::Closure& callback);
-  ~SyncBackendHostForProfileSyncTest() override;
+  ~SyncEngineForProfileSyncTest() override;
 
   void RequestConfigureSyncer(
       syncer::ConfigureReason reason,
@@ -58,14 +58,14 @@
 
  private:
   // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop.
-  // Allows extra initialization work to be performed before the backend comes
+  // Allows extra initialization work to be performed before the engine comes
   // up.
   base::Closure callback_;
 
-  DISALLOW_COPY_AND_ASSIGN(SyncBackendHostForProfileSyncTest);
+  DISALLOW_COPY_AND_ASSIGN(SyncEngineForProfileSyncTest);
 };
 
-SyncBackendHostForProfileSyncTest::SyncBackendHostForProfileSyncTest(
+SyncEngineForProfileSyncTest::SyncEngineForProfileSyncTest(
     const base::FilePath& temp_dir,
     syncer::SyncClient* sync_client,
     invalidation::InvalidationService* invalidator,
@@ -79,9 +79,9 @@
           temp_dir.Append(base::FilePath(FILE_PATH_LITERAL("test")))),
       callback_(callback) {}
 
-SyncBackendHostForProfileSyncTest::~SyncBackendHostForProfileSyncTest() {}
+SyncEngineForProfileSyncTest::~SyncEngineForProfileSyncTest() {}
 
-void SyncBackendHostForProfileSyncTest::InitCore(
+void SyncEngineForProfileSyncTest::InitCore(
     std::unique_ptr<syncer::DoInitializeOptions> options) {
   options->http_bridge_factory = base::MakeUnique<TestHttpBridgeFactory>();
   options->sync_manager_factory =
@@ -92,8 +92,8 @@
   options->restored_key_for_bootstrapping.clear();
 
   // It'd be nice if we avoided creating the EngineComponentsFactory in the
-  // first place, but SyncBackendHost will have created one by now so we must
-  // free it. Grab the switches to pass on first.
+  // first place, but SyncEngine will have created one by now so we must free
+  // it. Grab the switches to pass on first.
   syncer::EngineComponentsFactory::Switches factory_switches =
       options->engine_components_factory->GetSwitches();
   options->engine_components_factory =
@@ -104,7 +104,7 @@
   SyncBackendHostImpl::InitCore(std::move(options));
 }
 
-void SyncBackendHostForProfileSyncTest::RequestConfigureSyncer(
+void SyncEngineForProfileSyncTest::RequestConfigureSyncer(
     syncer::ConfigureReason reason,
     syncer::ModelTypeSet to_download,
     syncer::ModelTypeSet to_purge,
@@ -124,12 +124,12 @@
   // Posted to avoid re-entrancy issues.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::Bind(&SyncBackendHostForProfileSyncTest::
-                     FinishConfigureDataTypesOnFrontendLoop,
-                 base::Unretained(this),
-                 syncer::Difference(to_download, failed_configuration_types),
-                 syncer::Difference(to_download, failed_configuration_types),
-                 failed_configuration_types, ready_task));
+      base::Bind(
+          &SyncEngineForProfileSyncTest::FinishConfigureDataTypesOnFrontendLoop,
+          base::Unretained(this),
+          syncer::Difference(to_download, failed_configuration_types),
+          syncer::Difference(to_download, failed_configuration_types),
+          failed_configuration_types, ready_task));
 }
 
 // Helper function for return-type-upcasting of the callback.
@@ -191,8 +191,8 @@
 
   syncer::SyncApiComponentFactoryMock* components =
       profile_sync_service_bundle_.component_factory();
-  EXPECT_CALL(*components, CreateSyncBackendHost(_, _, _, _))
-      .WillOnce(Return(new SyncBackendHostForProfileSyncTest(
+  EXPECT_CALL(*components, CreateSyncEngine(_, _, _, _))
+      .WillOnce(Return(new SyncEngineForProfileSyncTest(
           temp_dir_.GetPath(), sync_service_->GetSyncClient(),
           profile_sync_service_bundle_.fake_invalidation_service(),
           sync_service_->sync_prefs()->AsWeakPtr(),
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 5a55d2c1..4f1626e 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -30,7 +30,6 @@
 #include "components/sync/device_info/device_info_data_type_controller.h"
 #include "components/sync/device_info/local_device_info_provider_impl.h"
 #include "components/sync/driver/data_type_manager_impl.h"
-#include "components/sync/driver/glue/sync_backend_host.h"
 #include "components/sync/driver/glue/sync_backend_host_impl.h"
 #include "components/sync/driver/model_type_controller.h"
 #include "components/sync/driver/non_ui_data_type_controller.h"
@@ -39,6 +38,7 @@
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/attachments/attachment_downloader.h"
 #include "components/sync/engine/attachments/attachment_uploader.h"
+#include "components/sync/engine/sync_engine.h"
 #include "components/sync/model/attachments/attachment_service.h"
 #include "components/sync_bookmarks/bookmark_change_processor.h"
 #include "components/sync_bookmarks/bookmark_data_type_controller.h"
@@ -301,14 +301,13 @@
         debug_info_listener,
     const DataTypeController::TypeMap* controllers,
     const syncer::DataTypeEncryptionHandler* encryption_handler,
-    syncer::SyncBackendHost* backend,
+    syncer::SyncEngine* engine,
     DataTypeManagerObserver* observer) {
   return new DataTypeManagerImpl(debug_info_listener, controllers,
-                                 encryption_handler, backend, observer);
+                                 encryption_handler, engine, observer);
 }
 
-syncer::SyncBackendHost*
-ProfileSyncComponentsFactoryImpl::CreateSyncBackendHost(
+syncer::SyncEngine* ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
     const std::string& name,
     invalidation::InvalidationService* invalidator,
     const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index 4b0a641..ab96295 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -69,9 +69,9 @@
           debug_info_listener,
       const syncer::DataTypeController::TypeMap* controllers,
       const syncer::DataTypeEncryptionHandler* encryption_handler,
-      syncer::SyncBackendHost* backend,
+      syncer::SyncEngine* engine,
       syncer::DataTypeManagerObserver* observer) override;
-  syncer::SyncBackendHost* CreateSyncBackendHost(
+  syncer::SyncEngine* CreateSyncEngine(
       const std::string& name,
       invalidation::InvalidationService* invalidator,
       const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 0b436ed..aea8af1 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -108,7 +108,7 @@
 using syncer::ModelTypeSet;
 using syncer::ModelTypeStore;
 using syncer::ProtocolEventObserver;
-using syncer::SyncBackendHost;
+using syncer::SyncEngine;
 using syncer::SyncCredentials;
 using syncer::SyncProtocolError;
 using syncer::WeakHandle;
@@ -542,11 +542,10 @@
       local_sync_backend_folder.Append(kLoopbackServerBackendFilename);
 #endif  // defined(OS_WIN)
 
-  SyncBackendHost::HttpPostProviderFactoryGetter
-      http_post_provider_factory_getter =
-          base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory,
-                     base::Unretained(network_resources_.get()),
-                     url_request_context_, network_time_update_callback_);
+  SyncEngine::HttpPostProviderFactoryGetter http_post_provider_factory_getter =
+      base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory,
+                 base::Unretained(network_resources_.get()),
+                 url_request_context_, network_time_update_callback_);
 
   backend_->Initialize(
       this, sync_thread_->task_runner(), GetJsEventHandler(), sync_service_url_,
@@ -632,14 +631,12 @@
   invalidation::InvalidationService* invalidator =
       sync_client_->GetInvalidationService();
 
-  backend_.reset(
-      sync_client_->GetSyncApiComponentFactory()->CreateSyncBackendHost(
-          debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
-          directory_path_));
+  backend_.reset(sync_client_->GetSyncApiComponentFactory()->CreateSyncEngine(
+      debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
+      directory_path_));
 
-  // Initialize the backend.  Every time we start up a new SyncBackendHost,
-  // we'll want to start from a fresh SyncDB, so delete any old one that might
-  // be there.
+  // Initialize the backend. Every time we start up a new SyncEngine, we'll want
+  // to start from a fresh SyncDB, so delete any old one that might be there.
   InitializeBackend(ShouldDeleteSyncFolder());
 
   UpdateFirstSyncTimePref();
@@ -805,6 +802,7 @@
 
   backend_->Shutdown(reason);
   backend_.reset();
+
   base::TimeDelta shutdown_time = base::Time::Now() - shutdown_start_time;
   UMA_HISTOGRAM_TIMES("Sync.Shutdown.BackendDestroyedTime", shutdown_time);
 
@@ -844,7 +842,7 @@
   switch (data_fate) {
     case KEEP_DATA:
       // TODO(maxbogue): Investigate whether this logic can/should be moved
-      // into ShutdownImpl or SyncBackendHost itself.
+      // into ShutdownImpl or the sync engine itself.
       if (HasSyncingBackend()) {
         backend_->UnregisterInvalidationIds();
       }
@@ -959,7 +957,7 @@
 
   base::Time on_backend_initialized_time = base::Time::Now();
   base::TimeDelta delta =
-      on_backend_initialized_time - startup_controller_->start_backend_time();
+      on_backend_initialized_time - startup_controller_->start_engine_time();
   if (is_first_time_sync_configure_) {
     UMA_HISTOGRAM_LONG_TIMES("Sync.BackendInitializeFirstTime", delta);
   } else {
@@ -1503,7 +1501,7 @@
 
 std::string ProfileSyncService::GetBackendInitializationStateString() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return startup_controller_->GetBackendInitializationStateString();
+  return startup_controller_->GetEngineInitializationStateString();
 }
 
 bool ProfileSyncService::IsSetupInProgress() const {
@@ -1511,14 +1509,13 @@
   return startup_controller_->IsSetupInProgress();
 }
 
-bool ProfileSyncService::QueryDetailedSyncStatus(
-    SyncBackendHost::Status* result) {
+bool ProfileSyncService::QueryDetailedSyncStatus(SyncEngine::Status* result) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (backend_.get() && backend_initialized_) {
     *result = backend_->GetDetailedStatus();
     return true;
   } else {
-    SyncBackendHost::Status status;
+    SyncEngine::Status status;
     status.sync_protocol_error = last_actionable_error_;
     *result = status;
     return false;
@@ -1929,7 +1926,7 @@
     }
   }
 
-  SyncBackendHost::Status detailed_status = backend_->GetDetailedStatus();
+  SyncEngine::Status detailed_status = backend_->GetDetailedStatus();
   ModelTypeSet& throttled_types(detailed_status.throttled_types);
   ModelTypeSet& backed_off_types(detailed_status.backed_off_types);
   ModelTypeSet registered = GetRegisteredDataTypes();
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index b63dda54..f974d5d2 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -37,16 +37,16 @@
 #include "components/sync/driver/data_type_manager.h"
 #include "components/sync/driver/data_type_manager_observer.h"
 #include "components/sync/driver/data_type_status_table.h"
-#include "components/sync/driver/glue/sync_backend_host.h"
 #include "components/sync/driver/startup_controller.h"
 #include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_frontend.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_stopped_reporter.h"
 #include "components/sync/engine/events/protocol_event_observer.h"
 #include "components/sync/engine/model_safe_worker.h"
 #include "components/sync/engine/net/network_time_update_callback.h"
 #include "components/sync/engine/shutdown_reason.h"
+#include "components/sync/engine/sync_engine.h"
+#include "components/sync/engine/sync_engine_host.h"
 #include "components/sync/engine/sync_manager_factory.h"
 #include "components/sync/js/sync_js_controller.h"
 #include "components/sync/syncable/user_share.h"
@@ -172,7 +172,7 @@
 //   setup-in-progress handles, CanConfigureDataTypes() will return true and
 //   datatype configuration can begin.
 class ProfileSyncService : public syncer::SyncService,
-                           public syncer::SyncFrontend,
+                           public syncer::SyncEngineHost,
                            public syncer::SyncPrefObserver,
                            public syncer::DataTypeManagerObserver,
                            public syncer::UnrecoverableErrorHandler,
@@ -182,7 +182,7 @@
                            public SigninManagerBase::Observer,
                            public GaiaCookieManagerService::Observer {
  public:
-  typedef syncer::SyncBackendHost::Status Status;
+  typedef syncer::SyncEngine::Status Status;
   typedef base::Callback<bool(void)> PlatformSyncAllowedProvider;
 
   enum SyncEventCodes {
@@ -358,7 +358,7 @@
   // Called when asynchronous session restore has completed.
   void OnSessionRestoreComplete();
 
-  // SyncFrontend implementation.
+  // SyncEngineHost implementation.
   void OnBackendInitialized(
       const syncer::WeakHandle<syncer::JsBackend>& js_backend,
       const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
@@ -642,7 +642,7 @@
 
   // Helper for OnUnrecoverableError.
   // TODO(tim): Use an enum for |delete_sync_database| here, in ShutdownImpl,
-  // and in SyncBackendHost::Shutdown.
+  // and in SyncEngine::Shutdown.
   void OnUnrecoverableErrorImpl(const tracked_objects::Location& from_here,
                                 const std::string& message,
                                 bool delete_sync_database);
@@ -775,7 +775,7 @@
 
   // Our asynchronous backend to communicate with sync components living on
   // other threads.
-  std::unique_ptr<syncer::SyncBackendHost> backend_;
+  std::unique_ptr<syncer::SyncEngine> backend_;
 
   // Was the last SYNC_PASSPHRASE_REQUIRED notification sent because it
   // was required for encryption, decryption with a cached passphrase, or
@@ -829,7 +829,7 @@
   // List of available data type controllers.
   syncer::DataTypeController::TypeMap data_type_controllers_;
 
-  // Whether the SyncBackendHost has been initialized.
+  // Whether the SyncEngine has been initialized.
   bool backend_initialized_;
 
   // Set when sync receives DISABLED_BY_ADMIN error from server. Prevents
diff --git a/components/browser_sync/profile_sync_service_mock.h b/components/browser_sync/profile_sync_service_mock.h
index eea9041..2c735276 100644
--- a/components/browser_sync/profile_sync_service_mock.h
+++ b/components/browser_sync/profile_sync_service_mock.h
@@ -67,7 +67,7 @@
   MOCK_CONST_METHOD0(GetLastCycleSnapshot, syncer::SyncCycleSnapshot());
 
   MOCK_METHOD1(QueryDetailedSyncStatus,
-               bool(syncer::SyncBackendHost::Status* result));
+               bool(syncer::SyncEngine::Status* result));
   MOCK_CONST_METHOD0(GetAuthError, const GoogleServiceAuthError&());
   MOCK_CONST_METHOD0(IsFirstSetupInProgress, bool());
   MOCK_CONST_METHOD0(GetLastSyncedTimeString, base::string16());
diff --git a/components/browser_sync/profile_sync_service_startup_unittest.cc b/components/browser_sync/profile_sync_service_startup_unittest.cc
index 8a42187..61192bd 100644
--- a/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -18,9 +18,9 @@
 #include "components/sync/base/pref_names.h"
 #include "components/sync/driver/data_type_manager_mock.h"
 #include "components/sync/driver/fake_data_type_controller.h"
-#include "components/sync/driver/glue/sync_backend_host_mock.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
 #include "components/sync/driver/sync_service_observer.h"
+#include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -30,7 +30,7 @@
 
 using syncer::DataTypeManager;
 using syncer::DataTypeManagerMock;
-using syncer::SyncBackendHostMock;
+using syncer::FakeSyncEngine;
 using testing::_;
 using testing::AnyNumber;
 using testing::DoAll;
@@ -136,9 +136,9 @@
     return data_type_manager;
   }
 
-  SyncBackendHostMock* SetUpSyncBackendHost() {
-    SyncBackendHostMock* sync_backend_host = new SyncBackendHostMock();
-    EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+  FakeSyncEngine* SetUpSyncEngine() {
+    FakeSyncEngine* sync_backend_host = new FakeSyncEngine();
+    EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
         .WillOnce(Return(sync_backend_host));
     return sync_backend_host;
   }
@@ -169,7 +169,7 @@
   // We've never completed startup.
   pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
   CreateSyncService(ProfileSyncService::MANUAL_START);
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _)).Times(0);
 
@@ -243,7 +243,7 @@
 TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartInvalidCredentials) {
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
-  SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
+  FakeSyncEngine* mock_sbh = SetUpSyncEngine();
 
   // Tell the backend to stall while downloading control types (simulating an
   // auth error).
@@ -277,7 +277,7 @@
 TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
   EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _))
       .Times(0);
-  EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _)).Times(0);
+  EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _)).Times(0);
   pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
   EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber());
 
@@ -291,7 +291,7 @@
 }
 
 TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
   EXPECT_CALL(*data_type_manager, Configure(_, _));
@@ -312,7 +312,7 @@
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
   sync_service_->SetFirstSetupComplete();
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _));
   EXPECT_CALL(*data_type_manager, state())
@@ -342,7 +342,7 @@
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
   sync_service_->SetFirstSetupComplete();
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _));
   EXPECT_CALL(*data_type_manager, state())
@@ -368,7 +368,7 @@
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
   sync_service_->SetFirstSetupComplete();
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _));
   EXPECT_CALL(*data_type_manager, state())
@@ -400,7 +400,7 @@
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
   sync_service_->SetFirstSetupComplete();
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   EXPECT_CALL(*data_type_manager, Configure(_, _));
   EXPECT_CALL(*data_type_manager, state())
@@ -435,7 +435,7 @@
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
   sync_service_->SetFirstSetupComplete();
-  SetUpSyncBackendHost();
+  SetUpSyncEngine();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED;
   DataTypeManager::ConfigureResult result(status, syncer::ModelTypeSet());
@@ -459,7 +459,7 @@
   // Pre load the tokens
   CreateSyncService(ProfileSyncService::MANUAL_START);
   std::string account_id = SimulateTestUserSignin(sync_service_.get());
-  SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost();
+  FakeSyncEngine* mock_sbh = SetUpSyncEngine();
   mock_sbh->set_fail_initial_download(true);
 
   pref_service()->ClearPref(syncer::prefs::kSyncFirstSetupComplete);
diff --git a/components/browser_sync/profile_sync_service_unittest.cc b/components/browser_sync/profile_sync_service_unittest.cc
index be4ced1..824304b1 100644
--- a/components/browser_sync/profile_sync_service_unittest.cc
+++ b/components/browser_sync/profile_sync_service_unittest.cc
@@ -27,11 +27,11 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/driver/fake_data_type_controller.h"
-#include "components/sync/driver/glue/sync_backend_host_mock.h"
 #include "components/sync/driver/sync_api_component_factory_mock.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/driver/sync_service_observer.h"
 #include "components/sync/driver/sync_util.h"
+#include "components/sync/engine/fake_sync_engine.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/version_info/version_info_values.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -40,7 +40,7 @@
 #include "ui/base/l10n/l10n_util.h"
 
 using syncer::DataTypeController;
-using syncer::SyncBackendHostMock;
+using syncer::FakeSyncEngine;
 using syncer::SyncMergeResult;
 using testing::Return;
 
@@ -99,12 +99,12 @@
   bool setup_in_progress_;
 };
 
-// A variant of the SyncBackendHostMock that won't automatically
-// call back when asked to initialized.  Allows us to test things
-// that could happen while backend init is in progress.
-class SyncBackendHostNoReturn : public SyncBackendHostMock {
+// A variant of the FakeSyncEngine that won't automatically call back when asked
+// to initialized. Allows us to test things that could happen while backend init
+// is in progress.
+class SyncEngineNoReturn : public FakeSyncEngine {
   void Initialize(
-      syncer::SyncFrontend* frontend,
+      syncer::SyncEngineHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
       const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -122,14 +122,14 @@
           saved_nigori_state) override {}
 };
 
-class SyncBackendHostMockCollectDeleteDirParam : public SyncBackendHostMock {
+class FakeSyncEngineCollectDeleteDirParam : public FakeSyncEngine {
  public:
-  explicit SyncBackendHostMockCollectDeleteDirParam(
+  explicit FakeSyncEngineCollectDeleteDirParam(
       std::vector<bool>* delete_dir_param)
       : delete_dir_param_(delete_dir_param) {}
 
   void Initialize(
-      syncer::SyncFrontend* frontend,
+      syncer::SyncEngineHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
       const syncer::WeakHandle<syncer::JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -146,8 +146,8 @@
       std::unique_ptr<syncer::SyncEncryptionHandler::NigoriState>
           saved_nigori_state) override {
     delete_dir_param_->push_back(delete_sync_data_folder);
-    SyncBackendHostMock::Initialize(
-        frontend, std::move(sync_task_runner), event_handler, service_url,
+    FakeSyncEngine::Initialize(
+        host, std::move(sync_task_runner), event_handler, service_url,
         sync_user_agent, credentials, delete_sync_data_folder,
         enable_local_sync_backend, local_sync_backend_folder,
         std::move(sync_manager_factory), unrecoverable_error_handler,
@@ -159,14 +159,14 @@
   std::vector<bool>* delete_dir_param_;
 };
 
-// SyncBackendHostMock that calls an external callback when ClearServerData is
+// FakeSyncEngine that calls an external callback when ClearServerData is
 // called.
-class SyncBackendHostCaptureClearServerData : public SyncBackendHostMock {
+class SyncEngineCaptureClearServerData : public FakeSyncEngine {
  public:
   typedef base::Callback<void(
       const syncer::SyncManager::ClearServerDataCallback&)>
       ClearServerDataCalled;
-  explicit SyncBackendHostCaptureClearServerData(
+  explicit SyncEngineCaptureClearServerData(
       const ClearServerDataCalled& clear_server_data_called)
       : clear_server_data_called_(clear_server_data_called) {}
 
@@ -179,16 +179,16 @@
   ClearServerDataCalled clear_server_data_called_;
 };
 
-ACTION(ReturnNewSyncBackendHostMock) {
-  return new SyncBackendHostMock();
+ACTION(ReturnNewFakeSyncEngine) {
+  return new FakeSyncEngine();
 }
 
-ACTION(ReturnNewSyncBackendHostNoReturn) {
-  return new SyncBackendHostNoReturn();
+ACTION(ReturnNewSyncEngineNoReturn) {
+  return new SyncEngineNoReturn();
 }
 
 ACTION_P(ReturnNewMockHostCollectDeleteDirParam, delete_dir_param) {
-  return new SyncBackendHostMockCollectDeleteDirParam(delete_dir_param);
+  return new FakeSyncEngineCollectDeleteDirParam(delete_dir_param);
 }
 
 void OnClearServerDataCalled(
@@ -198,7 +198,7 @@
 }
 
 ACTION_P(ReturnNewMockHostCaptureClearServerData, captured_callback) {
-  return new SyncBackendHostCaptureClearServerData(base::Bind(
+  return new SyncEngineCaptureClearServerData(base::Bind(
       &OnClearServerDataCalled, base::Unretained(captured_callback)));
 }
 
@@ -207,10 +207,10 @@
                const SyncMergeResult& ignored3) {}
 
 // A test harness that uses a real ProfileSyncService and in most cases a
-// MockSyncBackendHost.
+// MockSyncEngine.
 //
 // This is useful if we want to test the ProfileSyncService and don't care about
-// testing the SyncBackendHost.
+// testing the SyncEngine.
 class ProfileSyncServiceTest : public ::testing::Test {
  protected:
   ProfileSyncServiceTest() : component_factory_(nullptr) {}
@@ -315,31 +315,31 @@
         .WillRepeatedly(ReturnNewDataTypeManager(callback));
   }
 
-  void ExpectSyncBackendHostCreation(int times) {
-    EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+  void ExpectSyncEngineCreation(int times) {
+    EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
         .Times(times)
-        .WillRepeatedly(ReturnNewSyncBackendHostMock());
+        .WillRepeatedly(ReturnNewFakeSyncEngine());
   }
 
-  void ExpectSyncBackendHostCreationCollectDeleteDir(
+  void ExpectSyncEngineCreationCollectDeleteDir(
       int times,
       std::vector<bool>* delete_dir_param) {
-    EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+    EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
         .Times(times)
         .WillRepeatedly(
             ReturnNewMockHostCollectDeleteDirParam(delete_dir_param));
   }
 
-  void ExpectSyncBackendHostCreationCaptureClearServerData(
+  void ExpectSyncEngineCreationCaptureClearServerData(
       syncer::SyncManager::ClearServerDataCallback* captured_callback) {
-    EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
+    EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
         .Times(1)
         .WillOnce(ReturnNewMockHostCaptureClearServerData(captured_callback));
   }
 
-  void PrepareDelayedInitSyncBackendHost() {
-    EXPECT_CALL(*component_factory_, CreateSyncBackendHost(_, _, _, _))
-        .WillOnce(ReturnNewSyncBackendHostNoReturn());
+  void PrepareDelayedInitSyncEngine() {
+    EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
+        .WillOnce(ReturnNewSyncEngineNoReturn());
   }
 
   AccountTrackerService* account_tracker() {
@@ -404,7 +404,7 @@
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
   EXPECT_FALSE(service()->IsManaged());
   EXPECT_TRUE(service()->IsSyncActive());
@@ -464,7 +464,7 @@
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   EXPECT_FALSE(service()->IsManaged());
@@ -481,7 +481,7 @@
 // before the backend initialize call returns.
 TEST_F(ProfileSyncServiceTest, AbortedByShutdown) {
   CreateService(ProfileSyncService::AUTO_START);
-  PrepareDelayedInitSyncBackendHost();
+  PrepareDelayedInitSyncEngine();
 
   IssueTestTokens();
   InitializeForNthSync();
@@ -495,7 +495,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
 
   service()->RequestStop(ProfileSyncService::KEEP_DATA);
   EXPECT_FALSE(service()->IsSyncRequested());
@@ -516,7 +516,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
@@ -529,7 +529,7 @@
   EXPECT_TRUE(prefs()->GetBoolean(syncer::prefs::kSyncSuppressStart));
 
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
 
   service()->RequestStart();
   EXPECT_TRUE(service()->IsSyncActive());
@@ -542,7 +542,7 @@
 TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   IssueTestTokens();
   InitializeForNthSync();
 
@@ -559,7 +559,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   // Initial status.
@@ -596,7 +596,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
   EXPECT_TRUE(service()->IsSyncActive());
 
@@ -625,7 +625,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
   EXPECT_TRUE(service()->IsSyncActive());
 
@@ -646,7 +646,7 @@
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
   EXPECT_TRUE(service()->IsSyncActive());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW),
@@ -678,7 +678,7 @@
   CreateService(ProfileSyncService::AUTO_START);
   IssueTestTokens();
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
@@ -726,10 +726,10 @@
   syncer::SyncManager::ClearServerDataCallback captured_callback;
   syncer::ConfigureReason configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
 
-  // Initialize sync, ensure that both DataTypeManager and SyncBackendHost are
+  // Initialize sync, ensure that both DataTypeManager and SyncEngine are
   // initialized and DTM::Configure is called with
   // CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE.
-  ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+  ExpectSyncEngineCreationCaptureClearServerData(&captured_callback);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   InitializeForNthSync();
@@ -755,7 +755,7 @@
   // Once SBH::ClearServerData finishes successfully ensure that sync is
   // restarted.
   configure_reason = syncer::CONFIGURE_REASON_UNKNOWN;
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   captured_callback.Run();
@@ -774,7 +774,7 @@
       switches::kSyncClearDataOnPassphraseEncryption);
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   InitializeForNthSync();
@@ -793,7 +793,7 @@
   // Simulate browser restart. First configuration is a regular one.
   service()->Shutdown();
   syncer::SyncManager::ClearServerDataCallback captured_callback;
-  ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+  ExpectSyncEngineCreationCaptureClearServerData(&captured_callback);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   service()->RequestStart();
@@ -811,7 +811,7 @@
   service()->OnConfigureDone(result);
   EXPECT_FALSE(captured_callback.is_null());
 
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   captured_callback.Run();
@@ -830,7 +830,7 @@
       switches::kSyncClearDataOnPassphraseEncryption);
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
-  ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+  ExpectSyncEngineCreationCaptureClearServerData(&captured_callback);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
   InitializeForNthSync();
   testing::Mock::VerifyAndClearExpectations(component_factory());
@@ -843,7 +843,7 @@
 
   // Simulate browser restart. First configuration is a regular one.
   service()->Shutdown();
-  ExpectSyncBackendHostCreationCaptureClearServerData(&captured_callback);
+  ExpectSyncEngineCreationCaptureClearServerData(&captured_callback);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   service()->RequestStart();
@@ -863,7 +863,7 @@
   service()->OnConfigureDone(result);
   EXPECT_FALSE(captured_callback.is_null());
 
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   ExpectDataTypeManagerCreation(
       1, GetRecordingConfigureCalledCallback(&configure_reason));
   captured_callback.Run();
@@ -877,7 +877,7 @@
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   syncer::SyncPrefs sync_prefs(service()->GetSyncClient()->GetPrefService());
@@ -910,7 +910,7 @@
   // Backend should get initialized two times: once during initialization and
   // once when handling actionable error.
   ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(2);
+  ExpectSyncEngineCreation(2);
   InitializeForNthSync();
 
   syncer::SyncProtocolError client_cmd;
@@ -924,7 +924,7 @@
   IssueTestTokens();
   CreateService(ProfileSyncService::AUTO_START);
   ExpectDataTypeManagerCreation(1, GetDefaultConfigureCalledCallback());
-  ExpectSyncBackendHostCreation(1);
+  ExpectSyncEngineCreation(1);
   InitializeForNthSync();
 
   EXPECT_TRUE(service()->IsSyncActive());
diff --git a/components/password_manager/OWNERS b/components/password_manager/OWNERS
index a1dcd02..bc2ebbb 100644
--- a/components/password_manager/OWNERS
+++ b/components/password_manager/OWNERS
@@ -1,7 +1,6 @@
 dvadym@chromium.org
 engedy@chromium.org
 gcasto@chromium.org
-isherman@chromium.org
 melandory@chromium.org
 mkwst@chromium.org
 vabr@chromium.org
diff --git a/components/signin/core/browser/signin_manager.cc b/components/signin/core/browser/signin_manager.cc
index fc3a0c5..2e3a70445 100644
--- a/components/signin/core/browser/signin_manager.cc
+++ b/components/signin/core/browser/signin_manager.cc
@@ -269,7 +269,7 @@
 }
 
 void SigninManager::OnSigninAllowedPrefChanged() {
-  if (!IsSigninAllowed())
+  if (!IsSigninAllowed() && (IsAuthenticated() || AuthInProgress()))
     SignOut(signin_metrics::SIGNOUT_PREF_CHANGED,
             signin_metrics::SignoutDelete::IGNORE_METRIC);
 }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 90801bc..9a3c4e7 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -99,8 +99,6 @@
     "device_info/local_device_info_provider_impl.h",
     "driver/about_sync_util.cc",
     "driver/about_sync_util.h",
-    "driver/backend_data_type_configurer.cc",
-    "driver/backend_data_type_configurer.h",
     "driver/backend_migrator.cc",
     "driver/backend_migrator.h",
     "driver/data_type_controller.cc",
@@ -122,8 +120,6 @@
     "driver/generic_change_processor.h",
     "driver/generic_change_processor_factory.cc",
     "driver/generic_change_processor_factory.h",
-    "driver/glue/sync_backend_host.cc",
-    "driver/glue/sync_backend_host.h",
     "driver/glue/sync_backend_host_core.cc",
     "driver/glue/sync_backend_host_core.h",
     "driver/glue/sync_backend_host_impl.cc",
@@ -154,8 +150,6 @@
     "driver/sync_driver_switches.h",
     "driver/sync_error_controller.cc",
     "driver/sync_error_controller.h",
-    "driver/sync_frontend.cc",
-    "driver/sync_frontend.h",
     "driver/sync_service.cc",
     "driver/sync_service.h",
     "driver/sync_service_observer.cc",
@@ -167,8 +161,6 @@
     "driver/sync_type_preference_provider.h",
     "driver/sync_util.cc",
     "driver/sync_util.h",
-    "driver/ui_data_type_controller.cc",
-    "driver/ui_data_type_controller.h",
     "driver/user_selectable_sync_type.h",
     "engine/activation_context.cc",
     "engine/activation_context.h",
@@ -222,6 +214,8 @@
     "engine/events/protocol_event_observer.h",
     "engine/model_safe_worker.cc",
     "engine/model_safe_worker.h",
+    "engine/model_type_configurer.cc",
+    "engine/model_type_configurer.h",
     "engine/model_type_connector.cc",
     "engine/model_type_connector.h",
     "engine/model_type_processor.cc",
@@ -245,6 +239,10 @@
     "engine/sync_auth_provider.h",
     "engine/sync_encryption_handler.cc",
     "engine/sync_encryption_handler.h",
+    "engine/sync_engine.cc",
+    "engine/sync_engine.h",
+    "engine/sync_engine_host.cc",
+    "engine/sync_engine_host.h",
     "engine/sync_manager.cc",
     "engine/sync_manager.h",
     "engine/sync_manager_factory.cc",
@@ -798,14 +796,14 @@
     "driver/fake_sync_service.h",
     "driver/frontend_data_type_controller_mock.cc",
     "driver/frontend_data_type_controller_mock.h",
-    "driver/glue/sync_backend_host_mock.cc",
-    "driver/glue/sync_backend_host_mock.h",
     "driver/model_associator_mock.cc",
     "driver/model_associator_mock.h",
     "driver/non_ui_data_type_controller_mock.cc",
     "driver/non_ui_data_type_controller_mock.h",
     "driver/sync_api_component_factory_mock.cc",
     "driver/sync_api_component_factory_mock.h",
+    "engine/fake_sync_engine.cc",
+    "engine/fake_sync_engine.h",
     "model/change_processor_mock.cc",
     "model/change_processor_mock.h",
   ]
@@ -865,7 +863,6 @@
     "driver/startup_controller_unittest.cc",
     "driver/sync_stopped_reporter_unittest.cc",
     "driver/sync_util_unittest.cc",
-    "driver/ui_data_type_controller_unittest.cc",
     "engine/attachments/attachment_store_frontend_unittest.cc",
     "engine/attachments/attachment_store_test_template.h",
     "engine/attachments/fake_attachment_downloader_unittest.cc",
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index 6c25d1562..76d0c63b 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -20,7 +20,7 @@
 
 namespace syncer {
 
-class BackendDataTypeConfigurer;
+class ModelTypeConfigurer;
 class SyncError;
 class SyncMergeResult;
 
@@ -102,7 +102,7 @@
   // DataTypeManager before downloading initial data. Non-blocking types need to
   // pass activation context containing progress marker to sync backend before
   // initial download starts.
-  virtual void RegisterWithBackend(BackendDataTypeConfigurer* configurer) = 0;
+  virtual void RegisterWithBackend(ModelTypeConfigurer* configurer) = 0;
 
   // Will start a potentially asynchronous operation to perform the
   // model association. Once the model association is done the callback will
@@ -113,11 +113,11 @@
   // one of the implementation specific methods provided by the |configurer|.
   // This is called (on UI thread) after the data type configuration has
   // completed successfully.
-  virtual void ActivateDataType(BackendDataTypeConfigurer* configurer) = 0;
+  virtual void ActivateDataType(ModelTypeConfigurer* configurer) = 0;
 
   // Called by DataTypeManager to deactivate the controlled data type.
   // See comments for ModelAssociationManager::OnSingleDataTypeWillStop.
-  virtual void DeactivateDataType(BackendDataTypeConfigurer* configurer) = 0;
+  virtual void DeactivateDataType(ModelTypeConfigurer* configurer) = 0;
 
   // Synchronously stops the data type. If StartAssociating has already been
   // called but is not done yet it will be aborted. Similarly if LoadModels
diff --git a/components/sync/driver/data_type_manager_impl.cc b/components/sync/driver/data_type_manager_impl.cc
index c747405..a449da4 100644
--- a/components/sync/driver/data_type_manager_impl.cc
+++ b/components/sync/driver/data_type_manager_impl.cc
@@ -47,7 +47,7 @@
     const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
     const DataTypeController::TypeMap* controllers,
     const DataTypeEncryptionHandler* encryption_handler,
-    BackendDataTypeConfigurer* configurer,
+    ModelTypeConfigurer* configurer,
     DataTypeManagerObserver* observer)
     : configurer_(configurer),
       controllers_(controllers),
@@ -164,7 +164,7 @@
   }
 }
 
-BackendDataTypeConfigurer::DataTypeConfigStateMap
+ModelTypeConfigurer::DataTypeConfigStateMap
 DataTypeManagerImpl::BuildDataTypeConfigStateMap(
     const ModelTypeSet& types_being_configured) const {
   // 1. Get the failed types (due to fatal, crypto, and unready errors).
@@ -201,24 +201,22 @@
   DVLOG(1) << "Configuring: " << ModelTypeSetToString(to_configure);
   DVLOG(1) << "Disabling: " << ModelTypeSetToString(disabled_types);
 
-  BackendDataTypeConfigurer::DataTypeConfigStateMap config_state_map;
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::CONFIGURE_INACTIVE, enabled_types,
+  ModelTypeConfigurer::DataTypeConfigStateMap config_state_map;
+  ModelTypeConfigurer::SetDataTypesState(
+      ModelTypeConfigurer::CONFIGURE_INACTIVE, enabled_types,
       &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, to_configure,
-      &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::CONFIGURE_CLEAN, clean_types,
-      &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::DISABLED, disabled_types, &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(BackendDataTypeConfigurer::FATAL,
-                                               fatal_types, &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::CRYPTO, crypto_types, &config_state_map);
-  BackendDataTypeConfigurer::SetDataTypesState(
-      BackendDataTypeConfigurer::UNREADY, unready_types, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::CONFIGURE_ACTIVE,
+                                         to_configure, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::CONFIGURE_CLEAN,
+                                         clean_types, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::DISABLED,
+                                         disabled_types, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::FATAL,
+                                         fatal_types, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::CRYPTO,
+                                         crypto_types, &config_state_map);
+  ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::UNREADY,
+                                         unready_types, &config_state_map);
   return config_state_map;
 }
 
diff --git a/components/sync/driver/data_type_manager_impl.h b/components/sync/driver/data_type_manager_impl.h
index 7edd5696..73c0456 100644
--- a/components/sync/driver/data_type_manager_impl.h
+++ b/components/sync/driver/data_type_manager_impl.h
@@ -17,8 +17,8 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "components/sync/base/weak_handle.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
 #include "components/sync/driver/model_association_manager.h"
+#include "components/sync/engine/model_type_configurer.h"
 
 namespace syncer {
 
@@ -39,7 +39,7 @@
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
-      BackendDataTypeConfigurer* configurer,
+      ModelTypeConfigurer* configurer,
       DataTypeManagerObserver* observer);
   ~DataTypeManagerImpl() override;
 
@@ -122,7 +122,7 @@
   // Calls data type controllers of requested types to register with backend.
   void RegisterTypesWithBackend();
 
-  BackendDataTypeConfigurer::DataTypeConfigStateMap BuildDataTypeConfigStateMap(
+  ModelTypeConfigurer::DataTypeConfigStateMap BuildDataTypeConfigStateMap(
       const ModelTypeSet& types_being_configured) const;
 
   // Start download of next set of types in |download_types_queue_| (if
@@ -141,7 +141,7 @@
   // Returns the currently enabled types.
   ModelTypeSet GetEnabledTypes() const;
 
-  BackendDataTypeConfigurer* configurer_;
+  ModelTypeConfigurer* configurer_;
   // Map of all data type controllers that are available for sync.
   // This list is determined at startup by various command line flags.
   const DataTypeController::TypeMap* controllers_;
diff --git a/components/sync/driver/data_type_manager_impl_unittest.cc b/components/sync/driver/data_type_manager_impl_unittest.cc
index 8c2ca08..5e5ade9 100644
--- a/components/sync/driver/data_type_manager_impl_unittest.cc
+++ b/components/sync/driver/data_type_manager_impl_unittest.cc
@@ -60,12 +60,12 @@
   return status_table;
 }
 
-// Fake BackendDataTypeConfigurer implementation that simply stores away the
+// Fake ModelTypeConfigurer implementation that simply stores away the
 // callback passed into ConfigureDataTypes.
-class FakeBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
+class FakeModelTypeConfigurer : public ModelTypeConfigurer {
  public:
-  FakeBackendDataTypeConfigurer() : configure_call_count_(0) {}
-  ~FakeBackendDataTypeConfigurer() override {}
+  FakeModelTypeConfigurer() : configure_call_count_(0) {}
+  ~FakeModelTypeConfigurer() override {}
 
   ModelTypeSet ConfigureDataTypes(
       ConfigureReason reason,
@@ -218,7 +218,7 @@
  public:
   TestDataTypeManager(
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
-      BackendDataTypeConfigurer* configurer,
+      ModelTypeConfigurer* configurer,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
       DataTypeManagerObserver* observer)
@@ -331,7 +331,7 @@
 
   base::MessageLoopForUI ui_loop_;
   DataTypeController::TypeMap controllers_;
-  FakeBackendDataTypeConfigurer configurer_;
+  FakeModelTypeConfigurer configurer_;
   FakeDataTypeManagerObserver observer_;
   std::unique_ptr<TestDataTypeManager> dtm_;
   FakeDataTypeEncryptionHandler encryption_handler_;
@@ -962,14 +962,14 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // BOOKMARKS is configured after download of PREFERENCES finishes.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -994,13 +994,13 @@
 
   // Reconfigure while associating PREFERENCES and downloading BOOKMARKS.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1011,15 +1011,14 @@
   // Reconfiguration starts after downloading and association of previous
   // types finish.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
-      ModelTypeSet(BOOKMARKS, APPS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS, APPS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1045,14 +1044,14 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // BOOKMARKS is configured after download of PREFERENCES finishes.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1085,14 +1084,14 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // BOOKMARKS is configured after download of PREFERENCES finishes.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1111,7 +1110,7 @@
   // Finish association of PREFERENCES. This will trigger a reconfiguration to
   // disable bookmarks.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
@@ -1135,14 +1134,14 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // BOOKMARKS is configured after download of PREFERENCES finishes.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1160,10 +1159,10 @@
   // Reconfigure without PREFERENCES after the BOOKMARKS download completes,
   // then reconfigure with BOOKMARKS.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ControlTypes());
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ControlTypes());
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(), ModelTypeSet());
 
   // Reconfigure with BOOKMARKS.
@@ -1192,14 +1191,14 @@
 
   // Initially only PREFERENCES is configured.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   Configure(dtm_.get(), ModelTypeSet(BOOKMARKS, PREFERENCES));
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
   // BOOKMARKS is configured after download of PREFERENCES finishes.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet(BOOKMARKS));
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
 
@@ -1217,7 +1216,7 @@
   // Make BOOKMARKS association fail, which triggers reconfigure with only
   // PREFERENCES.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE,
+      ModelTypeConfigurer::CONFIGURE_ACTIVE,
       AddControlTypesTo(ModelTypeSet(PREFERENCES)));
   GetController(BOOKMARKS)->FinishStart(DataTypeController::ASSOCIATION_FAILED);
   EXPECT_EQ(DataTypeController::NOT_RUNNING, GetController(BOOKMARKS)->state());
@@ -1225,7 +1224,7 @@
 
   // Finish configuration with only PREFERENCES.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet());
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, ModelTypeSet());
   FinishDownload(*dtm_, ModelTypeSet(PREFERENCES), ModelTypeSet());
   EXPECT_EQ(DataTypeManager::CONFIGURED, dtm_->state());
   EXPECT_EQ(DataTypeController::RUNNING, GetController(PREFERENCES)->state());
@@ -1245,7 +1244,7 @@
   expected_types.Put(BOOKMARKS);
   // APPS is filtered out because there's no controller for it.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_ACTIVE, expected_types);
+      ModelTypeConfigurer::CONFIGURE_ACTIVE, expected_types);
   Configure(dtm_.get(), types);
   FinishDownload(*dtm_, ModelTypeSet(BOOKMARKS), ModelTypeSet());
   GetController(BOOKMARKS)->FinishStart(DataTypeController::OK);
@@ -1461,8 +1460,8 @@
             GetController(BOOKMARKS)->state());
 
   // Because Bookmarks are a ready type, once Preference finishes, Bookmarks
-  // can start associating immediately (even before the
-  // BackendDataTypeConfigurer calls back).
+  // can start associating immediately (even before the ModelTypeConfigurer
+  // calls back).
   GetController(PREFERENCES)->FinishStart(DataTypeController::OK);
   EXPECT_EQ(DataTypeController::ASSOCIATING, GetController(BOOKMARKS)->state());
 
@@ -1590,7 +1589,7 @@
   SetConfigureStartExpectation();
   SetConfigureDoneExpectation(DataTypeManager::OK, DataTypeStatusTable());
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_CLEAN,
+      ModelTypeConfigurer::CONFIGURE_CLEAN,
       AddControlTypesTo(ModelTypeSet(BOOKMARKS, PASSWORDS)));
 
   dtm_->Configure(ModelTypeSet(BOOKMARKS, PASSWORDS),
@@ -1625,7 +1624,7 @@
 
   // Configure (catch up) with one type.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_CLEAN,
+      ModelTypeConfigurer::CONFIGURE_CLEAN,
       AddControlTypesTo(ModelTypeSet(BOOKMARKS)));
   dtm_->Configure(ModelTypeSet(BOOKMARKS), CONFIGURE_REASON_CATCH_UP);
   EXPECT_EQ(DataTypeManager::CONFIGURING, dtm_->state());
@@ -1633,7 +1632,7 @@
   // Configure with both types before the first one completes. Both types should
   // end up in CONFIGURE_CLEAN.
   configurer_.set_expected_configure_types(
-      BackendDataTypeConfigurer::CONFIGURE_CLEAN,
+      ModelTypeConfigurer::CONFIGURE_CLEAN,
       AddControlTypesTo(ModelTypeSet(BOOKMARKS, PASSWORDS)));
   dtm_->Configure(ModelTypeSet(BOOKMARKS, PASSWORDS),
                   CONFIGURE_REASON_RECONFIGURATION);
diff --git a/components/sync/driver/directory_data_type_controller.cc b/components/sync/driver/directory_data_type_controller.cc
index cb75cd5..08fd79d5 100644
--- a/components/sync/driver/directory_data_type_controller.cc
+++ b/components/sync/driver/directory_data_type_controller.cc
@@ -9,8 +9,8 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
 #include "components/sync/driver/sync_service.h"
+#include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/syncable/syncable_read_transaction.h"
 #include "components/sync/syncable/user_share.h"
 
@@ -58,10 +58,10 @@
 }
 
 void DirectoryDataTypeController::RegisterWithBackend(
-    BackendDataTypeConfigurer* configurer) {}
+    ModelTypeConfigurer* configurer) {}
 
 void DirectoryDataTypeController::ActivateDataType(
-    BackendDataTypeConfigurer* configurer) {
+    ModelTypeConfigurer* configurer) {
   DCHECK(CalledOnValidThread());
   // Tell the backend about the change processor for this type so it can
   // begin routing changes to it.
@@ -70,7 +70,7 @@
 }
 
 void DirectoryDataTypeController::DeactivateDataType(
-    BackendDataTypeConfigurer* configurer) {
+    ModelTypeConfigurer* configurer) {
   DCHECK(CalledOnValidThread());
   configurer->DeactivateDirectoryDataType(type());
 }
diff --git a/components/sync/driver/directory_data_type_controller.h b/components/sync/driver/directory_data_type_controller.h
index 2b2051c1..48571e6 100644
--- a/components/sync/driver/directory_data_type_controller.h
+++ b/components/sync/driver/directory_data_type_controller.h
@@ -29,21 +29,21 @@
   // Directory based data types don't need to register with backend.
   // ModelTypeRegistry will create all necessary objects in
   // SetEnabledDirectoryTypes based on routing info.
-  void RegisterWithBackend(BackendDataTypeConfigurer* configurer) override;
+  void RegisterWithBackend(ModelTypeConfigurer* configurer) override;
 
   // Directory specific implementation of ActivateDataType with the
   // type specific ChangeProcessor and ModelSafeGroup.
   // Activates change processing on the controlled data type.
   // This is called by DataTypeManager, synchronously with data type's
   // model association.
-  // See BackendDataTypeConfigurer::ActivateDataType for more details.
-  void ActivateDataType(BackendDataTypeConfigurer* configurer) override;
+  // See ModelTypeConfigurer::ActivateDataType for more details.
+  void ActivateDataType(ModelTypeConfigurer* configurer) override;
 
   // Directory specific implementation of DeactivateDataType.
   // Deactivates change processing on the controlled data type (by removing
   // the data type's ChangeProcessor registration with the backend).
-  // See BackendDataTypeConfigurer::DeactivateDataType for more details.
-  void DeactivateDataType(BackendDataTypeConfigurer* configurer) override;
+  // See ModelTypeConfigurer::DeactivateDataType for more details.
+  void DeactivateDataType(ModelTypeConfigurer* configurer) override;
 
   // Returns a ListValue representing all nodes for a specified type by querying
   // the directory.
diff --git a/components/sync/driver/fake_data_type_controller.cc b/components/sync/driver/fake_data_type_controller.cc
index 2d23827..2587431b 100644
--- a/components/sync/driver/fake_data_type_controller.cc
+++ b/components/sync/driver/fake_data_type_controller.cc
@@ -53,7 +53,7 @@
 }
 
 void FakeDataTypeController::RegisterWithBackend(
-    BackendDataTypeConfigurer* configurer) {
+    ModelTypeConfigurer* configurer) {
   ++register_with_backend_call_count_;
 }
 
diff --git a/components/sync/driver/fake_data_type_controller.h b/components/sync/driver/fake_data_type_controller.h
index 5da38eb..509e6b3 100644
--- a/components/sync/driver/fake_data_type_controller.h
+++ b/components/sync/driver/fake_data_type_controller.h
@@ -30,7 +30,7 @@
   // DirectoryDataTypeController implementation.
   bool ShouldLoadModelBeforeConfigure() const override;
   void LoadModels(const ModelLoadCallback& model_load_callback) override;
-  void RegisterWithBackend(BackendDataTypeConfigurer* configurer) override;
+  void RegisterWithBackend(ModelTypeConfigurer* configurer) override;
   void StartAssociating(const StartCallback& start_callback) override;
   void Stop() override;
   std::string name() const override;
diff --git a/components/sync/driver/generic_change_processor_unittest.cc b/components/sync/driver/generic_change_processor_unittest.cc
index 96ddee1..dc3d1bd 100644
--- a/components/sync/driver/generic_change_processor_unittest.cc
+++ b/components/sync/driver/generic_change_processor_unittest.cc
@@ -73,15 +73,14 @@
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
-      SyncBackendHost* backend,
+      SyncEngine* backend,
       DataTypeManagerObserver* observer) override {
     return nullptr;
   };
-  SyncBackendHost* CreateSyncBackendHost(
-      const std::string& name,
-      invalidation::InvalidationService* invalidator,
-      const base::WeakPtr<SyncPrefs>& sync_prefs,
-      const base::FilePath& sync_folder) override {
+  SyncEngine* CreateSyncEngine(const std::string& name,
+                               invalidation::InvalidationService* invalidator,
+                               const base::WeakPtr<SyncPrefs>& sync_prefs,
+                               const base::FilePath& sync_folder) override {
     return nullptr;
   }
   std::unique_ptr<LocalDeviceInfoProvider> CreateLocalDeviceInfoProvider()
diff --git a/components/sync/driver/glue/sync_backend_host_core.h b/components/sync/driver/glue/sync_backend_host_core.h
index 81b60d9..bdec45a 100644
--- a/components/sync/driver/glue/sync_backend_host_core.h
+++ b/components/sync/driver/glue/sync_backend_host_core.h
@@ -83,7 +83,7 @@
 };
 
 // Helper struct to handle currying params to
-// SyncBackendHost::Core::DoConfigureSyncer.
+// SyncBackendHostCore::DoConfigureSyncer.
 struct DoConfigureSyncerTypes {
   DoConfigureSyncerTypes();
   DoConfigureSyncerTypes(const DoConfigureSyncerTypes& other);
@@ -156,17 +156,16 @@
 
   // Note:
   //
-  // The Do* methods are the various entry points from our
-  // SyncBackendHost.  They are all called on the sync thread to
-  // actually perform synchronous (and potentially blocking) syncapi
-  // operations.
+  // The Do* methods are the various entry points from our SyncBackendHostImpl.
+  // They are all called on the sync thread to actually perform synchronous (and
+  // potentially blocking) syncapi operations.
   //
   // Called to perform initialization of the syncapi on behalf of
-  // SyncBackendHost::Initialize.
+  // SyncEngine::Initialize.
   void DoInitialize(std::unique_ptr<DoInitializeOptions> options);
 
   // Called to perform credential update on behalf of
-  // SyncBackendHost::UpdateCredentials.
+  // SyncEngine::UpdateCredentials.
   void DoUpdateCredentials(const SyncCredentials& credentials);
 
   // Called to tell the syncapi to start syncing (generally after
@@ -189,7 +188,7 @@
   void DoRefreshTypes(ModelTypeSet types);
 
   // Invoked if we failed to download the necessary control types at startup.
-  // Invokes SyncBackendHost::HandleControlTypesDownloadRetry.
+  // Invokes SyncEngine::HandleControlTypesDownloadRetry.
   void OnControlTypesDownloadRetry();
 
   // Called to perform tasks which require the control data to be downloaded.
@@ -227,8 +226,8 @@
   void DisableProtocolEventForwarding();
 
   // Enables the forwarding of directory type debug counters to the
-  // SyncBackendHost.  Also requests that updates to all counters be
-  // emitted right away to initialize any new listeners' states.
+  // SyncEngineHost. Also requests that updates to all counters be emitted right
+  // away to initialize any new listeners' states.
   void EnableDirectoryTypeDebugInfoForwarding();
 
   // Disables forwarding of directory type debug counters.
@@ -275,7 +274,7 @@
   // Path of the folder that stores the sync data files.
   const base::FilePath sync_data_folder_path_;
 
-  // Our parent SyncBackendHost.
+  // Our parent SyncBackendHostImpl.
   WeakHandle<SyncBackendHostImpl> host_;
 
   // Our parent's registrar (not owned).  Non-null only between
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index 6f98bf6..b276ae2 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -23,12 +23,12 @@
 #include "components/sync/driver/glue/sync_backend_registrar.h"
 #include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_driver_switches.h"
-#include "components/sync/driver/sync_frontend.h"
 #include "components/sync/engine/activation_context.h"
 #include "components/sync/engine/engine_components_factory.h"
 #include "components/sync/engine/engine_components_factory_impl.h"
 #include "components/sync/engine/events/protocol_event.h"
 #include "components/sync/engine/net/http_bridge.h"
+#include "components/sync/engine/sync_engine_host.h"
 #include "components/sync/engine/sync_manager_factory.h"
 #include "components/sync/engine/sync_string_conversions.h"
 #include "components/sync/syncable/base_transaction.h"
@@ -50,24 +50,20 @@
     const base::FilePath& sync_folder)
     : sync_client_(sync_client),
       name_(name),
-      initialized_(false),
       sync_prefs_(sync_prefs),
-      frontend_(nullptr),
-      cached_passphrase_type_(PassphraseType::IMPLICIT_PASSPHRASE),
       invalidator_(invalidator),
-      invalidation_handler_registered_(false),
       weak_ptr_factory_(this) {
   core_ = new SyncBackendHostCore(name_, sync_folder,
                                   weak_ptr_factory_.GetWeakPtr());
 }
 
 SyncBackendHostImpl::~SyncBackendHostImpl() {
-  DCHECK(!core_.get() && !frontend_) << "Must call Shutdown before destructor.";
+  DCHECK(!core_.get() && !host_) << "Must call Shutdown before destructor.";
   DCHECK(!registrar_.get());
 }
 
 void SyncBackendHostImpl::Initialize(
-    SyncFrontend* frontend,
+    SyncEngineHost* host,
     scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
     const WeakHandle<JsEventHandler>& event_handler,
     const GURL& sync_service_url,
@@ -88,8 +84,8 @@
       name_, base::Bind(&SyncClient::CreateModelWorkerForGroup,
                         base::Unretained(sync_client_)));
 
-  DCHECK(frontend);
-  frontend_ = frontend;
+  DCHECK(host);
+  host_ = host;
 
   std::vector<scoped_refptr<ModelSafeWorker>> workers;
   registrar_->GetWorkers(&workers);
@@ -159,6 +155,8 @@
 
 void SyncBackendHostImpl::SetEncryptionPassphrase(const std::string& passphrase,
                                                   bool is_explicit) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   if (!IsNigoriEnabled()) {
     NOTREACHED() << "SetEncryptionPassphrase must never be called when nigori"
                     " is disabled.";
@@ -168,9 +166,6 @@
   // We should never be called with an empty passphrase.
   DCHECK(!passphrase.empty());
 
-  // This should only be called by the frontend.
-  DCHECK(thread_checker_.CalledOnValidThread());
-
   // SetEncryptionPassphrase should never be called if we are currently
   // encrypted with an explicit passphrase.
   DCHECK(cached_passphrase_type_ == PassphraseType::KEYSTORE_PASSPHRASE ||
@@ -184,6 +179,8 @@
 
 bool SyncBackendHostImpl::SetDecryptionPassphrase(
     const std::string& passphrase) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
   if (!IsNigoriEnabled()) {
     NOTREACHED() << "SetDecryptionPassphrase must never be called when nigori"
                     " is disabled.";
@@ -193,9 +190,6 @@
   // We should never be called with an empty passphrase.
   DCHECK(!passphrase.empty());
 
-  // This should only be called by the frontend.
-  DCHECK(thread_checker_.CalledOnValidThread());
-
   // This should only be called when we have cached pending keys.
   DCHECK(cached_pending_keys_.has_blob());
 
@@ -228,8 +222,8 @@
 
   // Stop getting messages from the sync thread.
   weak_ptr_factory_.InvalidateWeakPtrs();
-  // Immediately stop sending messages to the frontend.
-  frontend_ = nullptr;
+  // Immediately stop sending messages to the host.
+  host_ = nullptr;
 
   registrar_->RequestWorkerStopOnUIThread();
 
@@ -237,9 +231,9 @@
 }
 
 void SyncBackendHostImpl::Shutdown(ShutdownReason reason) {
-  // StopSyncingForShutdown() (which nulls out |frontend_|) should be
+  // StopSyncingForShutdown() (which nulls out |host_|) should be
   // called first.
-  DCHECK(!frontend_);
+  DCHECK(!host_);
 
   if (invalidation_handler_registered_) {
     if (reason == DISABLE_SYNC) {
@@ -541,7 +535,7 @@
   CHECK(initialized());
   Experiments experiments;
   if (core_->sync_manager()->ReceivedExperiment(&experiments))
-    frontend_->OnExperimentsChanged(experiments);
+    host_->OnExperimentsChanged(experiments);
 }
 
 void SyncBackendHostImpl::HandleInitializationSuccessOnFrontendLoop(
@@ -566,17 +560,17 @@
 
   // Now that we've downloaded the control types, we can see if there are any
   // experimental types to enable. This should be done before we inform
-  // the frontend to ensure they're visible in the customize screen.
+  // the host to ensure they're visible in the customize screen.
   AddExperimentalTypes();
-  frontend_->OnBackendInitialized(js_backend, debug_info_listener, cache_guid,
-                                  true);
+  host_->OnBackendInitialized(js_backend, debug_info_listener, cache_guid,
+                              true);
 }
 
 void SyncBackendHostImpl::HandleInitializationFailureOnFrontendLoop() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnBackendInitialized(WeakHandle<JsBackend>(),
-                                  WeakHandle<DataTypeDebugInfoListener>(), "",
-                                  false);
+  host_->OnBackendInitialized(WeakHandle<JsBackend>(),
+                              WeakHandle<DataTypeDebugInfoListener>(), "",
+                              false);
 }
 
 void SyncBackendHostImpl::HandleSyncCycleCompletedOnFrontendLoop(
@@ -596,7 +590,7 @@
     AddExperimentalTypes();
 
   if (initialized())
-    frontend_->OnSyncCycleCompleted();
+    host_->OnSyncCycleCompleted();
 }
 
 void SyncBackendHostImpl::RetryConfigurationOnFrontendLoop(
@@ -618,13 +612,13 @@
 void SyncBackendHostImpl::HandleActionableErrorEventOnFrontendLoop(
     const SyncProtocolError& sync_error) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnActionableError(sync_error);
+  host_->OnActionableError(sync_error);
 }
 
 void SyncBackendHostImpl::HandleMigrationRequestedOnFrontendLoop(
     ModelTypeSet types) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnMigrationNeededForTypes(types);
+  host_->OnMigrationNeededForTypes(types);
 }
 
 void SyncBackendHostImpl::OnInvalidatorStateChange(InvalidatorState state) {
@@ -664,26 +658,26 @@
   // Update our cache of the cryptographer's pending keys.
   cached_pending_keys_ = pending_keys;
 
-  frontend_->OnPassphraseRequired(reason, pending_keys);
+  host_->OnPassphraseRequired(reason, pending_keys);
 }
 
 void SyncBackendHostImpl::NotifyPassphraseAccepted() {
   DCHECK(thread_checker_.CalledOnValidThread());
   // Clear our cache of the cryptographer's pending keys.
   cached_pending_keys_.clear_blob();
-  frontend_->OnPassphraseAccepted();
+  host_->OnPassphraseAccepted();
 }
 
 void SyncBackendHostImpl::NotifyEncryptedTypesChanged(
     ModelTypeSet encrypted_types,
     bool encrypt_everything) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnEncryptedTypesChanged(encrypted_types, encrypt_everything);
+  host_->OnEncryptedTypesChanged(encrypted_types, encrypt_everything);
 }
 
 void SyncBackendHostImpl::NotifyEncryptionComplete() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnEncryptionComplete();
+  host_->OnEncryptionComplete();
 }
 
 void SyncBackendHostImpl::HandlePassphraseTypeChangedOnFrontendLoop(
@@ -698,42 +692,46 @@
 void SyncBackendHostImpl::HandleLocalSetPassphraseEncryptionOnFrontendLoop(
     const SyncEncryptionHandler::NigoriState& nigori_state) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  frontend_->OnLocalSetPassphraseEncryption(nigori_state);
+  host_->OnLocalSetPassphraseEncryption(nigori_state);
 }
 
 void SyncBackendHostImpl::HandleConnectionStatusChangeOnFrontendLoop(
     ConnectionStatus status) {
   DCHECK(thread_checker_.CalledOnValidThread());
-
   DVLOG(1) << "Connection status changed: " << ConnectionStatusToString(status);
-  frontend_->OnConnectionStatusChange(status);
+  host_->OnConnectionStatusChange(status);
 }
 
 void SyncBackendHostImpl::HandleProtocolEventOnFrontendLoop(
     std::unique_ptr<ProtocolEvent> event) {
-  frontend_->OnProtocolEvent(*event);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  host_->OnProtocolEvent(*event);
 }
 
 void SyncBackendHostImpl::HandleDirectoryCommitCountersUpdatedOnFrontendLoop(
     ModelType type,
     const CommitCounters& counters) {
-  frontend_->OnDirectoryTypeCommitCounterUpdated(type, counters);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  host_->OnDirectoryTypeCommitCounterUpdated(type, counters);
 }
 
 void SyncBackendHostImpl::HandleDirectoryUpdateCountersUpdatedOnFrontendLoop(
     ModelType type,
     const UpdateCounters& counters) {
-  frontend_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  host_->OnDirectoryTypeUpdateCounterUpdated(type, counters);
 }
 
 void SyncBackendHostImpl::HandleDirectoryStatusCountersUpdatedOnFrontendLoop(
     ModelType type,
     const StatusCounters& counters) {
-  frontend_->OnDatatypeStatusCounterUpdated(type, counters);
+  DCHECK(thread_checker_.CalledOnValidThread());
+  host_->OnDatatypeStatusCounterUpdated(type, counters);
 }
 
 void SyncBackendHostImpl::UpdateInvalidationVersions(
     const std::map<ModelType, int64_t>& invalidation_versions) {
+  DCHECK(thread_checker_.CalledOnValidThread());
   sync_prefs_->UpdateInvalidationVersions(invalidation_versions);
 }
 
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h
index 59fa562..0f57a602 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.h
+++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -17,17 +17,16 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
 #include "components/invalidation/public/invalidation_handler.h"
 #include "components/sync/base/extensions_activity.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/weak_handle.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
-#include "components/sync/driver/glue/sync_backend_host.h"
 #include "components/sync/engine/configure_reason.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
 #include "components/sync/engine/cycle/type_debug_info_observer.h"
+#include "components/sync/engine/model_type_configurer.h"
+#include "components/sync/engine/sync_engine.h"
 #include "components/sync/engine/sync_manager.h"
 #include "components/sync/protocol/encryption.pb.h"
 #include "components/sync/protocol/sync_protocol_error.h"
@@ -49,16 +48,12 @@
 class UnrecoverableErrorHandler;
 struct DoInitializeOptions;
 
-// The only real implementation of the SyncBackendHost.  See that interface's
+// The only real implementation of the SyncEngine. See that interface's
 // definition for documentation of public methods.
-class SyncBackendHostImpl : public SyncBackendHost, public InvalidationHandler {
+class SyncBackendHostImpl : public SyncEngine, public InvalidationHandler {
  public:
   typedef SyncStatus Status;
 
-  // Create a SyncBackendHost with a reference to the |frontend| that
-  // it serves and communicates to via the SyncFrontend interface (on
-  // the same thread it used to call the constructor).  Must outlive
-  // |sync_prefs|.
   SyncBackendHostImpl(
       const std::string& name,
       SyncClient* sync_client,
@@ -67,9 +62,9 @@
       const base::FilePath& sync_folder);
   ~SyncBackendHostImpl() override;
 
-  // SyncBackendHost implementation.
+  // SyncEngine implementation.
   void Initialize(
-      SyncFrontend* frontend,
+      SyncEngineHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
       const WeakHandle<JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -170,9 +165,9 @@
       std::unique_ptr<ModelTypeConnector> model_type_connector,
       const std::string& cache_guid);
 
-  // Forwards a ProtocolEvent to the frontend.  Will not be called unless a
-  // call to SetForwardProtocolEvents() explicitly requested that we start
-  // forwarding these events.
+  // Forwards a ProtocolEvent to the host. Will not be called unless a call to
+  // SetForwardProtocolEvents() explicitly requested that we start forwarding
+  // these events.
   void HandleProtocolEventOnFrontendLoop(std::unique_ptr<ProtocolEvent> event);
 
   // Forwards a directory commit counter update to the frontend loop.  Will not
@@ -201,7 +196,7 @@
   void UpdateInvalidationVersions(
       const std::map<ModelType, int64_t>& invalidation_versions);
 
-  SyncFrontend* frontend() { return frontend_; }
+  SyncEngineHost* host() { return host_; }
 
  private:
   friend class SyncBackendHostCore;
@@ -304,14 +299,15 @@
   // object is owned because in production code it is a proxy object.
   std::unique_ptr<ModelTypeConnector> model_type_connector_;
 
-  bool initialized_;
+  bool initialized_ = false;
 
   const base::WeakPtr<SyncPrefs> sync_prefs_;
 
   std::unique_ptr<SyncBackendRegistrar> registrar_;
 
-  // The frontend which we serve (and are owned by).
-  SyncFrontend* frontend_;
+  // The host which we serve (and are owned by). Set in Initialize() and nulled
+  // out in StopSyncingForShutdown().
+  SyncEngineHost* host_ = nullptr;
 
   // We cache the cryptographer's pending keys whenever NotifyPassphraseRequired
   // is called. This way, before the UI calls SetDecryptionPassphrase on the
@@ -327,7 +323,7 @@
   // in the nigori node. Updated whenever a new nigori node arrives or the user
   // manually changes their passphrase state. Cached so we can synchronously
   // check it from the UI thread.
-  PassphraseType cached_passphrase_type_;
+  PassphraseType cached_passphrase_type_ = PassphraseType::IMPLICIT_PASSPHRASE;
 
   // If an explicit passphrase is in use, the time at which the passphrase was
   // first set (if available).
@@ -337,7 +333,7 @@
   SyncCycleSnapshot last_snapshot_;
 
   invalidation::InvalidationService* invalidator_;
-  bool invalidation_handler_registered_;
+  bool invalidation_handler_registered_ = false;
 
   // Checks that we're on the same thread this was constructed on (UI thread).
   base::ThreadChecker thread_checker_;
diff --git a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
index 36469d20..9572893 100644
--- a/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "components/invalidation/impl/invalidator_storage.h"
@@ -26,7 +27,6 @@
 #include "components/sync/base/test_unrecoverable_error_handler.h"
 #include "components/sync/device_info/device_info.h"
 #include "components/sync/driver/fake_sync_client.h"
-#include "components/sync/driver/sync_frontend.h"
 #include "components/sync/engine/cycle/commit_counters.h"
 #include "components/sync/engine/cycle/status_counters.h"
 #include "components/sync/engine/cycle/update_counters.h"
@@ -35,6 +35,7 @@
 #include "components/sync/engine/net/http_bridge_network_resources.h"
 #include "components/sync/engine/net/network_resources.h"
 #include "components/sync/engine/passive_model_worker.h"
+#include "components/sync/engine/sync_engine_host.h"
 #include "components/sync/engine/sync_manager_factory.h"
 #include "components/sync/test/callback_counter.h"
 #include "components/sync_preferences/pref_service_syncable.h"
@@ -70,9 +71,9 @@
   base::MessageLoop::current()->QuitWhenIdle();
 }
 
-class MockSyncFrontend : public SyncFrontend {
+class MockSyncEngineHost : public SyncEngineHost {
  public:
-  virtual ~MockSyncFrontend() {}
+  virtual ~MockSyncEngineHost() {}
 
   MOCK_METHOD4(OnBackendInitialized,
                void(const WeakHandle<JsBackend>&,
@@ -152,12 +153,12 @@
   }
 };
 
-class SyncBackendHostTest : public testing::Test {
+class SyncEngineTest : public testing::Test {
  protected:
-  SyncBackendHostTest()
+  SyncEngineTest()
       : sync_thread_("SyncThreadForTest"), fake_manager_(nullptr) {}
 
-  ~SyncBackendHostTest() override {}
+  ~SyncEngineTest() override {}
 
   void SetUp() override {
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
@@ -204,18 +205,17 @@
 
   // Synchronously initializes the backend.
   void InitializeBackend(bool expect_success) {
-    EXPECT_CALL(mock_frontend_, OnBackendInitialized(_, _, _, expect_success))
+    EXPECT_CALL(mock_host_, OnBackendInitialized(_, _, _, expect_success))
         .WillOnce(InvokeWithoutArgs(QuitMessageLoop));
-    SyncBackendHost::HttpPostProviderFactoryGetter
+    SyncEngine::HttpPostProviderFactoryGetter
         http_post_provider_factory_getter =
             base::Bind(&NetworkResources::GetHttpPostProviderFactory,
                        base::Unretained(network_resources_.get()), nullptr,
                        base::Bind(&EmptyNetworkTimeUpdate));
     backend_->Initialize(
-        &mock_frontend_, sync_thread_.task_runner(),
-        WeakHandle<JsEventHandler>(), GURL(std::string()), std::string(),
-        credentials_, true, false, base::FilePath(),
-        std::move(fake_manager_factory_),
+        &mock_host_, sync_thread_.task_runner(), WeakHandle<JsEventHandler>(),
+        GURL(std::string()), std::string(), credentials_, true, false,
+        base::FilePath(), std::move(fake_manager_factory_),
         MakeWeakHandle(test_unrecoverable_error_handler_.GetWeakPtr()),
         base::Closure(), http_post_provider_factory_getter,
         std::move(saved_nigori_state_));
@@ -233,23 +233,19 @@
   ModelTypeSet ConfigureDataTypes(ModelTypeSet types_to_add,
                                   ModelTypeSet types_to_remove,
                                   ModelTypeSet types_to_unapply) {
-    BackendDataTypeConfigurer::DataTypeConfigStateMap config_state_map;
-    BackendDataTypeConfigurer::SetDataTypesState(
-        BackendDataTypeConfigurer::CONFIGURE_ACTIVE, types_to_add,
-        &config_state_map);
-    BackendDataTypeConfigurer::SetDataTypesState(
-        BackendDataTypeConfigurer::DISABLED, types_to_remove,
-        &config_state_map);
-    BackendDataTypeConfigurer::SetDataTypesState(
-        BackendDataTypeConfigurer::UNREADY, types_to_unapply,
-        &config_state_map);
+    ModelTypeConfigurer::DataTypeConfigStateMap config_state_map;
+    ModelTypeConfigurer::SetDataTypesState(
+        ModelTypeConfigurer::CONFIGURE_ACTIVE, types_to_add, &config_state_map);
+    ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::DISABLED,
+                                           types_to_remove, &config_state_map);
+    ModelTypeConfigurer::SetDataTypesState(ModelTypeConfigurer::UNREADY,
+                                           types_to_unapply, &config_state_map);
 
     types_to_add.PutAll(ControlTypes());
     ModelTypeSet ready_types = backend_->ConfigureDataTypes(
         CONFIGURE_REASON_RECONFIGURATION, config_state_map,
-        base::Bind(&SyncBackendHostTest::DownloadReady, base::Unretained(this)),
-        base::Bind(&SyncBackendHostTest::OnDownloadRetry,
-                   base::Unretained(this)));
+        base::Bind(&SyncEngineTest::DownloadReady, base::Unretained(this)),
+        base::Bind(&SyncEngineTest::OnDownloadRetry, base::Unretained(this)));
     base::RunLoop run_loop;
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE, run_loop.QuitClosure(), TestTimeouts::action_timeout());
@@ -268,7 +264,7 @@
   base::ScopedTempDir temp_dir_;
   sync_preferences::TestingPrefServiceSyncable pref_service_;
   base::Thread sync_thread_;
-  StrictMock<MockSyncFrontend> mock_frontend_;
+  StrictMock<MockSyncEngineHost> mock_host_;
   SyncCredentials credentials_;
   BackendSyncClient sync_client_;
   TestUnrecoverableErrorHandler test_unrecoverable_error_handler_;
@@ -283,7 +279,7 @@
 
 // Test basic initialization with no initial types (first time initialization).
 // Only the nigori should be configured.
-TEST_F(SyncBackendHostTest, InitShutdown) {
+TEST_F(SyncEngineTest, InitShutdown) {
   InitializeBackend(true);
   EXPECT_EQ(ControlTypes(), fake_manager_->GetAndResetDownloadedTypes());
   EXPECT_EQ(ControlTypes(), fake_manager_->InitialSyncEndedTypes());
@@ -294,7 +290,7 @@
 
 // Test first time sync scenario. All types should be properly configured.
 
-TEST_F(SyncBackendHostTest, FirstTimeSync) {
+TEST_F(SyncEngineTest, FirstTimeSync) {
   InitializeBackend(true);
   EXPECT_EQ(ControlTypes(), fake_manager_->GetAndResetDownloadedTypes());
   EXPECT_EQ(ControlTypes(), fake_manager_->InitialSyncEndedTypes());
@@ -318,7 +314,7 @@
 
 // Test the restart after setting up sync scenario. No enabled types should be
 // downloaded or cleaned.
-TEST_F(SyncBackendHostTest, Restart) {
+TEST_F(SyncEngineTest, Restart) {
   sync_prefs_->SetFirstSetupComplete();
   ModelTypeSet all_but_nigori = enabled_types_;
   fake_manager_factory_->set_progress_marker_types(enabled_types_);
@@ -350,7 +346,7 @@
 
 // Test a sync restart scenario where some types had never finished configuring.
 // The partial types should be purged, then reconfigured properly.
-TEST_F(SyncBackendHostTest, PartialTypes) {
+TEST_F(SyncEngineTest, PartialTypes) {
   sync_prefs_->SetFirstSetupComplete();
   // Set sync manager behavior before passing it down. All types have progress
   // markers, but nigori and bookmarks are missing initial sync ended.
@@ -388,7 +384,7 @@
 
 // Test the behavior when we lose the sync db. Although we already have types
 // enabled, we should re-download all of them because we lost their data.
-TEST_F(SyncBackendHostTest, LostDB) {
+TEST_F(SyncEngineTest, LostDB) {
   sync_prefs_->SetFirstSetupComplete();
   // Initialization should fetch the Nigori node.  Everything else should be
   // left untouched.
@@ -423,7 +419,7 @@
           .Empty());
 }
 
-TEST_F(SyncBackendHostTest, DisableTypes) {
+TEST_F(SyncEngineTest, DisableTypes) {
   // Simulate first time sync.
   InitializeBackend(true);
   fake_manager_->GetAndResetCleanedTypes();
@@ -462,7 +458,7 @@
           .Empty());
 }
 
-TEST_F(SyncBackendHostTest, AddTypes) {
+TEST_F(SyncEngineTest, AddTypes) {
   // Simulate first time sync.
   InitializeBackend(true);
   fake_manager_->GetAndResetCleanedTypes();
@@ -503,7 +499,7 @@
 }
 
 // And and disable in the same configuration.
-TEST_F(SyncBackendHostTest, AddDisableTypes) {
+TEST_F(SyncEngineTest, AddDisableTypes) {
   // Simulate first time sync.
   InitializeBackend(true);
   fake_manager_->GetAndResetCleanedTypes();
@@ -546,7 +542,7 @@
 
 // Test restarting the browser to newly supported datatypes. The new datatypes
 // should be downloaded on the configuration after backend initialization.
-TEST_F(SyncBackendHostTest, NewlySupportedTypes) {
+TEST_F(SyncEngineTest, NewlySupportedTypes) {
   sync_prefs_->SetFirstSetupComplete();
   // Set sync manager behavior before passing it down. All types have progress
   // markers and initial sync ended except the new types.
@@ -586,7 +582,7 @@
 // Test the newly supported types scenario, but with the presence of partial
 // types as well. Both partial and newly supported types should be downloaded
 // the configuration.
-TEST_F(SyncBackendHostTest, NewlySupportedTypesWithPartialTypes) {
+TEST_F(SyncEngineTest, NewlySupportedTypesWithPartialTypes) {
   sync_prefs_->SetFirstSetupComplete();
   // Set sync manager behavior before passing it down. All types have progress
   // markers and initial sync ended except the new types.
@@ -629,7 +625,7 @@
 
 // Verify that downloading control types only downloads those types that do
 // not have initial sync ended set.
-TEST_F(SyncBackendHostTest, DownloadControlTypes) {
+TEST_F(SyncEngineTest, DownloadControlTypes) {
   sync_prefs_->SetFirstSetupComplete();
   // Set sync manager behavior before passing it down. Experiments and device
   // info are new types without progress markers or initial sync ended, while
@@ -658,13 +654,13 @@
 // The failure is "silent" in the sense that the GetUpdates request appears to
 // be successful, but it returned no results.  This means that the usual
 // download retry logic will not be invoked.
-TEST_F(SyncBackendHostTest, SilentlyFailToDownloadControlTypes) {
+TEST_F(SyncEngineTest, SilentlyFailToDownloadControlTypes) {
   fake_manager_factory_->set_configure_fail_types(ModelTypeSet::All());
   InitializeBackend(false);
 }
 
 // Test that local refresh requests are delivered to sync.
-TEST_F(SyncBackendHostTest, ForwardLocalRefreshRequest) {
+TEST_F(SyncEngineTest, ForwardLocalRefreshRequest) {
   InitializeBackend(true);
 
   ModelTypeSet set1 = ModelTypeSet::All();
@@ -679,14 +675,14 @@
 }
 
 // Test that configuration on signin sends the proper GU source.
-TEST_F(SyncBackendHostTest, DownloadControlTypesNewClient) {
+TEST_F(SyncEngineTest, DownloadControlTypesNewClient) {
   InitializeBackend(true);
   EXPECT_EQ(CONFIGURE_REASON_NEW_CLIENT,
             fake_manager_->GetAndResetConfigureReason());
 }
 
 // Test that configuration on restart sends the proper GU source.
-TEST_F(SyncBackendHostTest, DownloadControlTypesRestart) {
+TEST_F(SyncEngineTest, DownloadControlTypesRestart) {
   sync_prefs_->SetFirstSetupComplete();
   fake_manager_factory_->set_progress_marker_types(enabled_types_);
   fake_manager_factory_->set_initial_sync_ended_types(enabled_types_);
@@ -697,7 +693,7 @@
 
 // It is SyncBackendHostCore responsibility to cleanup Sync Data folder if sync
 // setup hasn't been completed. This test ensures that cleanup happens.
-TEST_F(SyncBackendHostTest, TestStartupWithOldSyncData) {
+TEST_F(SyncEngineTest, TestStartupWithOldSyncData) {
   const char* nonsense = "slon";
   base::FilePath temp_directory =
       temp_dir_.GetPath().Append(base::FilePath(kTestSyncDir));
@@ -712,9 +708,9 @@
 
 // If bookmarks encounter an error that results in disabling without purging
 // (such as when the type is unready), and then is explicitly disabled, the
-// SyncBackendHost needs to tell the manager to purge the type, even though
+// SyncEngine needs to tell the manager to purge the type, even though
 // it's already disabled (crbug.com/386778).
-TEST_F(SyncBackendHostTest, DisableThenPurgeType) {
+TEST_F(SyncEngineTest, DisableThenPurgeType) {
   ModelTypeSet error_types(BOOKMARKS);
 
   InitializeBackend(true);
@@ -747,7 +743,7 @@
 
 // Test that a call to ClearServerData is forwarded to the underlying
 // SyncManager.
-TEST_F(SyncBackendHostTest, ClearServerDataCallsAreForwarded) {
+TEST_F(SyncEngineTest, ClearServerDataCallsAreForwarded) {
   InitializeBackend(true);
   CallbackCounter callback_counter;
   backend_->ClearServerData(base::Bind(&CallbackCounter::Callback,
@@ -758,7 +754,7 @@
 
 // Ensure that redundant invalidations are ignored and that the most recent
 // set of invalidation version is persisted across restarts.
-TEST_F(SyncBackendHostTest, IgnoreOldInvalidations) {
+TEST_F(SyncEngineTest, IgnoreOldInvalidations) {
   // Set up some old persisted invalidations.
   std::map<ModelType, int64_t> invalidation_versions;
   invalidation_versions[BOOKMARKS] = 20;
@@ -819,7 +815,7 @@
 // Tests that SyncBackendHostImpl retains ModelTypeConnector after call to
 // StopSyncingForShutdown. This is needed for datatype deactivation during
 // DataTypeManager shutdown.
-TEST_F(SyncBackendHostTest, ModelTypeConnectorValidDuringShutdown) {
+TEST_F(SyncEngineTest, ModelTypeConnectorValidDuringShutdown) {
   InitializeBackend(true);
   backend_->StopSyncingForShutdown();
   // Verify that call to DeactivateNonBlockingDataType doesn't assert.
diff --git a/components/sync/driver/glue/sync_backend_host_mock.cc b/components/sync/driver/glue/sync_backend_host_mock.cc
deleted file mode 100644
index 3edb4f8..0000000
--- a/components/sync/driver/glue/sync_backend_host_mock.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/driver/glue/sync_backend_host_mock.h"
-
-#include "components/sync/driver/sync_frontend.h"
-#include "components/sync/engine/activation_context.h"
-
-namespace syncer {
-
-const char kTestCacheGuid[] = "test-guid";
-
-SyncBackendHostMock::SyncBackendHostMock() : fail_initial_download_(false) {}
-SyncBackendHostMock::~SyncBackendHostMock() {}
-
-void SyncBackendHostMock::Initialize(
-    SyncFrontend* frontend,
-    scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
-    const WeakHandle<JsEventHandler>& event_handler,
-    const GURL& service_url,
-    const std::string& sync_user_agent,
-    const SyncCredentials& credentials,
-    bool delete_sync_data_folder,
-    bool enable_local_sync_backend,
-    const base::FilePath& local_sync_backend_folder,
-    std::unique_ptr<SyncManagerFactory> sync_manager_factory,
-    const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler,
-    const base::Closure& report_unrecoverable_error_function,
-    const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
-    std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) {
-  frontend->OnBackendInitialized(WeakHandle<JsBackend>(),
-                                 WeakHandle<DataTypeDebugInfoListener>(),
-                                 kTestCacheGuid, !fail_initial_download_);
-}
-
-void SyncBackendHostMock::TriggerRefresh(const ModelTypeSet& types) {}
-
-void SyncBackendHostMock::UpdateCredentials(
-    const SyncCredentials& credentials) {}
-
-void SyncBackendHostMock::StartSyncingWithServer() {}
-
-void SyncBackendHostMock::SetEncryptionPassphrase(const std::string& passphrase,
-                                                  bool is_explicit) {}
-
-bool SyncBackendHostMock::SetDecryptionPassphrase(
-    const std::string& passphrase) {
-  return false;
-}
-
-void SyncBackendHostMock::StopSyncingForShutdown() {}
-
-void SyncBackendHostMock::Shutdown(ShutdownReason reason) {}
-
-void SyncBackendHostMock::UnregisterInvalidationIds() {}
-
-ModelTypeSet SyncBackendHostMock::ConfigureDataTypes(
-    ConfigureReason reason,
-    const DataTypeConfigStateMap& config_state_map,
-    const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
-    const base::Callback<void()>& retry_callback) {
-  return ModelTypeSet();
-}
-
-void SyncBackendHostMock::EnableEncryptEverything() {}
-
-void SyncBackendHostMock::ActivateDirectoryDataType(
-    ModelType type,
-    ModelSafeGroup group,
-    ChangeProcessor* change_processor) {}
-void SyncBackendHostMock::DeactivateDirectoryDataType(ModelType type) {}
-
-void SyncBackendHostMock::ActivateNonBlockingDataType(
-    ModelType type,
-    std::unique_ptr<ActivationContext> activation_context) {}
-
-void SyncBackendHostMock::DeactivateNonBlockingDataType(ModelType type) {}
-
-UserShare* SyncBackendHostMock::GetUserShare() const {
-  return nullptr;
-}
-
-SyncBackendHost::Status SyncBackendHostMock::GetDetailedStatus() {
-  return SyncBackendHost::Status();
-}
-
-SyncCycleSnapshot SyncBackendHostMock::GetLastCycleSnapshot() const {
-  return SyncCycleSnapshot();
-}
-
-bool SyncBackendHostMock::HasUnsyncedItems() const {
-  return false;
-}
-
-bool SyncBackendHostMock::IsNigoriEnabled() const {
-  return true;
-}
-
-PassphraseType SyncBackendHostMock::GetPassphraseType() const {
-  return PassphraseType::IMPLICIT_PASSPHRASE;
-}
-
-base::Time SyncBackendHostMock::GetExplicitPassphraseTime() const {
-  return base::Time();
-}
-
-bool SyncBackendHostMock::IsCryptographerReady(
-    const BaseTransaction* trans) const {
-  return false;
-}
-
-void SyncBackendHostMock::GetModelSafeRoutingInfo(
-    ModelSafeRoutingInfo* out) const {}
-
-void SyncBackendHostMock::FlushDirectory() const {}
-
-void SyncBackendHostMock::RefreshTypesForTest(ModelTypeSet types) {}
-
-void SyncBackendHostMock::RequestBufferedProtocolEventsAndEnableForwarding() {}
-
-void SyncBackendHostMock::DisableProtocolEventForwarding() {}
-
-void SyncBackendHostMock::EnableDirectoryTypeDebugInfoForwarding() {}
-
-void SyncBackendHostMock::DisableDirectoryTypeDebugInfoForwarding() {}
-
-void SyncBackendHostMock::set_fail_initial_download(bool should_fail) {
-  fail_initial_download_ = should_fail;
-}
-
-void SyncBackendHostMock::ClearServerData(
-    const SyncManager::ClearServerDataCallback& callback) {
-  callback.Run();
-}
-
-void SyncBackendHostMock::OnCookieJarChanged(bool account_mismatch,
-                                             bool empty_jar) {}
-
-}  // namespace syncer
diff --git a/components/sync/driver/model_association_manager.h b/components/sync/driver/model_association_manager.h
index 40d9bba3..2f8bd9d 100644
--- a/components/sync/driver/model_association_manager.h
+++ b/components/sync/driver/model_association_manager.h
@@ -29,7 +29,7 @@
 class ModelAssociationManagerDelegate {
  public:
   // Called when all desired types are ready to be configured with
-  // BackendDataTypeConfigurer. Data type is ready when its progress marker is
+  // ModelTypeConfigurer. Data type is ready when its progress marker is
   // available to configurer. Directory data types are always ready, their
   // progress markers are read from directory. USS data type controllers need to
   // load model and read data type context first.
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index 7b506b8..9dbe973 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -14,9 +14,9 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/base/data_type_histogram.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
 #include "components/sync/driver/sync_client.h"
 #include "components/sync/engine/activation_context.h"
+#include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/model/data_type_error_handler_impl.h"
 #include "components/sync/model/model_type_change_processor.h"
 #include "components/sync/model/model_type_debug_info.h"
@@ -159,8 +159,7 @@
   LoadModelsDone(result, error);
 }
 
-void ModelTypeController::RegisterWithBackend(
-    BackendDataTypeConfigurer* configurer) {
+void ModelTypeController::RegisterWithBackend(ModelTypeConfigurer* configurer) {
   DCHECK(CalledOnValidThread());
   if (activated_)
     return;
@@ -185,8 +184,7 @@
   start_callback.Run(OK, merge_result, merge_result);
 }
 
-void ModelTypeController::ActivateDataType(
-    BackendDataTypeConfigurer* configurer) {
+void ModelTypeController::ActivateDataType(ModelTypeConfigurer* configurer) {
   DCHECK(CalledOnValidThread());
   DCHECK(configurer);
   DCHECK_EQ(RUNNING, state_);
@@ -196,8 +194,7 @@
   DCHECK(!activation_context_);
 }
 
-void ModelTypeController::DeactivateDataType(
-    BackendDataTypeConfigurer* configurer) {
+void ModelTypeController::DeactivateDataType(ModelTypeConfigurer* configurer) {
   DCHECK(CalledOnValidThread());
   DCHECK(configurer);
   if (activated_) {
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index 6c83098..7efa58f 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -40,10 +40,10 @@
   // Registers non-blocking data type with sync backend. In the process the
   // activation context is passed to ModelTypeRegistry, where ModelTypeWorker
   // gets created and connected with ModelTypeProcessor.
-  void RegisterWithBackend(BackendDataTypeConfigurer* configurer) override;
+  void RegisterWithBackend(ModelTypeConfigurer* configurer) override;
   void StartAssociating(const StartCallback& start_callback) override;
-  void ActivateDataType(BackendDataTypeConfigurer* configurer) override;
-  void DeactivateDataType(BackendDataTypeConfigurer* configurer) override;
+  void ActivateDataType(ModelTypeConfigurer* configurer) override;
+  void DeactivateDataType(ModelTypeConfigurer* configurer) override;
   void Stop() override;
   std::string name() const override;
   State state() const override;
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index fd6bb59..c675192 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -18,11 +18,11 @@
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
 #include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/engine/activation_context.h"
 #include "components/sync/engine/commit_queue.h"
 #include "components/sync/engine/fake_model_type_processor.h"
+#include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
 #include "components/sync/model/fake_model_type_change_processor.h"
 #include "components/sync/model/stub_model_type_sync_bridge.h"
@@ -70,11 +70,11 @@
   DISALLOW_COPY_AND_ASSIGN(TestModelTypeProcessor);
 };
 
-// A BackendDataTypeConfigurer that just connects USS types.
-class TestBackendDataTypeConfigurer : public BackendDataTypeConfigurer {
+// A ModelTypeConfigurer that just connects USS types.
+class TestModelTypeConfigurer : public ModelTypeConfigurer {
  public:
-  TestBackendDataTypeConfigurer() {}
-  ~TestBackendDataTypeConfigurer() override {}
+  TestModelTypeConfigurer() {}
+  ~TestModelTypeConfigurer() override {}
 
   ModelTypeSet ConfigureDataTypes(
       ConfigureReason reason,
@@ -251,7 +251,7 @@
   base::MessageLoop message_loop_;
   base::Thread model_thread_;
   SyncPrefs sync_prefs_;
-  TestBackendDataTypeConfigurer configurer_;
+  TestModelTypeConfigurer configurer_;
   std::unique_ptr<StubModelTypeSyncBridge> bridge_;
   std::unique_ptr<ModelTypeController> controller_;
   TestModelTypeProcessor* processor_;
diff --git a/components/sync/driver/proxy_data_type_controller.cc b/components/sync/driver/proxy_data_type_controller.cc
index 36f27d9..d2ff0d7 100644
--- a/components/sync/driver/proxy_data_type_controller.cc
+++ b/components/sync/driver/proxy_data_type_controller.cc
@@ -29,7 +29,7 @@
 }
 
 void ProxyDataTypeController::RegisterWithBackend(
-    BackendDataTypeConfigurer* configurer) {}
+    ModelTypeConfigurer* configurer) {}
 
 void ProxyDataTypeController::StartAssociating(
     const StartCallback& start_callback) {
@@ -55,10 +55,10 @@
 }
 
 void ProxyDataTypeController::ActivateDataType(
-    BackendDataTypeConfigurer* configurer) {}
+    ModelTypeConfigurer* configurer) {}
 
 void ProxyDataTypeController::DeactivateDataType(
-    BackendDataTypeConfigurer* configurer) {}
+    ModelTypeConfigurer* configurer) {}
 
 void ProxyDataTypeController::GetAllNodes(const AllNodesCallback& callback) {
   callback.Run(type(), base::MakeUnique<base::ListValue>());
diff --git a/components/sync/driver/proxy_data_type_controller.h b/components/sync/driver/proxy_data_type_controller.h
index 1b51c6e..670a33f 100644
--- a/components/sync/driver/proxy_data_type_controller.h
+++ b/components/sync/driver/proxy_data_type_controller.h
@@ -24,13 +24,13 @@
   // DataTypeController interface.
   bool ShouldLoadModelBeforeConfigure() const override;
   void LoadModels(const ModelLoadCallback& model_load_callback) override;
-  void RegisterWithBackend(BackendDataTypeConfigurer* configurer) override;
+  void RegisterWithBackend(ModelTypeConfigurer* configurer) override;
   void StartAssociating(const StartCallback& start_callback) override;
   void Stop() override;
   std::string name() const override;
   State state() const override;
-  void ActivateDataType(BackendDataTypeConfigurer* configurer) override;
-  void DeactivateDataType(BackendDataTypeConfigurer* configurer) override;
+  void ActivateDataType(ModelTypeConfigurer* configurer) override;
+  void DeactivateDataType(ModelTypeConfigurer* configurer) override;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
 
diff --git a/components/sync/driver/shared_change_processor_unittest.cc b/components/sync/driver/shared_change_processor_unittest.cc
index 08db038..72f06592 100644
--- a/components/sync/driver/shared_change_processor_unittest.cc
+++ b/components/sync/driver/shared_change_processor_unittest.cc
@@ -47,15 +47,14 @@
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
-      SyncBackendHost* backend,
+      SyncEngine* engine,
       DataTypeManagerObserver* observer) override {
     return nullptr;
   }
-  SyncBackendHost* CreateSyncBackendHost(
-      const std::string& name,
-      invalidation::InvalidationService* invalidator,
-      const base::WeakPtr<SyncPrefs>& sync_prefs,
-      const base::FilePath& sync_folder) override {
+  SyncEngine* CreateSyncEngine(const std::string& name,
+                               invalidation::InvalidationService* invalidator,
+                               const base::WeakPtr<SyncPrefs>& sync_prefs,
+                               const base::FilePath& sync_folder) override {
     return nullptr;
   }
   std::unique_ptr<LocalDeviceInfoProvider> CreateLocalDeviceInfoProvider()
@@ -82,7 +81,7 @@
  public:
   SyncSharedChangeProcessorTest()
       : FakeSyncClient(&factory_),
-        backend_thread_("dbthread"),
+        model_thread_("dbthread"),
         did_connect_(false),
         has_attachment_service_(false) {}
 
@@ -100,15 +99,15 @@
   void SetUp() override {
     test_user_share_.SetUp();
     shared_change_processor_ = new SharedChangeProcessor(AUTOFILL);
-    ASSERT_TRUE(backend_thread_.Start());
-    ASSERT_TRUE(backend_thread_.task_runner()->PostTask(
+    ASSERT_TRUE(model_thread_.Start());
+    ASSERT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&SyncSharedChangeProcessorTest::SetUpDBSyncableService,
                    base::Unretained(this))));
   }
 
   void TearDown() override {
-    EXPECT_TRUE(backend_thread_.task_runner()->PostTask(
+    EXPECT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&SyncSharedChangeProcessorTest::TearDownDBSyncableService,
                    base::Unretained(this))));
@@ -119,26 +118,26 @@
     // TODO(akalin): Write deterministic tests for the destruction of
     // |shared_change_processor_| on the UI and DB threads.
     shared_change_processor_ = nullptr;
-    backend_thread_.Stop();
+    model_thread_.Stop();
 
     // Note: Stop() joins the threads, and that barrier prevents this read
     // from being moved (e.g by compiler optimization) in such a way that it
     // would race with the write in ConnectOnDBThread (because by this time,
-    // everything that could have run on |backend_thread_| has done so).
+    // everything that could have run on |model_thread_| has done so).
     ASSERT_TRUE(did_connect_);
     test_user_share_.TearDown();
   }
 
   // Connect |shared_change_processor_| on the DB thread.
   void Connect() {
-    EXPECT_TRUE(backend_thread_.task_runner()->PostTask(
+    EXPECT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&SyncSharedChangeProcessorTest::ConnectOnDBThread,
                    base::Unretained(this), shared_change_processor_)));
   }
 
   void SetAttachmentStore() {
-    EXPECT_TRUE(backend_thread_.task_runner()->PostTask(
+    EXPECT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&SyncSharedChangeProcessorTest::SetAttachmentStoreOnDBThread,
                    base::Unretained(this))));
@@ -147,7 +146,7 @@
   bool HasAttachmentService() {
     base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
                               base::WaitableEvent::InitialState::NOT_SIGNALED);
-    EXPECT_TRUE(backend_thread_.task_runner()->PostTask(
+    EXPECT_TRUE(model_thread_.task_runner()->PostTask(
         FROM_HERE,
         base::Bind(
             &SyncSharedChangeProcessorTest::CheckAttachmentServiceOnDBThread,
@@ -159,20 +158,20 @@
  private:
   // Used by SetUp().
   void SetUpDBSyncableService() {
-    DCHECK(backend_thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     DCHECK(!db_syncable_service_.get());
     db_syncable_service_ = base::MakeUnique<FakeSyncableService>();
   }
 
   // Used by TearDown().
   void TearDownDBSyncableService() {
-    DCHECK(backend_thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     DCHECK(db_syncable_service_.get());
     db_syncable_service_.reset();
   }
 
   void SetAttachmentStoreOnDBThread() {
-    DCHECK(backend_thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     DCHECK(db_syncable_service_.get());
     db_syncable_service_->set_attachment_store(
         AttachmentStore::CreateInMemoryStore());
@@ -183,7 +182,7 @@
   // (in TearDown()).
   void ConnectOnDBThread(
       const scoped_refptr<SharedChangeProcessor>& shared_change_processor) {
-    DCHECK(backend_thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     EXPECT_TRUE(shared_change_processor->Connect(
         this, &processor_factory_, test_user_share_.user_share(),
         base::MakeUnique<DataTypeErrorHandlerMock>(),
@@ -192,14 +191,14 @@
   }
 
   void CheckAttachmentServiceOnDBThread(base::WaitableEvent* event) {
-    DCHECK(backend_thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(model_thread_.task_runner()->BelongsToCurrentThread());
     DCHECK(db_syncable_service_.get());
     has_attachment_service_ = !!db_syncable_service_->attachment_service();
     event->Signal();
   }
 
   base::MessageLoop frontend_loop_;
-  base::Thread backend_thread_;
+  base::Thread model_thread_;
   TestUserShare test_user_share_;
   TestSyncApiComponentFactory factory_;
 
diff --git a/components/sync/driver/startup_controller.cc b/components/sync/driver/startup_controller.cc
index f7783ba5..6131e28 100644
--- a/components/sync/driver/startup_controller.cc
+++ b/components/sync/driver/startup_controller.cc
@@ -22,7 +22,7 @@
 const int kDeferredInitFallbackSeconds = 10;
 
 // Enum (for UMA, primarily) defining different events that cause us to
-// exit the "deferred" state of initialization and invoke start_backend.
+// exit the "deferred" state of initialization and invoke start_engine.
 enum DeferredInitTrigger {
   // We have received a signal from a SyncableService requesting that sync
   // starts as soon as possible.
@@ -36,13 +36,13 @@
 
 StartupController::StartupController(const SyncPrefs* sync_prefs,
                                      base::Callback<bool()> can_start,
-                                     base::Closure start_backend)
+                                     base::Closure start_engine)
     : bypass_setup_complete_(false),
       received_start_request_(false),
       setup_in_progress_(false),
       sync_prefs_(sync_prefs),
       can_start_(can_start),
-      start_backend_(start_backend),
+      start_engine_(start_engine),
       fallback_timeout_(
           base::TimeDelta::FromSeconds(kDeferredInitFallbackSeconds)),
       weak_factory_(this) {
@@ -67,7 +67,7 @@
   received_start_request_ = false;
   bypass_setup_complete_ = false;
   start_up_time_ = base::Time();
-  start_backend_time_ = base::Time();
+  start_engine_time_ = base::Time();
   // Don't let previous timers affect us post-reset.
   weak_factory_.InvalidateWeakPtrs();
   registered_types_ = registered_types;
@@ -85,7 +85,7 @@
   if (first_start)
     start_up_time_ = base::Time::Now();
 
-  if (deferred_option == STARTUP_BACKEND_DEFERRED &&
+  if (deferred_option == STARTUP_DEFERRED &&
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kSyncDisableDeferredStartup) &&
       sync_prefs_->GetPreferredDataTypes(registered_types_).Has(SESSIONS)) {
@@ -99,9 +99,9 @@
     return false;
   }
 
-  if (start_backend_time_.is_null()) {
-    start_backend_time_ = base::Time::Now();
-    start_backend_.Run();
+  if (start_engine_time_.is_null()) {
+    start_engine_time_ = base::Time::Now();
+    start_engine_.Run();
   }
 
   return true;
@@ -119,15 +119,15 @@
   // For performance reasons, defer the heavy lifting for sync init unless:
   //
   // - a datatype has requested an immediate start of sync, or
-  // - sync needs to start up the backend immediately to provide control state
+  // - sync needs to start up the engine immediately to provide control state
   //   and encryption information to the UI.
-  // Do not start up the sync backend if setup has not completed and isn't
+  // Do not start up the sync engine if setup has not completed and isn't
   // in progress, unless told to otherwise.
   if (setup_in_progress_) {
     return StartUp(STARTUP_IMMEDIATE);
   } else if (sync_prefs_->IsFirstSetupComplete() || bypass_setup_complete_) {
     return StartUp(received_start_request_ ? STARTUP_IMMEDIATE
-                                           : STARTUP_BACKEND_DEFERRED);
+                                           : STARTUP_DEFERRED);
   } else {
     return false;
   }
@@ -151,10 +151,10 @@
   DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kSyncDisableDeferredStartup));
 
-  if (!start_backend_time_.is_null())
+  if (!start_engine_time_.is_null())
     return;
 
-  DVLOG(2) << "Sync deferred init fallback timer expired, starting backend.";
+  DVLOG(2) << "Sync deferred init fallback timer expired, starting engine.";
   RecordTimeDeferred();
   UMA_HISTOGRAM_ENUMERATION("Sync.Startup.DeferredInitTrigger",
                             TRIGGER_FALLBACK_TIMER, MAX_TRIGGER_VALUE);
@@ -162,8 +162,8 @@
   TryStart();
 }
 
-std::string StartupController::GetBackendInitializationStateString() const {
-  if (!start_backend_time_.is_null())
+std::string StartupController::GetEngineInitializationStateString() const {
+  if (!start_engine_time_.is_null())
     return "Started";
   else if (!start_up_time_.is_null())
     return "Deferred";
@@ -179,7 +179,7 @@
     return;
   }
 
-  if (!start_backend_time_.is_null())
+  if (!start_engine_time_.is_null())
     return;
 
   DVLOG(2) << "Data type requesting sync startup: " << ModelTypeToString(type);
diff --git a/components/sync/driver/startup_controller.h b/components/sync/driver/startup_controller.h
index ceef627f..63c02785 100644
--- a/components/sync/driver/startup_controller.h
+++ b/components/sync/driver/startup_controller.h
@@ -17,18 +17,17 @@
 class SyncPrefs;
 
 // This class is used by ProfileSyncService to manage all logic and state
-// pertaining to initialization of the SyncBackendHost (colloquially referred
-// to as "the backend").
+// pertaining to initialization of the SyncEngine.
 class StartupController {
  public:
   StartupController(const SyncPrefs* sync_prefs,
                     base::Callback<bool()> can_start,
-                    base::Closure start_backend);
+                    base::Closure start_engine);
   ~StartupController();
 
   // Starts up sync if it is requested by the user and preconditions are met.
   // Returns true if these preconditions are met, although does not imply
-  // the backend was started.
+  // the engine was started.
   bool TryStart();
 
   // Same as TryStart() above, but bypasses deferred startup and the first setup
@@ -54,14 +53,14 @@
   void SetSetupInProgress(bool setup_in_progress);
 
   bool IsSetupInProgress() const { return setup_in_progress_; }
-  base::Time start_backend_time() const { return start_backend_time_; }
-  std::string GetBackendInitializationStateString() const;
+  base::Time start_engine_time() const { return start_engine_time_; }
+  std::string GetEngineInitializationStateString() const;
 
   void OverrideFallbackTimeoutForTest(const base::TimeDelta& timeout);
 
  private:
-  enum StartUpDeferredOption { STARTUP_BACKEND_DEFERRED, STARTUP_IMMEDIATE };
-  // Returns true if all conditions to start the backend are met.
+  enum StartUpDeferredOption { STARTUP_DEFERRED, STARTUP_IMMEDIATE };
+  // Returns true if all conditions to start the engine are met.
   bool StartUp(StartUpDeferredOption deferred_option);
   void OnFallbackStartupTimerExpired();
 
@@ -78,7 +77,7 @@
 
   // The time that StartUp() is called. This is used to calculate time spent
   // in the deferred state; that is, after StartUp and before invoking the
-  // start_backend_ callback.
+  // start_engine_ callback.
   base::Time start_up_time_;
 
   // If |true|, there is setup UI visible so we should not start downloading
@@ -91,15 +90,15 @@
   const SyncPrefs* sync_prefs_;
 
   // A function that can be invoked repeatedly to determine whether sync can be
-  // started. |start_backend_| should not be invoked unless this returns true.
+  // started. |start_engine_| should not be invoked unless this returns true.
   base::Callback<bool()> can_start_;
 
   // The callback we invoke when it's time to call expensive
-  // startup routines for the sync backend.
-  base::Closure start_backend_;
+  // startup routines for the sync engine.
+  base::Closure start_engine_;
 
-  // The time at which we invoked the start_backend_ callback.
-  base::Time start_backend_time_;
+  // The time at which we invoked the start_engine_ callback.
+  base::Time start_engine_time_;
 
   base::TimeDelta fallback_timeout_;
 
diff --git a/components/sync/driver/startup_controller_unittest.cc b/components/sync/driver/startup_controller_unittest.cc
index 8bf9e5c..6cc59d4e 100644
--- a/components/sync/driver/startup_controller_unittest.cc
+++ b/components/sync/driver/startup_controller_unittest.cc
@@ -18,7 +18,7 @@
 namespace syncer {
 
 // These are coupled to the implementation of StartupController's
-// GetBackendInitializationStateString which is used by about:sync. We use it
+// GetEngineInitializationStateString which is used by about:sync. We use it
 // as a convenient way to verify internal state and that the class is
 // outputting the correct values for the debug string.
 static const char kStateStringStarted[] = "Started";
@@ -54,7 +54,7 @@
   void ExpectStarted() {
     EXPECT_TRUE(started());
     EXPECT_EQ(kStateStringStarted,
-              controller()->GetBackendInitializationStateString());
+              controller()->GetEngineInitializationStateString());
   }
 
   void ExpectStartDeferred() {
@@ -63,13 +63,13 @@
             switches::kSyncDisableDeferredStartup);
     EXPECT_EQ(!deferred_start, started());
     EXPECT_EQ(deferred_start ? kStateStringDeferred : kStateStringStarted,
-              controller()->GetBackendInitializationStateString());
+              controller()->GetEngineInitializationStateString());
   }
 
   void ExpectNotStarted() {
     EXPECT_FALSE(started());
     EXPECT_EQ(kStateStringNotStarted,
-              controller()->GetBackendInitializationStateString());
+              controller()->GetEngineInitializationStateString());
   }
 
   bool started() const { return started_; }
diff --git a/components/sync/driver/sync_api_component_factory.h b/components/sync/driver/sync_api_component_factory.h
index 7c1ac75..cb869fd 100644
--- a/components/sync/driver/sync_api_component_factory.h
+++ b/components/sync/driver/sync_api_component_factory.h
@@ -32,7 +32,7 @@
 class DataTypeManager;
 class DataTypeManagerObserver;
 class LocalDeviceInfoProvider;
-class SyncBackendHost;
+class SyncEngine;
 class SyncClient;
 class SyncPrefs;
 class SyncService;
@@ -78,18 +78,16 @@
       SyncService* sync_service,
       const RegisterDataTypesMethod& register_platform_types_method) = 0;
 
-  // Instantiates a new DataTypeManager with a SyncBackendHost, a list of data
-  // type controllers and a DataTypeManagerObserver.  The return pointer is
-  // owned by the caller.
+  // Creates a DataTypeManager; the return pointer is owned by the caller.
   virtual DataTypeManager* CreateDataTypeManager(
       const WeakHandle<DataTypeDebugInfoListener>& debug_info_listener,
       const DataTypeController::TypeMap* controllers,
       const DataTypeEncryptionHandler* encryption_handler,
-      SyncBackendHost* backend,
+      SyncEngine* engine,
       DataTypeManagerObserver* observer) = 0;
 
   // Creating this in the factory helps us mock it out in testing.
-  virtual SyncBackendHost* CreateSyncBackendHost(
+  virtual SyncEngine* CreateSyncEngine(
       const std::string& name,
       invalidation::InvalidationService* invalidator,
       const base::WeakPtr<SyncPrefs>& sync_prefs,
diff --git a/components/sync/driver/sync_api_component_factory_mock.h b/components/sync/driver/sync_api_component_factory_mock.h
index a4a7965..586543f 100644
--- a/components/sync/driver/sync_api_component_factory_mock.h
+++ b/components/sync/driver/sync_api_component_factory_mock.h
@@ -33,13 +33,13 @@
                DataTypeManager*(const WeakHandle<DataTypeDebugInfoListener>&,
                                 const DataTypeController::TypeMap*,
                                 const DataTypeEncryptionHandler*,
-                                SyncBackendHost*,
+                                SyncEngine*,
                                 DataTypeManagerObserver* observer));
-  MOCK_METHOD4(CreateSyncBackendHost,
-               SyncBackendHost*(const std::string& name,
-                                invalidation::InvalidationService* invalidator,
-                                const base::WeakPtr<SyncPrefs>& sync_prefs,
-                                const base::FilePath& sync_folder));
+  MOCK_METHOD4(CreateSyncEngine,
+               SyncEngine*(const std::string& name,
+                           invalidation::InvalidationService* invalidator,
+                           const base::WeakPtr<SyncPrefs>& sync_prefs,
+                           const base::FilePath& sync_folder));
 
   std::unique_ptr<LocalDeviceInfoProvider> CreateLocalDeviceInfoProvider()
       override;
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 83be47b..51e40722 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -200,9 +200,7 @@
   virtual const GoogleServiceAuthError& GetAuthError() const = 0;
   virtual bool HasUnrecoverableError() const = 0;
 
-  // Returns true if the SyncBackendHost has told us it's ready to accept
-  // changes. This should only be used for sync's internal configuration logic
-  // (such as deciding when to prompt for an encryption passphrase).
+  // Returns true if the SyncEngine has told us it's ready to accept changes.
   virtual bool IsBackendInitialized() const = 0;
 
   // Return the active OpenTabsUIDelegate. If open/proxy tabs is not enabled or
diff --git a/components/sync/driver/ui_data_type_controller.cc b/components/sync/driver/ui_data_type_controller.cc
deleted file mode 100644
index bb08a9f9..0000000
--- a/components/sync/driver/ui_data_type_controller.cc
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/driver/ui_data_type_controller.h"
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/profiler/scoped_tracker.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/sync/base/data_type_histogram.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/driver/generic_change_processor_factory.h"
-#include "components/sync/driver/shared_change_processor_ref.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/data_type_error_handler_impl.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/sync_merge_result.h"
-#include "components/sync/model/syncable_service.h"
-
-namespace syncer {
-
-UIDataTypeController::UIDataTypeController()
-    : DirectoryDataTypeController(UNSPECIFIED,
-                                  base::Closure(),
-                                  nullptr,
-                                  GROUP_UI),
-      state_(NOT_RUNNING) {}
-
-UIDataTypeController::UIDataTypeController(ModelType type,
-                                           const base::Closure& dump_stack,
-                                           SyncClient* sync_client)
-    : DirectoryDataTypeController(type, dump_stack, sync_client, GROUP_UI),
-      state_(NOT_RUNNING),
-      processor_factory_(new GenericChangeProcessorFactory()) {
-  DCHECK(IsRealDataType(type));
-}
-
-void UIDataTypeController::SetGenericChangeProcessorFactoryForTest(
-    std::unique_ptr<GenericChangeProcessorFactory> factory) {
-  DCHECK_EQ(state_, NOT_RUNNING);
-  processor_factory_ = std::move(factory);
-}
-
-UIDataTypeController::~UIDataTypeController() {}
-
-void UIDataTypeController::LoadModels(
-    const ModelLoadCallback& model_load_callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(IsRealDataType(type()));
-  model_load_callback_ = model_load_callback;
-  if (state_ != NOT_RUNNING) {
-    model_load_callback.Run(type(),
-                            SyncError(FROM_HERE, SyncError::DATATYPE_ERROR,
-                                      "Model already loaded", type()));
-    return;
-  }
-  // Since we can't be called multiple times before Stop() is called,
-  // |shared_change_processor_| must be null here.
-  DCHECK(!shared_change_processor_.get());
-  shared_change_processor_ = new SharedChangeProcessor(type());
-
-  state_ = MODEL_STARTING;
-  if (!StartModels()) {
-    // If we are waiting for some external service to load before associating
-    // or we failed to start the models, we exit early. state_ will control
-    // what we perform next.
-    DCHECK(state_ == NOT_RUNNING || state_ == MODEL_STARTING);
-    return;
-  }
-
-  state_ = MODEL_LOADED;
-  model_load_callback_.Run(type(), SyncError());
-}
-
-void UIDataTypeController::OnModelLoaded() {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(state_, MODEL_STARTING);
-
-  state_ = MODEL_LOADED;
-  model_load_callback_.Run(type(), SyncError());
-}
-
-void UIDataTypeController::StartAssociating(
-    const StartCallback& start_callback) {
-  DCHECK(CalledOnValidThread());
-  DCHECK(!start_callback.is_null());
-  DCHECK_EQ(state_, MODEL_LOADED);
-
-  start_callback_ = start_callback;
-  state_ = ASSOCIATING;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&UIDataTypeController::Associate, base::AsWeakPtr(this)));
-}
-
-bool UIDataTypeController::StartModels() {
-  DCHECK_EQ(state_, MODEL_STARTING);
-  // By default, no additional services need to be started before we can proceed
-  // with model association.
-  return true;
-}
-
-void UIDataTypeController::Associate() {
-  DCHECK(CalledOnValidThread());
-  if (state_ != ASSOCIATING) {
-    // Stop() must have been called while Associate() task have been waiting.
-    DCHECK_EQ(state_, NOT_RUNNING);
-    return;
-  }
-
-  SyncMergeResult local_merge_result(type());
-  SyncMergeResult syncer_merge_result(type());
-  base::WeakPtrFactory<SyncMergeResult> weak_ptr_factory(&syncer_merge_result);
-
-  // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403 is
-  // fixed.
-  tracked_objects::ScopedTracker tracking_profile1(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "471403 UIDataTypeController::Associate1"));
-
-  // Connect |shared_change_processor_| to the syncer and get the
-  // SyncableService associated with type().
-  DCHECK(sync_client_->GetSyncService());
-  local_service_ = shared_change_processor_->Connect(
-      sync_client_, processor_factory_.get(),
-      sync_client_->GetSyncService()->GetUserShare(), CreateErrorHandler(),
-      weak_ptr_factory.GetWeakPtr());
-  if (!local_service_.get()) {
-    SyncError error(FROM_HERE, SyncError::DATATYPE_ERROR,
-                    "Failed to connect to syncer.", type());
-    local_merge_result.set_error(error);
-    StartDone(ASSOCIATION_FAILED, local_merge_result, syncer_merge_result);
-    return;
-  }
-
-  // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403 is
-  // fixed.
-  tracked_objects::ScopedTracker tracking_profile2(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "471403 UIDataTypeController::Associate2"));
-  if (!shared_change_processor_->CryptoReadyIfNecessary()) {
-    SyncError error(FROM_HERE, SyncError::CRYPTO_ERROR, "", type());
-    local_merge_result.set_error(error);
-    StartDone(NEEDS_CRYPTO, local_merge_result, syncer_merge_result);
-    return;
-  }
-
-  // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403 is
-  // fixed.
-  tracked_objects::ScopedTracker tracking_profile3(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "471403 UIDataTypeController::Associate3"));
-  bool sync_has_nodes = false;
-  if (!shared_change_processor_->SyncModelHasUserCreatedNodes(
-          &sync_has_nodes)) {
-    SyncError error(FROM_HERE, SyncError::UNRECOVERABLE_ERROR,
-                    "Failed to load sync nodes", type());
-    local_merge_result.set_error(error);
-    StartDone(UNRECOVERABLE_ERROR, local_merge_result, syncer_merge_result);
-    return;
-  }
-
-  // Scope for |initial_sync_data| which might be expensive, so we don't want
-  // to keep it in memory longer than necessary.
-  {
-    SyncDataList initial_sync_data;
-
-    // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403
-    // is fixed.
-    tracked_objects::ScopedTracker tracking_profile4(
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "471403 UIDataTypeController::Associate4"));
-    base::TimeTicks start_time = base::TimeTicks::Now();
-    SyncError error = shared_change_processor_->GetAllSyncDataReturnError(
-        type(), &initial_sync_data);
-    if (error.IsSet()) {
-      local_merge_result.set_error(error);
-      StartDone(ASSOCIATION_FAILED, local_merge_result, syncer_merge_result);
-      return;
-    }
-
-    // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403
-    // is fixed.
-    tracked_objects::ScopedTracker tracking_profile5(
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "471403 UIDataTypeController::Associate5"));
-    std::string datatype_context;
-    if (shared_change_processor_->GetDataTypeContext(&datatype_context)) {
-      local_service_->UpdateDataTypeContext(
-          type(), SyncChangeProcessor::NO_REFRESH, datatype_context);
-    }
-
-    // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403
-    // is fixed.
-    tracked_objects::ScopedTracker tracking_profile6(
-        FROM_HERE_WITH_EXPLICIT_FUNCTION(
-            "471403 UIDataTypeController::Associate6"));
-    syncer_merge_result.set_num_items_before_association(
-        initial_sync_data.size());
-    // Passes a reference to |shared_change_processor_|.
-    local_merge_result = local_service_->MergeDataAndStartSyncing(
-        type(), initial_sync_data,
-        std::unique_ptr<SyncChangeProcessor>(
-            new SharedChangeProcessorRef(shared_change_processor_)),
-        std::unique_ptr<SyncErrorFactory>(
-            new SharedChangeProcessorRef(shared_change_processor_)));
-    RecordAssociationTime(base::TimeTicks::Now() - start_time);
-    if (local_merge_result.error().IsSet()) {
-      StartDone(ASSOCIATION_FAILED, local_merge_result, syncer_merge_result);
-      return;
-    }
-  }
-
-  // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403 is
-  // fixed.
-  tracked_objects::ScopedTracker tracking_profile7(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "471403 UIDataTypeController::Associate7"));
-  syncer_merge_result.set_num_items_after_association(
-      shared_change_processor_->GetSyncCount());
-
-  state_ = RUNNING;
-  StartDone(sync_has_nodes ? OK : OK_FIRST_RUN, local_merge_result,
-            syncer_merge_result);
-}
-
-ChangeProcessor* UIDataTypeController::GetChangeProcessor() const {
-  DCHECK_EQ(state_, RUNNING);
-  return shared_change_processor_->generic_change_processor();
-}
-
-void UIDataTypeController::AbortModelLoad() {
-  DCHECK(CalledOnValidThread());
-  state_ = NOT_RUNNING;
-
-  if (shared_change_processor_.get()) {
-    shared_change_processor_ = nullptr;
-  }
-
-  // We don't want to continue loading models (e.g OnModelLoaded should never be
-  // called after we've decided to abort).
-  StopModels();
-}
-
-void UIDataTypeController::StartDone(
-    ConfigureResult start_result,
-    const SyncMergeResult& local_merge_result,
-    const SyncMergeResult& syncer_merge_result) {
-  DCHECK(CalledOnValidThread());
-
-  // TODO(robliao): Remove ScopedTracker below once https://crbug.com/471403 is
-  // fixed.
-  tracked_objects::ScopedTracker tracking_profile(
-      FROM_HERE_WITH_EXPLICIT_FUNCTION(
-          "471403 UIDataTypeController::StartDone"));
-
-  if (!IsSuccessfulResult(start_result)) {
-    StopModels();
-    if (start_result == ASSOCIATION_FAILED) {
-      state_ = DISABLED;
-    } else {
-      state_ = NOT_RUNNING;
-    }
-    RecordStartFailure(start_result);
-
-    if (shared_change_processor_.get()) {
-      shared_change_processor_->Disconnect();
-      shared_change_processor_ = nullptr;
-    }
-  }
-
-  start_callback_.Run(start_result, local_merge_result, syncer_merge_result);
-}
-
-void UIDataTypeController::Stop() {
-  DCHECK(CalledOnValidThread());
-  DCHECK(IsRealDataType(type()));
-
-  if (state_ == NOT_RUNNING)
-    return;
-
-  State prev_state = state_;
-  state_ = STOPPING;
-
-  if (shared_change_processor_.get()) {
-    shared_change_processor_->Disconnect();
-    shared_change_processor_ = nullptr;
-  }
-
-  // If Stop() is called while Start() is waiting for the datatype model to
-  // load, abort the start.
-  if (prev_state == MODEL_STARTING) {
-    AbortModelLoad();
-    // We can just return here since we haven't performed association if we're
-    // still in MODEL_STARTING.
-    return;
-  }
-
-  StopModels();
-
-  if (local_service_.get()) {
-    local_service_->StopSyncing(type());
-  }
-
-  state_ = NOT_RUNNING;
-}
-
-void UIDataTypeController::StopModels() {
-  // Do nothing by default.
-}
-
-std::string UIDataTypeController::name() const {
-  // For logging only.
-  return ModelTypeToString(type());
-}
-
-DataTypeController::State UIDataTypeController::state() const {
-  return state_;
-}
-
-std::unique_ptr<DataTypeErrorHandler>
-UIDataTypeController::CreateErrorHandler() {
-  DCHECK(CalledOnValidThread());
-  return base::MakeUnique<DataTypeErrorHandlerImpl>(
-      base::ThreadTaskRunnerHandle::Get(), dump_stack_,
-      base::Bind(&UIDataTypeController::OnUnrecoverableError,
-                 base::AsWeakPtr(this)));
-}
-
-void UIDataTypeController::OnUnrecoverableError(const SyncError& error) {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(type(), error.model_type());
-  if (!model_load_callback_.is_null()) {
-    model_load_callback_.Run(type(), error);
-  }
-}
-
-void UIDataTypeController::RecordAssociationTime(base::TimeDelta time) {
-  DCHECK(CalledOnValidThread());
-#define PER_DATA_TYPE_MACRO(type_str) \
-  UMA_HISTOGRAM_TIMES("Sync." type_str "AssociationTime", time);
-  SYNC_DATA_TYPE_HISTOGRAM(type());
-#undef PER_DATA_TYPE_MACRO
-}
-
-void UIDataTypeController::RecordStartFailure(ConfigureResult result) {
-  DCHECK(CalledOnValidThread());
-  UMA_HISTOGRAM_ENUMERATION("Sync.DataTypeStartFailures",
-                            ModelTypeToHistogramInt(type()), MODEL_TYPE_COUNT);
-#define PER_DATA_TYPE_MACRO(type_str)                                    \
-  UMA_HISTOGRAM_ENUMERATION("Sync." type_str "ConfigureFailure", result, \
-                            MAX_CONFIGURE_RESULT);
-  SYNC_DATA_TYPE_HISTOGRAM(type());
-#undef PER_DATA_TYPE_MACRO
-}
-
-}  // namespace syncer
diff --git a/components/sync/driver/ui_data_type_controller.h b/components/sync/driver/ui_data_type_controller.h
deleted file mode 100644
index 3784e52..0000000
--- a/components/sync/driver/ui_data_type_controller.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SYNC_DRIVER_UI_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_SYNC_DRIVER_UI_DATA_TYPE_CONTROLLER_H_
-
-#include <memory>
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/sync/driver/directory_data_type_controller.h"
-#include "components/sync/driver/shared_change_processor.h"
-
-namespace base {
-class TimeDelta;
-}  // namespace base
-
-namespace syncer {
-
-class SyncableService;
-class SyncClient;
-class SyncError;
-
-// Implementation for datatypes that reside on the (UI thread). This is the same
-// thread we perform initialization on, so we don't have to worry about thread
-// safety. The main start/stop funtionality is implemented by default.
-// Note: RefCountedThreadSafe by way of DataTypeController.
-class UIDataTypeController : public DirectoryDataTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  UIDataTypeController(ModelType type,
-                       const base::Closure& dump_stack,
-                       SyncClient* sync_client);
-  ~UIDataTypeController() override;
-
-  // DataTypeController interface.
-  void LoadModels(const ModelLoadCallback& model_load_callback) override;
-  void StartAssociating(const StartCallback& start_callback) override;
-  void Stop() override;
-  ChangeProcessor* GetChangeProcessor() const override;
-  std::string name() const override;
-  State state() const override;
-
-  // Used by tests to override the factory used to create
-  // GenericChangeProcessors.
-  void SetGenericChangeProcessorFactoryForTest(
-      std::unique_ptr<GenericChangeProcessorFactory> factory);
-
- protected:
-  // For testing only.
-  UIDataTypeController();
-
-  // Start any dependent services that need to be running before we can
-  // associate models. The default implementation is a no-op.
-  // Return value:
-  //   True - if models are ready and association can proceed.
-  //   False - if models are not ready. OnModelLoaded() should be called when
-  //           the models are ready.
-  virtual bool StartModels();
-
-  // Perform any DataType controller specific state cleanup before stopping
-  // the datatype controller. The default implementation is a no-op.
-  virtual void StopModels();
-
-  // Helper method for cleaning up state and invoking the start callback.
-  virtual void StartDone(ConfigureResult result,
-                         const SyncMergeResult& local_merge_result,
-                         const SyncMergeResult& syncer_merge_result);
-
-  // Record association time.
-  virtual void RecordAssociationTime(base::TimeDelta time);
-  // Record causes of start failure.
-  virtual void RecordStartFailure(ConfigureResult result);
-
-  // If the DTC is waiting for models to load, once the models are
-  // loaded the datatype service will call this function on DTC to let
-  // us know that it is safe to start associating.
-  void OnModelLoaded();
-
-  std::unique_ptr<DataTypeErrorHandler> CreateErrorHandler() override;
-
-  State state_;
-
-  StartCallback start_callback_;
-  ModelLoadCallback model_load_callback_;
-
-  // Sync's interface to the datatype. All sync changes for |type_| are pushed
-  // through it to the datatype as well as vice versa.
-  //
-  // Lifetime: it gets created when Start()) is called, and a reference to it
-  // is passed to |local_service_| during Associate(). We release our reference
-  // when Stop() or StartFailed() is called, and |local_service_| releases its
-  // reference when local_service_->StopSyncing() is called or when it is
-  // destroyed.
-  //
-  // Note: we use refcounting here primarily so that we can keep a uniform
-  // SyncableService API, whether the datatype lives on the UI thread or not
-  // (a SyncableService takes ownership of its SyncChangeProcessor when
-  // MergeDataAndStartSyncing is called). This will help us eventually merge the
-  // two datatype controller implementations (for ui and non-ui thread
-  // datatypes).
-  scoped_refptr<SharedChangeProcessor> shared_change_processor_;
-
-  std::unique_ptr<GenericChangeProcessorFactory> processor_factory_;
-
-  // A weak pointer to the actual local syncable service, which performs all the
-  // real work. We do not own the object.
-  base::WeakPtr<SyncableService> local_service_;
-
- private:
-  // Associate the sync model with the service's model, then start syncing.
-  virtual void Associate();
-
-  virtual void AbortModelLoad();
-
-  void OnUnrecoverableError(const SyncError& error);
-
-  DISALLOW_COPY_AND_ASSIGN(UIDataTypeController);
-};
-
-}  // namespace syncer
-
-#endif  // COMPONENTS_SYNC_DRIVER_UI_DATA_TYPE_CONTROLLER_H_
diff --git a/components/sync/driver/ui_data_type_controller_unittest.cc b/components/sync/driver/ui_data_type_controller_unittest.cc
deleted file mode 100644
index 39b3a2f..0000000
--- a/components/sync/driver/ui_data_type_controller_unittest.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/sync/driver/ui_data_type_controller.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/tracked_objects.h"
-#include "components/sync/base/model_type.h"
-#include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/fake_sync_client.h"
-#include "components/sync/model/fake_syncable_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::Invoke;
-using testing::InvokeWithoutArgs;
-using testing::Return;
-
-namespace syncer {
-namespace {
-
-class UIDataTypeControllerFake : public UIDataTypeController {
- public:
-  UIDataTypeControllerFake(ModelType type,
-                           const base::Closure& dump_stack,
-                           SyncClient* sync_client)
-      : UIDataTypeController(type, dump_stack, sync_client) {}
-
-  void OnUnrecoverableError(const SyncError& error) {
-    CreateErrorHandler()->OnUnrecoverableError(error);
-  }
-};
-
-// TODO(zea): Expand this to make the dtc type paramterizable. This will let us
-// test the basic functionality of all UIDataTypeControllers. We'll need to have
-// intelligent default values for the methods queried in the dependent services
-// (e.g. those queried in StartModels).
-class SyncUIDataTypeControllerTest : public testing::Test,
-                                     public FakeSyncClient {
- public:
-  SyncUIDataTypeControllerTest()
-      : type_(PREFERENCES), change_processor_(nullptr) {}
-
-  // FakeSyncClient overrides.
-  base::WeakPtr<SyncableService> GetSyncableServiceForType(
-      ModelType type) override {
-    return syncable_service_.AsWeakPtr();
-  }
-
-  void SetUp() override {
-    preference_dtc_ = base::MakeUnique<UIDataTypeControllerFake>(
-        type_, base::Closure(), this);
-    SetStartExpectations();
-  }
-
-  void TearDown() override {
-    // Must be done before we pump the loop.
-    syncable_service_.StopSyncing(type_);
-    preference_dtc_ = nullptr;
-    PumpLoop();
-  }
-
- protected:
-  void SetStartExpectations() {
-    std::unique_ptr<FakeGenericChangeProcessor> p(
-        new FakeGenericChangeProcessor(type_, this));
-    change_processor_ = p.get();
-    std::unique_ptr<GenericChangeProcessorFactory> f(
-        new FakeGenericChangeProcessorFactory(std::move(p)));
-    preference_dtc_->SetGenericChangeProcessorFactoryForTest(std::move(f));
-    EXPECT_CALL(model_load_callback_, Run(_, _));
-  }
-
-  void Start() {
-    preference_dtc_->LoadModels(base::Bind(
-        &ModelLoadCallbackMock::Run, base::Unretained(&model_load_callback_)));
-    preference_dtc_->StartAssociating(base::Bind(
-        &StartCallbackMock::Run, base::Unretained(&start_callback_)));
-    PumpLoop();
-  }
-
-  void PumpLoop() { base::RunLoop().RunUntilIdle(); }
-
-  base::MessageLoop message_loop_;
-  const ModelType type_;
-  StartCallbackMock start_callback_;
-  ModelLoadCallbackMock model_load_callback_;
-  FakeGenericChangeProcessor* change_processor_;
-  FakeSyncableService syncable_service_;
-  std::unique_ptr<UIDataTypeControllerFake> preference_dtc_;
-};
-
-// Start the DTC. Verify that the callback is called with OK, the
-// service has been told to start syncing and that the DTC is now in RUNNING
-// state.
-TEST_F(SyncUIDataTypeControllerTest, Start) {
-  EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
-  EXPECT_TRUE(syncable_service_.syncing());
-}
-
-// Start and then stop the DTC. Verify that the service started and stopped
-// syncing, and that the DTC went from RUNNING to NOT_RUNNING.
-TEST_F(SyncUIDataTypeControllerTest, StartStop) {
-  EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
-  EXPECT_TRUE(syncable_service_.syncing());
-  preference_dtc_->Stop();
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-// Start and then stop the DTC before the Start had a chance to perform
-// association. Verify that the service never started and is NOT_RUNNING.
-TEST_F(SyncUIDataTypeControllerTest, StartStopBeforeAssociation) {
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  message_loop_.task_runner()->PostTask(
-      FROM_HERE, base::Bind(&UIDataTypeController::Stop,
-                            base::AsWeakPtr(preference_dtc_.get())));
-  Start();
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-// Start the DTC when no user nodes are created. Verify that the callback
-// is called with OK_FIRST_RUN. Stop the DTC.
-TEST_F(SyncUIDataTypeControllerTest, StartStopFirstRun) {
-  EXPECT_CALL(start_callback_, Run(DataTypeController::OK_FIRST_RUN, _, _));
-  change_processor_->set_sync_model_has_user_created_nodes(false);
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(DataTypeController::RUNNING, preference_dtc_->state());
-  EXPECT_TRUE(syncable_service_.syncing());
-  preference_dtc_->Stop();
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-// Start the DTC, but have the service fail association. Verify the callback
-// is called with ASSOCIATION_FAILED, the DTC goes to state DISABLED, and the
-// service is not syncing. Then stop the DTC.
-TEST_F(SyncUIDataTypeControllerTest, StartAssociationFailed) {
-  EXPECT_CALL(start_callback_,
-              Run(DataTypeController::ASSOCIATION_FAILED, _, _));
-  syncable_service_.set_merge_data_and_start_syncing_error(
-      SyncError(FROM_HERE, SyncError::DATATYPE_ERROR, "Error", type_));
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(DataTypeController::DISABLED, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  preference_dtc_->Stop();
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-// Start the DTC but fail to check if there are user created nodes. Verify the
-// DTC calls the callback with UNRECOVERABLE_ERROR and that it goes into
-// NOT_RUNNING state. Verify the syncable service is not syncing.
-TEST_F(SyncUIDataTypeControllerTest,
-       StartAssociationTriggersUnrecoverableError) {
-  EXPECT_CALL(start_callback_,
-              Run(DataTypeController::UNRECOVERABLE_ERROR, _, _));
-  change_processor_->set_sync_model_has_user_created_nodes_success(false);
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-// Start the DTC, but then trigger an unrecoverable error. Verify the syncer
-// gets stopped and the DTC is in NOT_RUNNING state.
-TEST_F(SyncUIDataTypeControllerTest, OnSingleDatatypeUnrecoverableError) {
-  EXPECT_CALL(start_callback_, Run(DataTypeController::OK, _, _));
-
-  EXPECT_EQ(DataTypeController::NOT_RUNNING, preference_dtc_->state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_TRUE(syncable_service_.syncing());
-
-  testing::Mock::VerifyAndClearExpectations(&start_callback_);
-  EXPECT_CALL(model_load_callback_, Run(_, _));
-  SyncError error(FROM_HERE, SyncError::DATATYPE_ERROR, "error", PREFERENCES);
-  preference_dtc_->OnUnrecoverableError(error);
-  PumpLoop();
-}
-
-}  // namespace
-}  // namespace syncer
diff --git a/components/sync/engine/fake_sync_engine.cc b/components/sync/engine/fake_sync_engine.cc
new file mode 100644
index 0000000..a6ab2bb
--- /dev/null
+++ b/components/sync/engine/fake_sync_engine.cc
@@ -0,0 +1,136 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync/engine/fake_sync_engine.h"
+
+#include "components/sync/engine/activation_context.h"
+#include "components/sync/engine/sync_engine_host.h"
+
+namespace syncer {
+
+const char kTestCacheGuid[] = "test-guid";
+
+FakeSyncEngine::FakeSyncEngine() : fail_initial_download_(false) {}
+FakeSyncEngine::~FakeSyncEngine() {}
+
+void FakeSyncEngine::Initialize(
+    SyncEngineHost* host,
+    scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
+    const WeakHandle<JsEventHandler>& event_handler,
+    const GURL& service_url,
+    const std::string& sync_user_agent,
+    const SyncCredentials& credentials,
+    bool delete_sync_data_folder,
+    bool enable_local_sync_backend,
+    const base::FilePath& local_sync_backend_folder,
+    std::unique_ptr<SyncManagerFactory> sync_manager_factory,
+    const WeakHandle<UnrecoverableErrorHandler>& unrecoverable_error_handler,
+    const base::Closure& report_unrecoverable_error_function,
+    const HttpPostProviderFactoryGetter& http_post_provider_factory_getter,
+    std::unique_ptr<SyncEncryptionHandler::NigoriState> saved_nigori_state) {
+  host->OnBackendInitialized(WeakHandle<JsBackend>(),
+                             WeakHandle<DataTypeDebugInfoListener>(),
+                             kTestCacheGuid, !fail_initial_download_);
+}
+
+void FakeSyncEngine::TriggerRefresh(const ModelTypeSet& types) {}
+
+void FakeSyncEngine::UpdateCredentials(const SyncCredentials& credentials) {}
+
+void FakeSyncEngine::StartSyncingWithServer() {}
+
+void FakeSyncEngine::SetEncryptionPassphrase(const std::string& passphrase,
+                                             bool is_explicit) {}
+
+bool FakeSyncEngine::SetDecryptionPassphrase(const std::string& passphrase) {
+  return false;
+}
+
+void FakeSyncEngine::StopSyncingForShutdown() {}
+
+void FakeSyncEngine::Shutdown(ShutdownReason reason) {}
+
+void FakeSyncEngine::UnregisterInvalidationIds() {}
+
+ModelTypeSet FakeSyncEngine::ConfigureDataTypes(
+    ConfigureReason reason,
+    const DataTypeConfigStateMap& config_state_map,
+    const base::Callback<void(ModelTypeSet, ModelTypeSet)>& ready_task,
+    const base::Callback<void()>& retry_callback) {
+  return ModelTypeSet();
+}
+
+void FakeSyncEngine::EnableEncryptEverything() {}
+
+void FakeSyncEngine::ActivateDirectoryDataType(
+    ModelType type,
+    ModelSafeGroup group,
+    ChangeProcessor* change_processor) {}
+void FakeSyncEngine::DeactivateDirectoryDataType(ModelType type) {}
+
+void FakeSyncEngine::ActivateNonBlockingDataType(
+    ModelType type,
+    std::unique_ptr<ActivationContext> activation_context) {}
+
+void FakeSyncEngine::DeactivateNonBlockingDataType(ModelType type) {}
+
+UserShare* FakeSyncEngine::GetUserShare() const {
+  return nullptr;
+}
+
+SyncEngine::Status FakeSyncEngine::GetDetailedStatus() {
+  return SyncEngine::Status();
+}
+
+SyncCycleSnapshot FakeSyncEngine::GetLastCycleSnapshot() const {
+  return SyncCycleSnapshot();
+}
+
+bool FakeSyncEngine::HasUnsyncedItems() const {
+  return false;
+}
+
+bool FakeSyncEngine::IsNigoriEnabled() const {
+  return true;
+}
+
+PassphraseType FakeSyncEngine::GetPassphraseType() const {
+  return PassphraseType::IMPLICIT_PASSPHRASE;
+}
+
+base::Time FakeSyncEngine::GetExplicitPassphraseTime() const {
+  return base::Time();
+}
+
+bool FakeSyncEngine::IsCryptographerReady(const BaseTransaction* trans) const {
+  return false;
+}
+
+void FakeSyncEngine::GetModelSafeRoutingInfo(ModelSafeRoutingInfo* out) const {}
+
+void FakeSyncEngine::FlushDirectory() const {}
+
+void FakeSyncEngine::RefreshTypesForTest(ModelTypeSet types) {}
+
+void FakeSyncEngine::RequestBufferedProtocolEventsAndEnableForwarding() {}
+
+void FakeSyncEngine::DisableProtocolEventForwarding() {}
+
+void FakeSyncEngine::EnableDirectoryTypeDebugInfoForwarding() {}
+
+void FakeSyncEngine::DisableDirectoryTypeDebugInfoForwarding() {}
+
+void FakeSyncEngine::set_fail_initial_download(bool should_fail) {
+  fail_initial_download_ = should_fail;
+}
+
+void FakeSyncEngine::ClearServerData(
+    const SyncManager::ClearServerDataCallback& callback) {
+  callback.Run();
+}
+
+void FakeSyncEngine::OnCookieJarChanged(bool account_mismatch, bool empty_jar) {
+}
+
+}  // namespace syncer
diff --git a/components/sync/driver/glue/sync_backend_host_mock.h b/components/sync/engine/fake_sync_engine.h
similarity index 88%
rename from components/sync/driver/glue/sync_backend_host_mock.h
rename to components/sync/engine/fake_sync_engine.h
index 66b5a26..68e9347 100644
--- a/components/sync/driver/glue/sync_backend_host_mock.h
+++ b/components/sync/engine/fake_sync_engine.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 COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_MOCK_H_
-#define COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_MOCK_H_
+#ifndef COMPONENTS_SYNC_ENGINE_FAKE_SYNC_ENGINE_H_
+#define COMPONENTS_SYNC_ENGINE_FAKE_SYNC_ENGINE_H_
 
 #include <memory>
 #include <string>
@@ -11,23 +11,23 @@
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "components/sync/base/weak_handle.h"
-#include "components/sync/driver/glue/sync_backend_host.h"
+#include "components/sync/engine/sync_engine.h"
 
 namespace syncer {
 
-// A mock of the SyncBackendHost.
+// A mock of the SyncEngine.
 //
 // This class implements the bare minimum required for the ProfileSyncService to
 // get through initialization.  It often returns null pointers or nonesense
-// values; it is not intended to be used in tests that depend on SyncBackendHost
+// values; it is not intended to be used in tests that depend on SyncEngine
 // behavior.
-class SyncBackendHostMock : public SyncBackendHost {
+class FakeSyncEngine : public SyncEngine {
  public:
-  SyncBackendHostMock();
-  ~SyncBackendHostMock() override;
+  FakeSyncEngine();
+  ~FakeSyncEngine() override;
 
   void Initialize(
-      SyncFrontend* frontend,
+      SyncEngineHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
       const WeakHandle<JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -118,4 +118,4 @@
 
 }  // namespace syncer
 
-#endif  // COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_MOCK_H_
+#endif  // COMPONENTS_SYNC_ENGINE_FAKE_SYNC_ENGINE_H_
diff --git a/components/sync/driver/backend_data_type_configurer.cc b/components/sync/engine/model_type_configurer.cc
similarity index 66%
rename from components/sync/driver/backend_data_type_configurer.cc
rename to components/sync/engine/model_type_configurer.cc
index b689755e..914acc4 100644
--- a/components/sync/driver/backend_data_type_configurer.cc
+++ b/components/sync/engine/model_type_configurer.cc
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/sync/driver/backend_data_type_configurer.h"
+#include "components/sync/engine/model_type_configurer.h"
 
 namespace syncer {
 
 // static
-ModelTypeSet BackendDataTypeConfigurer::GetDataTypesInState(
+ModelTypeSet ModelTypeConfigurer::GetDataTypesInState(
     DataTypeConfigState state,
     const DataTypeConfigStateMap& state_map) {
   ModelTypeSet types;
@@ -20,10 +20,9 @@
 }
 
 // static
-void BackendDataTypeConfigurer::SetDataTypesState(
-    DataTypeConfigState state,
-    ModelTypeSet types,
-    DataTypeConfigStateMap* state_map) {
+void ModelTypeConfigurer::SetDataTypesState(DataTypeConfigState state,
+                                            ModelTypeSet types,
+                                            DataTypeConfigStateMap* state_map) {
   for (ModelTypeSet::Iterator it = types.First(); it.Good(); it.Inc()) {
     (*state_map)[it.Get()] = state;
   }
diff --git a/components/sync/driver/backend_data_type_configurer.h b/components/sync/engine/model_type_configurer.h
similarity index 86%
rename from components/sync/driver/backend_data_type_configurer.h
rename to components/sync/engine/model_type_configurer.h
index dcd6ed7..d1f9433 100644
--- a/components/sync/driver/backend_data_type_configurer.h
+++ b/components/sync/engine/model_type_configurer.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 COMPONENTS_SYNC_DRIVER_BACKEND_DATA_TYPE_CONFIGURER_H_
-#define COMPONENTS_SYNC_DRIVER_BACKEND_DATA_TYPE_CONFIGURER_H_
+#ifndef COMPONENTS_SYNC_ENGINE_MODEL_TYPE_CONFIGURER_H_
+#define COMPONENTS_SYNC_ENGINE_MODEL_TYPE_CONFIGURER_H_
 
 #include <map>
 #include <memory>
@@ -21,7 +21,7 @@
 // The DataTypeConfigurer interface abstracts out the action of
 // configuring a set of new data types and cleaning up after a set of
 // removed data types.
-class BackendDataTypeConfigurer {
+class ModelTypeConfigurer {
  public:
   enum DataTypeConfigState {
     CONFIGURE_ACTIVE,    // Actively being configured. Data of such types
@@ -46,11 +46,10 @@
   // Returns: the set of types that are already configured and are ready to
   // start.
   //
-  // TODO(akalin): Use a Delegate class with
-  // OnConfigureSuccess/OnConfigureFailure/OnConfigureRetry instead of
-  // a pair of callbacks.  The awkward part is handling when
-  // SyncBackendHost calls ConfigureDataTypes on itself to configure
-  // Nigori.
+  // TODO(akalin): Use a Delegate class with OnConfigureSuccess,
+  // OnConfigureFailure, and OnConfigureRetry instead of a pair of callbacks.
+  // The awkward part is handling when SyncEngine calls ConfigureDataTypes on
+  // itself to configure Nigori.
   virtual ModelTypeSet ConfigureDataTypes(
       ConfigureReason reason,
       const DataTypeConfigStateMap& config_state_map,
@@ -88,9 +87,9 @@
                                 DataTypeConfigStateMap* state_map);
 
  protected:
-  virtual ~BackendDataTypeConfigurer() {}
+  virtual ~ModelTypeConfigurer() {}
 };
 
 }  // namespace syncer
 
-#endif  // COMPONENTS_SYNC_DRIVER_BACKEND_DATA_TYPE_CONFIGURER_H_
+#endif  // COMPONENTS_SYNC_ENGINE_MODEL_TYPE_CONFIGURER_H_
diff --git a/components/sync/driver/glue/sync_backend_host.cc b/components/sync/engine/sync_engine.cc
similarity index 60%
rename from components/sync/driver/glue/sync_backend_host.cc
rename to components/sync/engine/sync_engine.cc
index 76da557d..5348259 100644
--- a/components/sync/driver/glue/sync_backend_host.cc
+++ b/components/sync/engine/sync_engine.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/sync/driver/glue/sync_backend_host.h"
+#include "components/sync/engine/sync_engine.h"
 
 namespace syncer {
 
-SyncBackendHost::SyncBackendHost() {}
-
-SyncBackendHost::~SyncBackendHost() {}
+SyncEngine::SyncEngine() {}
+SyncEngine::~SyncEngine() {}
 
 }  // namespace syncer
diff --git a/components/sync/driver/glue/sync_backend_host.h b/components/sync/engine/sync_engine.h
similarity index 73%
rename from components/sync/driver/glue/sync_backend_host.h
rename to components/sync/engine/sync_engine.h
index ec8ce496..790651f 100644
--- a/components/sync/driver/glue/sync_backend_host.h
+++ b/components/sync/engine/sync_engine.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 COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_H_
-#define COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_H_
+#ifndef COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_H_
+#define COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_H_
 
 #include <memory>
 #include <string>
@@ -14,9 +14,9 @@
 #include "base/single_thread_task_runner.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/base/weak_handle.h"
-#include "components/sync/driver/backend_data_type_configurer.h"
 #include "components/sync/engine/configure_reason.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
+#include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/engine/shutdown_reason.h"
 #include "components/sync/engine/sync_manager.h"
 #include "components/sync/engine/sync_manager_factory.h"
@@ -27,15 +27,15 @@
 
 class CancelationSignal;
 class HttpPostProviderFactory;
-class SyncFrontend;
+class SyncEngineHost;
 class SyncManagerFactory;
 class UnrecoverableErrorHandler;
 
-// An API to "host" the top level SyncAPI element.
-//
-// This class handles dispatch of potentially blocking calls to appropriate
-// threads and ensures that the SyncFrontend is only accessed on the UI loop.
-class SyncBackendHost : public BackendDataTypeConfigurer {
+// The interface into the sync engine, which is the part of sync that performs
+// communication between model types and the sync server. In prod the engine
+// will always live on the sync thread and the object implementing this
+// interface will handle crossing threads if necessary.
+class SyncEngine : public ModelTypeConfigurer {
  public:
   typedef SyncStatus Status;
   typedef base::Callback<std::unique_ptr<HttpPostProviderFactory>(
@@ -43,17 +43,16 @@
       HttpPostProviderFactoryGetter;
 
   // Stubs used by implementing classes.
-  SyncBackendHost();
-  ~SyncBackendHost() override;
+  SyncEngine();
+  ~SyncEngine() override;
 
-  // Called on the frontend's thread to kick off asynchronous initialization.
-  // Optionally deletes the "Sync Data" folder during init in order to make
-  // sure we're starting fresh.
+  // Kicks off asynchronous initialization. Optionally deletes sync data during
+  // init in order to make sure we're starting fresh.
   //
   // |saved_nigori_state| is optional nigori state to restore from a previous
-  // backend instance. May be null.
+  // engine instance. May be null.
   virtual void Initialize(
-      SyncFrontend* frontend,
+      SyncEngineHost* host,
       scoped_refptr<base::SingleThreadTaskRunner> sync_task_runner,
       const WeakHandle<JsEventHandler>& event_handler,
       const GURL& service_url,
@@ -69,21 +68,19 @@
       std::unique_ptr<SyncEncryptionHandler::NigoriState>
           saved_nigori_state) = 0;
 
-  // Called on the frontend's thread to trigger a refresh.
+  // Inform the engine to trigger a sync cycle for |types|.
   virtual void TriggerRefresh(const ModelTypeSet& types) = 0;
 
-  // Called on the frontend's thread to update SyncCredentials.
+  // Updates the engine's SyncCredentials.
   virtual void UpdateCredentials(const SyncCredentials& credentials) = 0;
 
-  // This starts the SyncerThread running a Syncer object to communicate with
-  // sync servers.  Until this is called, no changes will leave or enter this
+  // This starts the sync engine running a Syncer object to communicate with
+  // sync servers. Until this is called, no changes will leave or enter this
   // browser from the cloud / sync servers.
-  // Called on |frontend_loop_|.
   virtual void StartSyncingWithServer() = 0;
 
-  // Called on |frontend_loop_| to asynchronously set a new passphrase for
-  // encryption. Note that it is an error to call SetEncryptionPassphrase under
-  // the following circumstances:
+  // Asynchronously set a new passphrase for encryption. Note that it is an
+  // error to call SetEncryptionPassphrase under the following circumstances:
   // - An explicit passphrase has already been set
   // - |is_explicit| is true and we have pending keys.
   // When |is_explicit| is false, a couple of things could happen:
@@ -95,21 +92,20 @@
   virtual void SetEncryptionPassphrase(const std::string& passphrase,
                                        bool is_explicit) = 0;
 
-  // Called on |frontend_loop_| to use the provided passphrase to asynchronously
-  // attempt decryption. Returns false immediately if the passphrase could not
-  // be used to decrypt a locally cached copy of encrypted keys; returns true
-  // otherwise. If new encrypted keys arrive during the asynchronous call,
-  // OnPassphraseRequired may be triggered at a later time. It is an error to
-  // call this when there are no pending keys.
+  // Use the provided passphrase to asynchronously attempt decryption. Returns
+  // false immediately if the passphrase could not be used to decrypt a locally
+  // cached copy of encrypted keys; returns true otherwise. If new encrypted
+  // keys arrive during the asynchronous call, OnPassphraseRequired may be
+  // triggered at a later time. It is an error to call this when there are no
+  // pending keys.
   virtual bool SetDecryptionPassphrase(const std::string& passphrase)
       WARN_UNUSED_RESULT = 0;
 
-  // Called on |frontend_loop_| to kick off shutdown procedure.  Attempts to cut
-  // short any long-lived or blocking sync thread tasks so that the shutdown on
-  // sync thread task that we're about to post won't have to wait very long.
+  // Kick off shutdown procedure. Attempts to cut short any long-lived or
+  // blocking sync thread tasks so that the shutdown on sync thread task that
+  // we're about to post won't have to wait very long.
   virtual void StopSyncingForShutdown() = 0;
 
-  // Called on |frontend_loop_| to kick off shutdown.
   // See the implementation and Core::DoShutdown for details.
   // Must be called *after* StopSyncingForShutdown.
   virtual void Shutdown(ShutdownReason reason) = 0;
@@ -124,7 +120,7 @@
   // is non-empty, then an error was encountered).
   // Returns the set of types that are ready to start without needing any
   // further sync activity.
-  // BackendDataTypeConfigurer implementation.
+  // ModelTypeConfigurer implementation.
   ModelTypeSet ConfigureDataTypes(
       ConfigureReason reason,
       const DataTypeConfigStateMap& config_state_map,
@@ -134,9 +130,9 @@
   // Turns on encryption of all present and future sync data.
   virtual void EnableEncryptEverything() = 0;
 
-  // Called on |frontend_loop_| to obtain a handle to the UserShare needed for
-  // creating transactions.  Should not be called before we signal
-  // initialization is complete with OnBackendInitialized().
+  // Obtain a handle to the UserShare needed for creating transactions. Should
+  // not be called before we signal initialization is complete with
+  // OnBackendInitialized().
   virtual UserShare* GetUserShare() const = 0;
 
   // Called from any thread to obtain current status information in detailed or
@@ -199,9 +195,9 @@
   virtual void OnCookieJarChanged(bool account_mismatch, bool empty_jar) = 0;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(SyncBackendHost);
+  DISALLOW_COPY_AND_ASSIGN(SyncEngine);
 };
 
 }  // namespace syncer
 
-#endif  // COMPONENTS_SYNC_DRIVER_GLUE_SYNC_BACKEND_HOST_H_
+#endif  // COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_H_
diff --git a/components/sync/driver/sync_frontend.cc b/components/sync/engine/sync_engine_host.cc
similarity index 62%
rename from components/sync/driver/sync_frontend.cc
rename to components/sync/engine/sync_engine_host.cc
index 9badf6a4..7a19e8c1 100644
--- a/components/sync/driver/sync_frontend.cc
+++ b/components/sync/engine/sync_engine_host.cc
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/sync/driver/sync_frontend.h"
+#include "components/sync/engine/sync_engine_host.h"
 
 namespace syncer {
 
-SyncFrontend::SyncFrontend() {}
-
-SyncFrontend::~SyncFrontend() {}
+SyncEngineHost::SyncEngineHost() {}
+SyncEngineHost::~SyncEngineHost() {}
 
 }  // namespace syncer
diff --git a/components/sync/driver/sync_frontend.h b/components/sync/engine/sync_engine_host.h
similarity index 83%
rename from components/sync/driver/sync_frontend.h
rename to components/sync/engine/sync_engine_host.h
index c68b96a88..55b670b 100644
--- a/components/sync/driver/sync_frontend.h
+++ b/components/sync/engine/sync_engine_host.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 COMPONENTS_SYNC_DRIVER_SYNC_FRONTEND_H_
-#define COMPONENTS_SYNC_DRIVER_SYNC_FRONTEND_H_
+#ifndef COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_HOST_H_
+#define COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_HOST_H_
 
 #include <string>
 
@@ -26,15 +26,13 @@
 struct StatusCounters;
 struct UpdateCounters;
 
-// SyncFrontend is the interface used by SyncBackendHost to communicate with
-// the entity that created it and, presumably, is interested in sync-related
-// activity.
-// NOTE: All methods will be invoked by a SyncBackendHost on the same thread
-// used to create that SyncBackendHost.
-class SyncFrontend {
+// SyncEngineHost is the interface used by SyncEngine to communicate with the
+// entity that created it. It's essentially an observer interface except the
+// SyncEngine always has exactly one.
+class SyncEngineHost {
  public:
-  SyncFrontend();
-  virtual ~SyncFrontend();
+  SyncEngineHost();
+  virtual ~SyncEngineHost();
 
   // The backend has completed initialization and it is now ready to
   // accept and process changes.  If success is false, initialization
@@ -52,11 +50,10 @@
   // The backend queried the server recently and received some updates.
   virtual void OnSyncCycleCompleted() = 0;
 
-  // Informs the frontned of some network event.  These notifications are
-  // disabled by default and must be enabled through an explicit request to the
-  // SyncBackendHost.
+  // Informs the host of some network event. These notifications are disabled by
+  // default and must be enabled through an explicit request to the SyncEngine.
   //
-  // It's disabld by default to avoid copying data across threads when no one
+  // It's disabled by default to avoid copying data across threads when no one
   // is listening for it.
   virtual void OnProtocolEvent(const ProtocolEvent& event) = 0;
 
@@ -91,7 +88,7 @@
   // called when the first sensitive data type is setup by the user and anytime
   // the passphrase is changed by another synced client. |reason| denotes why
   // the passphrase was required. |pending_keys| is a copy of the
-  // cryptographer's pending keys to be passed on to the frontend in order to
+  // cryptographer's pending keys to be passed on to the host in order to
   // be cached.
   virtual void OnPassphraseRequired(
       PassphraseRequiredReason reason,
@@ -124,7 +121,7 @@
   // Called to perform migration of |types|.
   virtual void OnMigrationNeededForTypes(ModelTypeSet types) = 0;
 
-  // Inform the Frontend that new datatypes are available for registration.
+  // Called when new datatypes are available for registration.
   virtual void OnExperimentsChanged(const Experiments& experiments) = 0;
 
   // Called when the sync cycle returns there is an user actionable error.
@@ -141,4 +138,4 @@
 
 }  // namespace syncer
 
-#endif  // COMPONENTS_SYNC_DRIVER_SYNC_FRONTEND_H_
+#endif  // COMPONENTS_SYNC_ENGINE_SYNC_ENGINE_HOST_H_
diff --git a/components/sync/syncable/test_user_share.h b/components/sync/syncable/test_user_share.h
index 78b1405..4c88ce0b 100644
--- a/components/sync/syncable/test_user_share.h
+++ b/components/sync/syncable/test_user_share.h
@@ -68,7 +68,7 @@
   UserShare* user_share();
 
   // Sync's encryption handler. Used by tests to invoke the sync encryption
-  // methods normally handled via the SyncBackendHost
+  // methods normally handled via the SyncEngine.
   SyncEncryptionHandler* encryption_handler();
 
   // Returns the directory's transaction observer.  This transaction observer
diff --git a/components/sync_sessions/session_data_type_controller.cc b/components/sync_sessions/session_data_type_controller.cc
index b40c773..6199758 100644
--- a/components/sync_sessions/session_data_type_controller.cc
+++ b/components/sync_sessions/session_data_type_controller.cc
@@ -6,6 +6,7 @@
 
 #include <set>
 
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/driver/sync_client.h"
 #include "components/sync_sessions/sync_sessions_client.h"
@@ -19,7 +20,11 @@
     syncer::SyncClient* sync_client,
     syncer::LocalDeviceInfoProvider* local_device,
     const char* history_disabled_pref_name)
-    : UIDataTypeController(syncer::SESSIONS, dump_stack, sync_client),
+    : NonUIDataTypeController(syncer::SESSIONS,
+                              dump_stack,
+                              sync_client,
+                              syncer::GROUP_UI,
+                              base::ThreadTaskRunnerHandle::Get()),
       sync_client_(sync_client),
       local_device_(local_device),
       history_disabled_pref_name_(history_disabled_pref_name),
diff --git a/components/sync_sessions/session_data_type_controller.h b/components/sync_sessions/session_data_type_controller.h
index 27cb2409..3a6b6ff 100644
--- a/components/sync_sessions/session_data_type_controller.h
+++ b/components/sync_sessions/session_data_type_controller.h
@@ -10,14 +10,14 @@
 #include "base/macros.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sync/device_info/local_device_info_provider.h"
-#include "components/sync/driver/ui_data_type_controller.h"
+#include "components/sync/driver/non_ui_data_type_controller.h"
 
 namespace sync_sessions {
 
 // Overrides StartModels to avoid sync contention with sessions during
 // a session restore operation at startup and to wait for the local
 // device info to become available.
-class SessionDataTypeController : public syncer::UIDataTypeController {
+class SessionDataTypeController : public syncer::NonUIDataTypeController {
  public:
   // |dump_stack| is called when an unrecoverable error occurs.
   SessionDataTypeController(const base::Closure& dump_stack,
@@ -26,7 +26,7 @@
                             const char* history_disabled_pref_name);
   ~SessionDataTypeController() override;
 
-  // UIDataTypeController implementation.
+  // NonUIDataTypeController implementation.
   bool StartModels() override;
   void StopModels() override;
   bool ReadyForStart() const override;
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index acb6882..04e01b7 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -92,6 +92,7 @@
       local_tab_pool_out_of_sync_(true),
       sync_prefs_(sync_prefs),
       local_device_(local_device),
+      current_device_type_(sync_pb::SyncEnums_DeviceType_TYPE_OTHER),
       local_session_header_node_id_(TabNodePool::kInvalidTabNodeID),
       stale_session_threshold_days_(kDefaultStaleSessionThresholdDays),
       local_event_router_(std::move(router)),
@@ -121,6 +122,19 @@
   error_handler_ = std::move(error_handler);
   sync_processor_ = std::move(sync_processor);
 
+  // SessionDataTypeController ensures that the local device info
+  // is available before activating this datatype.
+  DCHECK(local_device_);
+  const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo();
+  if (!local_device_info) {
+    merge_result.set_error(error_handler_->CreateAndUploadError(
+        FROM_HERE, "Failed to get local device info."));
+    return merge_result;
+  }
+
+  current_session_name_ = local_device_info->client_name();
+  current_device_type_ = local_device_info->device_type();
+
   // It's possible(via RebuildAssociations) for lost_navigations_recorder_ to
   // persist between sync being stopped and started. If it did persist, it's
   // already associated with |sync_processor|, so leave it alone.
@@ -136,19 +150,7 @@
   // a conveniently safe time to assert sync is ready and the cache_guid is
   // initialized.
   if (current_machine_tag_.empty()) {
-    InitializeCurrentMachineTag();
-  }
-
-  // SessionDataTypeController ensures that the local device info
-  // is available before activating this datatype.
-  DCHECK(local_device_);
-  const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo();
-  if (local_device_info) {
-    current_session_name_ = local_device_info->client_name();
-  } else {
-    merge_result.set_error(error_handler_->CreateAndUploadError(
-        FROM_HERE, "Failed to get local device info."));
-    return merge_result;
+    InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID());
   }
 
   session_tracker_.SetLocalSessionTag(current_machine_tag_);
@@ -164,7 +166,7 @@
     base_specifics->set_session_tag(current_machine_tag());
     sync_pb::SessionHeader* header_s = base_specifics->mutable_header();
     header_s->set_client_name(current_session_name_);
-    header_s->set_device_type(local_device_info->device_type());
+    header_s->set_device_type(current_device_type_);
     syncer::SyncData data = syncer::SyncData::CreateLocalData(
         current_machine_tag(), current_session_name_, specifics);
     new_changes.push_back(
@@ -200,11 +202,7 @@
   SyncedSession* current_session = session_tracker_.GetSession(local_tag);
   current_session->modified_time = base::Time::Now();
   header_s->set_client_name(current_session_name_);
-  // SessionDataTypeController ensures that the local device info
-  // is available before activating this datatype.
-  DCHECK(local_device_);
-  const DeviceInfo* local_device_info = local_device_->GetLocalDeviceInfo();
-  header_s->set_device_type(local_device_info->device_type());
+  header_s->set_device_type(current_device_type_);
 
   session_tracker_.ResetSessionTracking(local_tag);
   std::set<const SyncedWindowDelegate*> windows =
@@ -389,7 +387,7 @@
       base::Time::Now();
 }
 
-void SessionsSyncManager::RebuildAssociations() {
+bool SessionsSyncManager::RebuildAssociations() {
   syncer::SyncDataList data(sync_processor_->GetAllSyncData(syncer::SESSIONS));
   std::unique_ptr<syncer::SyncErrorFactory> error_handler(
       std::move(error_handler_));
@@ -397,8 +395,9 @@
       std::move(sync_processor_));
 
   StopSyncing(syncer::SESSIONS);
-  MergeDataAndStartSyncing(syncer::SESSIONS, data, std::move(processor),
-                           std::move(error_handler));
+  syncer::SyncMergeResult merge_result = MergeDataAndStartSyncing(
+      syncer::SESSIONS, data, std::move(processor), std::move(error_handler));
+  return !merge_result.error().IsSet();
 }
 
 bool SessionsSyncManager::IsValidSessionHeader(
@@ -434,8 +433,8 @@
   if (local_tab_pool_out_of_sync_) {
     // If our tab pool is corrupt, pay the price of a full re-association to
     // fix things up.  This takes care of the new tab modification as well.
-    RebuildAssociations();
-    DCHECK(!local_tab_pool_out_of_sync_);
+    bool rebuild_association_succeeded = RebuildAssociations();
+    DCHECK(!rebuild_association_succeeded || !local_tab_pool_out_of_sync_);
     return;
   }
 
@@ -767,7 +766,8 @@
   }
 }
 
-void SessionsSyncManager::InitializeCurrentMachineTag() {
+void SessionsSyncManager::InitializeCurrentMachineTag(
+    const std::string& cache_guid) {
   DCHECK(current_machine_tag_.empty());
   std::string persisted_guid;
   persisted_guid = sync_prefs_->GetSyncSessionsGUID();
@@ -775,8 +775,6 @@
     current_machine_tag_ = persisted_guid;
     DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
   } else {
-    DCHECK(local_device_);
-    std::string cache_guid = local_device_->GetLocalSyncCacheGUID();
     DCHECK(!cache_guid.empty());
     current_machine_tag_ = BuildMachineTag(cache_guid);
     DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 5585bbf..5f2b5981 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -180,7 +180,7 @@
                            ProcessRemoteDeleteOfLocalSession);
   FRIEND_TEST_ALL_PREFIXES(SessionsSyncManagerTest, SetVariationIds);
 
-  void InitializeCurrentMachineTag();
+  void InitializeCurrentMachineTag(const std::string& cache_guid);
 
   // Load and add window or tab data for a foreign session to our internal
   // tracking.
@@ -299,9 +299,10 @@
       const syncer::SyncDataList& restored_tabs,
       syncer::SyncChangeList* change_output);
 
-  // Stops and re-starts syncing to rebuild association mappings.
+  // Stops and re-starts syncing to rebuild association mappings. Returns true
+  // when re-starting succeeds.
   // See |local_tab_pool_out_of_sync_|.
-  void RebuildAssociations();
+  bool RebuildAssociations();
 
   // Validates the content of a SessionHeader protobuf.
   // Returns false if validation fails.
@@ -351,8 +352,9 @@
   // Unique client tag.
   std::string current_machine_tag_;
 
-  // User-visible machine name.
+  // User-visible machine name and device type to populate header.
   std::string current_session_name_;
+  sync_pb::SyncEnums::DeviceType current_device_type_;
 
   // SyncID for the sync node containing all the window information for this
   // client.
diff --git a/content/browser/appcache/appcache_request_handler_unittest.cc b/content/browser/appcache/appcache_request_handler_unittest.cc
index 8367bc8b1..98d4c6bf 100644
--- a/content/browser/appcache/appcache_request_handler_unittest.cc
+++ b/content/browser/appcache/appcache_request_handler_unittest.cc
@@ -215,7 +215,9 @@
   void SetUpTest() {
     DCHECK(io_thread_->task_runner()->BelongsToCurrentThread());
     mock_service_.reset(new MockAppCacheService);
-    mock_service_->set_request_context(&empty_context_);
+    // Initializes URLRequestContext on the IO thread.
+    empty_context_.reset(new net::URLRequestContext);
+    mock_service_->set_request_context(empty_context_.get());
     mock_policy_.reset(new MockAppCachePolicy);
     mock_service_->set_appcache_policy(mock_policy_.get());
     mock_frontend_.reset(new MockFrontend);
@@ -226,7 +228,7 @@
     backend_impl_->RegisterHost(kHostId);
     host_ = backend_impl_->GetHost(kHostId);
     job_factory_.reset(new MockURLRequestJobFactory());
-    empty_context_.set_job_factory(job_factory_.get());
+    empty_context_->set_job_factory(job_factory_.get());
   }
 
   void TearDownTest() {
@@ -239,6 +241,7 @@
     mock_service_.reset();
     mock_policy_.reset();
     job_factory_.reset();
+    empty_context_.reset();
     host_ = NULL;
   }
 
@@ -277,8 +280,8 @@
         base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Miss,
                    base::Unretained(this)));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -325,8 +328,8 @@
         base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Hit,
                    base::Unretained(this)));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -375,8 +378,8 @@
         base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Fallback,
                    base::Unretained(this)));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -457,9 +460,9 @@
         &AppCacheRequestHandlerTest::Verify_MainResource_FallbackOverride,
         base::Unretained(this)));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/fallback-override"), net::DEFAULT_PRIORITY,
-        &delegate_);
+    request_ =
+        empty_context_->CreateRequest(GURL("http://blah/fallback-override"),
+                                      net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -523,8 +526,8 @@
   // SubResource_Miss_WithNoCacheSelected ----------------------------------
 
   void SubResource_Miss_WithNoCacheSelected() {
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -543,8 +546,8 @@
     // in a network or fallback namespace, should result in a failed request.
     host_->AssociateCompleteCache(MakeNewCache());
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -575,8 +578,8 @@
     host_->pending_selected_cache_id_ = cache->cache_id();
     host_->set_preferred_manifest_url(cache->owning_group()->manifest_url());
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -610,8 +613,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -643,8 +646,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -677,8 +680,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(), AppCacheEntry(AppCacheEntry::EXPLICIT, 1), false);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -712,8 +715,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(), AppCacheEntry(), true);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -742,8 +745,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -770,8 +773,8 @@
     // Precondition, the host is waiting on cache selection.
     host_->pending_selected_cache_id_ = 1;
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -806,8 +809,8 @@
     mock_storage()->SimulateFindSubResource(
         AppCacheEntry(AppCacheEntry::EXPLICIT, 1), AppCacheEntry(), false);
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -836,8 +839,8 @@
   }
 
   void DestroyedServiceWithCrossSiteNav() {
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -870,8 +873,8 @@
     // Precondition, the host is waiting on cache selection.
     host_->pending_selected_cache_id_ = 1;
 
-    request_ = empty_context_.CreateRequest(
-        GURL("ftp://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("ftp://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_SUB_RESOURCE,
                                                false));
@@ -892,8 +895,8 @@
   // CanceledRequest -----------------------------
 
   void CanceledRequest() {
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -933,8 +936,8 @@
     EXPECT_FALSE(AppCacheRequestHandler::IsMainResourceType(
         RESOURCE_TYPE_WORKER));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
 
     const int kParentHostId = host_->host_id();
     const int kWorkerHostId = 2;
@@ -971,8 +974,8 @@
         base::Bind(&AppCacheRequestHandlerTest::Verify_MainResource_Blocked,
                    base::Unretained(this)));
 
-    request_ = empty_context_.CreateRequest(
-        GURL("http://blah/"), net::DEFAULT_PRIORITY, &delegate_);
+    request_ = empty_context_->CreateRequest(GURL("http://blah/"),
+                                             net::DEFAULT_PRIORITY, &delegate_);
     handler_.reset(host_->CreateRequestHandler(request_.get(),
                                                RESOURCE_TYPE_MAIN_FRAME,
                                                false));
@@ -1033,7 +1036,7 @@
   std::unique_ptr<MockFrontend> mock_frontend_;
   std::unique_ptr<MockAppCachePolicy> mock_policy_;
   AppCacheHost* host_;
-  net::URLRequestContext empty_context_;
+  std::unique_ptr<net::URLRequestContext> empty_context_;
   std::unique_ptr<MockURLRequestJobFactory> job_factory_;
   MockURLRequestDelegate delegate_;
   std::unique_ptr<net::URLRequest> request_;
diff --git a/content/browser/blob_storage/blob_flattener_unittest.cc b/content/browser/blob_storage/blob_flattener_unittest.cc
index 3e70dffc..b67066a 100644
--- a/content/browser/blob_storage/blob_flattener_unittest.cc
+++ b/content/browser/blob_storage/blob_flattener_unittest.cc
@@ -6,9 +6,11 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/test_simple_task_runner.h"
@@ -17,6 +19,7 @@
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/blob_entry.h"
+#include "storage/browser/blob/blob_memory_controller.h"
 #include "storage/browser/blob/blob_storage_registry.h"
 #include "storage/browser/blob/shareable_blob_data_item.h"
 #include "storage/common/data_element.h"
@@ -25,9 +28,26 @@
 namespace storage {
 namespace {
 using base::TestSimpleTaskRunner;
+using FileCreationInfo = BlobMemoryController::FileCreationInfo;
 
 const char kType[] = "type";
 const char kDisposition[] = "";
+const size_t kTestBlobStorageIPCThresholdBytes = 20;
+const size_t kTestBlobStorageMaxSharedMemoryBytes = 50;
+
+const size_t kTestBlobStorageMaxBlobMemorySize = 400;
+const uint64_t kTestBlobStorageMaxDiskSpace = 4000;
+const uint64_t kTestBlobStorageMinFileSizeBytes = 10;
+const uint64_t kTestBlobStorageMaxFileSizeBytes = 100;
+
+void SaveBlobStatusAndFiles(BlobStatus* status_ptr,
+                            std::vector<FileCreationInfo>* files_ptr,
+                            BlobStatus status,
+                            std::vector<FileCreationInfo> files) {
+  EXPECT_FALSE(BlobStatusIsError(status));
+  *status_ptr = status;
+  std::move(files.begin(), files.end(), std::back_inserter(*files_ptr));
+}
 
 }  // namespace
 
@@ -39,11 +59,15 @@
       : fake_file_path_(base::FilePath(FILE_PATH_LITERAL("kFakePath"))) {}
   ~BlobFlattenerTest() override {}
 
-  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    context_ = base::MakeUnique<BlobStorageContext>();
+  }
 
   void TearDown() override {
     base::RunLoop().RunUntilIdle();
     file_runner_->RunPendingTasks();
+    base::RunLoop().RunUntilIdle();
     ASSERT_TRUE(temp_dir_.Delete());
   }
 
@@ -66,14 +90,21 @@
     return scoped_refptr<BlobDataItem>(new BlobDataItem(std::move(element)));
   };
 
+  scoped_refptr<BlobDataItem> CreateFutureFileItem(size_t offset, size_t size) {
+    std::unique_ptr<DataElement> element(new DataElement());
+    element->SetToFilePathRange(BlobDataBuilder::GetFutureFileItemPath(0),
+                                offset, size, base::Time());
+    return scoped_refptr<BlobDataItem>(new BlobDataItem(std::move(element)));
+  };
+
   std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) {
     BlobDataBuilder builder(id);
     builder.AppendData("1", 1);
     builder.set_content_type("text/plain");
-    return context_.AddFinishedBlob(builder);
+    return context_->AddFinishedBlob(builder);
   }
 
-  BlobStorageRegistry* registry() { return context_.mutable_registry(); }
+  BlobStorageRegistry* registry() { return context_->mutable_registry(); }
 
   const ShareableBlobDataItem& GetItemInBlob(const std::string& uuid,
                                              size_t index) {
@@ -82,12 +113,23 @@
     return *entry->items()[index];
   }
 
+  void SetTestMemoryLimits() {
+    BlobStorageLimits limits;
+    limits.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
+    limits.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
+    limits.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
+    limits.max_blob_disk_space = kTestBlobStorageMaxDiskSpace;
+    limits.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
+    limits.max_file_size = kTestBlobStorageMaxFileSizeBytes;
+    context_->mutable_memory_controller()->set_limits_for_testing(limits);
+  }
+
   base::FilePath fake_file_path_;
   base::ScopedTempDir temp_dir_;
   scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner();
 
   base::MessageLoop fake_io_message_loop;
-  BlobStorageContext context_;
+  std::unique_ptr<BlobStorageContext> context_;
 };
 
 TEST_F(BlobFlattenerTest, NoBlobItems) {
@@ -103,7 +145,7 @@
   EXPECT_EQ(0u, flattener.dependent_blobs.size());
   EXPECT_EQ(0u, flattener.copies.size());
   EXPECT_EQ(12u, flattener.total_size);
-  EXPECT_EQ(2u, flattener.memory_quota_needed);
+  EXPECT_EQ(2u, flattener.transport_quota_needed);
 
   ASSERT_EQ(2u, output.items().size());
   EXPECT_EQ(*CreateDataItem("hi", 2u), *output.items()[0]->item());
@@ -147,6 +189,7 @@
   const std::string kBlobUUID = "kId";
   const std::string kDataBlob = "kId2";
   const std::string kFileBlob = "kId3";
+  const std::string kPendingFileBlob = "kId4";
 
   // We have the following:
   // * data,
@@ -155,19 +198,35 @@
   // * full data blob,
   // * pending data,
 
+  context_ =
+      base::MakeUnique<BlobStorageContext>(temp_dir_.GetPath(), file_runner_);
+  SetTestMemoryLimits();
+
   std::unique_ptr<BlobDataHandle> data_blob;
   {
     BlobDataBuilder builder(kDataBlob);
     builder.AppendData("12345", 5);
     builder.set_content_type("text/plain");
-    data_blob = context_.AddFinishedBlob(builder);
+    data_blob = context_->AddFinishedBlob(builder);
   }
 
   std::unique_ptr<BlobDataHandle> file_blob;
   {
     BlobDataBuilder builder(kFileBlob);
     builder.AppendFile(fake_file_path_, 1u, 10u, base::Time::Max());
-    file_blob = context_.AddFinishedBlob(builder);
+    file_blob = context_->AddFinishedBlob(builder);
+  }
+
+  BlobStatus file_status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+  std::vector<FileCreationInfo> file_handles;
+  std::unique_ptr<BlobDataHandle> future_file_blob;
+  {
+    BlobDataBuilder builder(kPendingFileBlob);
+    builder.AppendFutureFile(0u, 2u, 0);
+    builder.AppendFutureFile(2u, 5u, 0);
+    future_file_blob = context_->BuildBlob(
+        builder,
+        base::Bind(&SaveBlobStatusAndFiles, &file_status, &file_handles));
   }
 
   BlobDataBuilder builder(kBlobUUID);
@@ -177,28 +236,47 @@
   builder.AppendBlob(kDataBlob);
   builder.AppendBlob(kFileBlob, 1u, 3u);
   builder.AppendFutureData(12u);
+  builder.AppendBlob(kPendingFileBlob, 1u, 3u);
 
   BlobEntry output(kType, kDisposition);
   BlobFlattener flattener(builder, &output, registry());
   EXPECT_EQ(BlobStatus::PENDING_QUOTA, flattener.status);
 
-  EXPECT_EQ(2u, flattener.dependent_blobs.size());
-  EXPECT_EQ(29u, flattener.total_size);
-  EXPECT_EQ(16u, flattener.memory_quota_needed);
+  EXPECT_EQ(3u, flattener.dependent_blobs.size());
+  EXPECT_EQ(32u, flattener.total_size);
+  EXPECT_EQ(14u, flattener.transport_quota_needed);
+  EXPECT_EQ(2u, flattener.copy_quota_needed);
 
-  ASSERT_EQ(6u, output.items().size());
+  ASSERT_EQ(8u, output.items().size());
   EXPECT_EQ(*CreateDataItem("hi", 2u), *output.items()[0]->item());
   EXPECT_EQ(*CreateDataDescriptionItem(2u), *output.items()[1]->item());
   EXPECT_EQ(*CreateFileItem(3u, 5u), *output.items()[2]->item());
   EXPECT_EQ(GetItemInBlob(kDataBlob, 0), *output.items()[3]);
   EXPECT_EQ(*CreateFileItem(2u, 3u), *output.items()[4]->item());
   EXPECT_EQ(*CreateDataDescriptionItem(12u), *output.items()[5]->item());
+  EXPECT_EQ(*CreateFutureFileItem(1u, 1u), *output.items()[6]->item());
+  EXPECT_EQ(*CreateFutureFileItem(2u, 2u), *output.items()[7]->item());
 
-  // We're copying item at index 1
-  ASSERT_EQ(1u, flattener.copies.size());
+  // We're copying items at index 1, 6, and 7.
+  ASSERT_EQ(3u, flattener.copies.size());
   EXPECT_EQ(*flattener.copies[0].dest_item, *output.items()[1]);
   EXPECT_EQ(GetItemInBlob(kDataBlob, 0), *flattener.copies[0].source_item);
   EXPECT_EQ(1u, flattener.copies[0].source_item_offset);
+  EXPECT_EQ(*flattener.copies[1].dest_item, *output.items()[6]);
+  EXPECT_EQ(GetItemInBlob(kPendingFileBlob, 0),
+            *flattener.copies[1].source_item);
+  EXPECT_EQ(1u, flattener.copies[1].source_item_offset);
+  EXPECT_EQ(*flattener.copies[2].dest_item, *output.items()[7]);
+  EXPECT_EQ(GetItemInBlob(kPendingFileBlob, 1),
+            *flattener.copies[2].source_item);
+  EXPECT_EQ(0u, flattener.copies[2].source_item_offset);
+
+  // Clean up temp files.
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  file_runner_->RunPendingTasks();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, file_status);
+  EXPECT_FALSE(file_handles.empty());
 }
 
 }  // namespace storage
diff --git a/content/browser/blob_storage/blob_memory_controller_unittest.cc b/content/browser/blob_storage/blob_memory_controller_unittest.cc
index 290a40be..ae0e796c 100644
--- a/content/browser/blob_storage/blob_memory_controller_unittest.cc
+++ b/content/browser/blob_storage/blob_memory_controller_unittest.cc
@@ -74,7 +74,7 @@
     controller->set_limits_for_testing(limits);
   }
 
-  void SaveFileCreationInfo(bool success, std::vector<FileCreationInfo> info) {
+  void SaveFileCreationInfo(std::vector<FileCreationInfo> info, bool success) {
     file_quota_result_ = success;
     if (success) {
       files_created_.swap(info);
diff --git a/content/browser/blob_storage/blob_slice_unittest.cc b/content/browser/blob_storage/blob_slice_unittest.cc
index e7266fd3..97d2bd0 100644
--- a/content/browser/blob_storage/blob_slice_unittest.cc
+++ b/content/browser/blob_storage/blob_slice_unittest.cc
@@ -48,6 +48,16 @@
         ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA));
   };
 
+  scoped_refptr<ShareableBlobDataItem> CreateTempFileItem(size_t offset,
+                                                          size_t size) {
+    std::unique_ptr<DataElement> element(new DataElement());
+    element->SetToFilePathRange(BlobDataBuilder::GetFutureFileItemPath(0),
+                                offset, size, base::Time());
+    return scoped_refptr<ShareableBlobDataItem>(
+        new ShareableBlobDataItem(new BlobDataItem(std::move(element)),
+                                  ShareableBlobDataItem::QUOTA_NEEDED));
+  };
+
   void ExpectFirstSlice(const BlobSlice& slice,
                         scoped_refptr<ShareableBlobDataItem> source_item,
                         size_t first_item_slice_offset,
@@ -56,8 +66,10 @@
     EXPECT_EQ(first_item_slice_offset, slice.first_item_slice_offset);
 
     ASSERT_LE(1u, slice.dest_items.size());
-    const DataElement& dest_element =
-        slice.dest_items[0]->item()->data_element();
+
+    scoped_refptr<ShareableBlobDataItem> item = slice.dest_items[0];
+    EXPECT_EQ(ShareableBlobDataItem::QUOTA_NEEDED, item->state());
+    const DataElement& dest_element = item->item()->data_element();
 
     EXPECT_EQ(DataElement::TYPE_BYTES_DESCRIPTION, dest_element.type());
     EXPECT_EQ(static_cast<uint64_t>(size), dest_element.length());
@@ -71,8 +83,9 @@
     EXPECT_TRUE(slice.last_source_item);
 
     ASSERT_LE(2u, slice.dest_items.size());
-    const DataElement& dest_element =
-        slice.dest_items.back()->item()->data_element();
+    scoped_refptr<ShareableBlobDataItem> item = slice.dest_items.back();
+    EXPECT_EQ(ShareableBlobDataItem::QUOTA_NEEDED, item->state());
+    const DataElement& dest_element = item->item()->data_element();
 
     EXPECT_EQ(DataElement::TYPE_BYTES_DESCRIPTION, dest_element.type());
     EXPECT_EQ(static_cast<uint64_t>(size), dest_element.length());
@@ -82,7 +95,6 @@
 };
 
 TEST_F(BlobSliceTest, FullItem) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize = 5u;
 
   BlobEntry data(kType, kDisposition);
@@ -100,7 +112,6 @@
 }
 
 TEST_F(BlobSliceTest, SliceSingleItem) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize = 5u;
 
   BlobEntry data(kType, kDisposition);
@@ -115,7 +126,6 @@
 }
 
 TEST_F(BlobSliceTest, SliceSingleLastItem) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize1 = 5u;
   const size_t kSize2 = 10u;
 
@@ -132,7 +142,6 @@
 }
 
 TEST_F(BlobSliceTest, SliceAcrossTwoItems) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize1 = 5u;
   const size_t kSize2 = 10u;
 
@@ -150,7 +159,6 @@
 }
 
 TEST_F(BlobSliceTest, SliceFileAndLastItem) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize1 = 5u;
   const size_t kSize2 = 10u;
 
@@ -170,7 +178,6 @@
 }
 
 TEST_F(BlobSliceTest, SliceAcrossLargeItem) {
-  const std::string kBlobUUID = "kId";
   const size_t kSize1 = 5u;
   const size_t kSize2 = 10u;
   const size_t kSize3 = 10u;
@@ -192,4 +199,23 @@
   EXPECT_EQ(*item2, *slice.dest_items[1]);
 }
 
+TEST_F(BlobSliceTest, SliceTempFileItem) {
+  BlobEntry data(kType, kDisposition);
+  scoped_refptr<ShareableBlobDataItem> item1 = CreateTempFileItem(1u, 10u);
+  data.AppendSharedBlobItem(item1);
+  BlobSlice slice(data, 2, 5);
+  EXPECT_EQ(0u, slice.copying_memory_size.ValueOrDie());
+  EXPECT_TRUE(slice.first_source_item);
+  EXPECT_EQ(2u, slice.first_item_slice_offset);
+  ASSERT_LE(1u, slice.dest_items.size());
+  scoped_refptr<ShareableBlobDataItem> item = slice.dest_items[0];
+  EXPECT_EQ(ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA, item->state());
+
+  const DataElement& dest_element = item->item()->data_element();
+  EXPECT_EQ(DataElement::TYPE_FILE, dest_element.type());
+  EXPECT_EQ(static_cast<uint64_t>(5), dest_element.length());
+  EXPECT_EQ(*item1, *slice.first_source_item);
+  ASSERT_EQ(1u, slice.dest_items.size());
+}
+
 }  // namespace storage
diff --git a/content/browser/blob_storage/blob_storage_browsertest.cc b/content/browser/blob_storage/blob_storage_browsertest.cc
new file mode 100644
index 0000000..fdcf7da
--- /dev/null
+++ b/content/browser/blob_storage/blob_storage_browsertest.cc
@@ -0,0 +1,103 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/run_loop.h"
+#include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+#include "storage/browser/blob/blob_memory_controller.h"
+#include "storage/browser/blob/blob_storage_context.h"
+#include "storage/common/blob_storage/blob_storage_constants.h"
+
+namespace content {
+namespace {
+const size_t kTestBlobStorageIPCThresholdBytes = 5;
+const size_t kTestBlobStorageMaxSharedMemoryBytes = 10;
+
+const size_t kTestBlobStorageMaxBlobMemorySize = 200;
+const uint64_t kTestBlobStorageMaxDiskSpace = 3000;
+const uint64_t kTestBlobStorageMinFileSizeBytes = 20;
+const uint64_t kTestBlobStorageMaxFileSizeBytes = 50;
+}  // namespace
+
+// This browser test is aimed towards exercising the blob storage transportation
+// strategies and paging memory to disk.
+class BlobStorageBrowserTest : public ContentBrowserTest {
+ public:
+  BlobStorageBrowserTest() {
+    limits_.max_ipc_memory_size = kTestBlobStorageIPCThresholdBytes;
+    limits_.max_shared_memory_size = kTestBlobStorageMaxSharedMemoryBytes;
+    limits_.max_blob_in_memory_space = kTestBlobStorageMaxBlobMemorySize;
+    limits_.max_blob_disk_space = kTestBlobStorageMaxDiskSpace;
+    limits_.min_page_file_size = kTestBlobStorageMinFileSizeBytes;
+    limits_.max_file_size = kTestBlobStorageMaxFileSizeBytes;
+  }
+
+  void SetBlobLimits() {
+    GetMemoryController()->set_limits_for_testing(limits_);
+  }
+
+  storage::BlobMemoryController* GetMemoryController() {
+    content::ChromeBlobStorageContext* blob_context =
+        ChromeBlobStorageContext::GetFor(
+            shell()->web_contents()->GetBrowserContext());
+    return blob_context->context()->mutable_memory_controller();
+  }
+
+  void SimpleTest(const GURL& test_url, bool incognito = false) {
+    // The test page will perform tests on blob storage, then navigate to either
+    // a #pass or #fail ref.
+    Shell* the_browser = incognito ? CreateOffTheRecordBrowser() : shell();
+
+    VLOG(0) << "Navigating to URL and blocking. " << test_url.spec();
+    NavigateToURLBlockUntilNavigationsComplete(the_browser, test_url, 2);
+    VLOG(0) << "Navigation done.";
+    std::string result =
+        the_browser->web_contents()->GetLastCommittedURL().ref();
+    if (result != "pass") {
+      std::string js_result;
+      ASSERT_TRUE(ExecuteScriptAndExtractString(
+          the_browser, "window.domAutomationController.send(getLog())",
+          &js_result));
+      FAIL() << "Failed: " << js_result;
+    }
+  }
+
+ protected:
+  storage::BlobStorageLimits limits_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlobStorageBrowserTest);
+};
+
+IN_PROC_BROWSER_TEST_F(BlobStorageBrowserTest, BlobCombinations) {
+  SetBlobLimits();
+  SimpleTest(GetTestUrl("blob_storage", "blob_creation_and_slicing.html"));
+  storage::BlobMemoryController* memory_controller = GetMemoryController();
+  // Our exact usages depend on IPC message ordering & garbage collection.
+  // Since this is basically random, we just check bounds.
+  EXPECT_LT(0u, memory_controller->memory_usage());
+  EXPECT_LT(0ul, memory_controller->disk_usage());
+  EXPECT_GT(memory_controller->disk_usage(),
+            static_cast<uint64_t>(memory_controller->memory_usage()));
+  EXPECT_GT(limits_.max_blob_in_memory_space,
+            memory_controller->memory_usage());
+  EXPECT_GT(limits_.max_blob_disk_space, memory_controller->disk_usage());
+  shell()->Close();
+
+  // Make sure we run all file / io tasks.
+  base::RunLoop().RunUntilIdle();
+  BrowserThread::GetBlockingPool()->FlushForTesting();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0u, memory_controller->memory_usage());
+  EXPECT_EQ(0ul, memory_controller->disk_usage());
+}
+
+}  // namespace content
diff --git a/content/browser/blob_storage/blob_storage_context_unittest.cc b/content/browser/blob_storage/blob_storage_context_unittest.cc
index 166509e7..5ac28ca9 100644
--- a/content/browser/blob_storage/blob_storage_context_unittest.cc
+++ b/content/browser/blob_storage/blob_storage_context_unittest.cc
@@ -99,12 +99,18 @@
                             std::vector<FileCreationInfo>* files_ptr,
                             BlobStatus status,
                             std::vector<FileCreationInfo> files) {
+  EXPECT_FALSE(BlobStatusIsError(status));
   *status_ptr = status;
   for (FileCreationInfo& info : files) {
     files_ptr->push_back(std::move(info));
   }
 }
 
+void IncrementNumber(size_t* number, BlobStatus status) {
+  EXPECT_EQ(BlobStatus::DONE, status);
+  *number = *number + 1;
+}
+
 }  // namespace
 
 class BlobStorageContextTest : public testing::Test {
@@ -112,7 +118,16 @@
   BlobStorageContextTest() {}
   ~BlobStorageContextTest() override {}
 
-  void SetUp() override { context_ = base::MakeUnique<BlobStorageContext>(); }
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    context_ = base::MakeUnique<BlobStorageContext>();
+  }
+
+  void TearDown() override {
+    base::RunLoop().RunUntilIdle();
+    file_runner_->RunPendingTasks();
+    ASSERT_TRUE(temp_dir_.Delete());
+  }
 
   std::unique_ptr<BlobDataHandle> SetupBasicBlob(const std::string& id) {
     BlobDataBuilder builder(id);
@@ -141,6 +156,8 @@
   }
 
   std::vector<FileCreationInfo> files_;
+  base::ScopedTempDir temp_dir_;
+  scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner();
 
   base::MessageLoop fake_io_message_loop_;
   std::unique_ptr<BlobStorageContext> context_;
@@ -511,6 +528,60 @@
   base::RunLoop().RunUntilIdle();
 }
 
+TEST_F(BlobStorageContextTest, BuildFutureFileOnlyBlob) {
+  const std::string kId1("id1");
+  context_ =
+      base::MakeUnique<BlobStorageContext>(temp_dir_.GetPath(), file_runner_);
+  SetTestMemoryLimits();
+
+  BlobDataBuilder builder(kId1);
+  builder.set_content_type("text/plain");
+  builder.AppendFutureFile(0, 10, 0);
+
+  BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+  std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
+      builder, base::Bind(&SaveBlobStatusAndFiles, &status, &files_));
+
+  size_t blobs_finished = 0;
+  EXPECT_EQ(BlobStatus::PENDING_QUOTA, handle->GetBlobStatus());
+  EXPECT_EQ(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS, status);
+  handle->RunOnConstructionComplete(
+      base::Bind(&IncrementNumber, &blobs_finished));
+  EXPECT_EQ(0u, blobs_finished);
+
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  file_runner_->RunPendingTasks();
+  EXPECT_EQ(0u, blobs_finished);
+  EXPECT_EQ(BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS, status);
+  EXPECT_EQ(BlobStatus::PENDING_QUOTA, handle->GetBlobStatus());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, status);
+  EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, handle->GetBlobStatus());
+  EXPECT_EQ(0u, blobs_finished);
+
+  ASSERT_EQ(1u, files_.size());
+
+  builder.PopulateFutureFile(0, files_[0].file_reference, base::Time::Max());
+  context_->NotifyTransportComplete(kId1);
+
+  EXPECT_EQ(BlobStatus::DONE, handle->GetBlobStatus());
+  EXPECT_EQ(0u, blobs_finished);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(1u, blobs_finished);
+
+  builder.Clear();
+  handle.reset();
+  files_.clear();
+  base::RunLoop().RunUntilIdle();
+  // We should have file cleanup tasks.
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  file_runner_->RunPendingTasks();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
+  EXPECT_EQ(0lu, context_->memory_controller().disk_usage());
+}
+
 TEST_F(BlobStorageContextTest, CompoundBlobs) {
   const std::string kId1("id1");
   const std::string kId2("id2");
@@ -655,6 +726,171 @@
   EXPECT_FALSE(context_->registry().HasEntry(kReferencingId));
 }
 
-// TODO(michaeln): tests for the depcrecated url stuff
+namespace {
+constexpr size_t kTotalRawBlobs = 200;
+constexpr size_t kTotalSlicedBlobs = 100;
+constexpr char kTestDiskCacheData[] = "Test Blob Data";
 
-}  // namespace content
+// Appends data and data types that depend on the index. This is designed to
+// exercise all types of combinations of data, future data, files, future files,
+// and disk cache entries.
+size_t AppendDataInBuilder(BlobDataBuilder* builder,
+                           size_t index,
+                           disk_cache::Entry* cache_entry) {
+  size_t size = 0;
+  // We can't have both future data and future files, so split those up.
+  if (index % 2 != 0) {
+    builder->AppendFutureData(5u);
+    size += 5u;
+    if (index % 3 == 1) {
+      builder->AppendData("abcdefghij", 4u);
+      size += 4u;
+    }
+    if (index % 3 == 0) {
+      builder->AppendFutureData(1u);
+      size += 1u;
+    }
+  } else if (index % 3 == 0) {
+    builder->AppendFutureFile(0lu, 3lu, 0);
+    size += 3u;
+  }
+  if (index % 5 != 0) {
+    builder->AppendFile(
+        base::FilePath::FromUTF8Unsafe(base::SizeTToString(index)), 0ul, 20ul,
+        base::Time::Max());
+    size += 20u;
+  }
+  if (index % 3 != 0) {
+    scoped_refptr<BlobDataBuilder::DataHandle> disk_cache_data_handle =
+        new EmptyDataHandle();
+    builder->AppendDiskCacheEntry(disk_cache_data_handle, cache_entry,
+                                  kTestDiskCacheStreamIndex);
+    size += strlen(kTestDiskCacheData);
+  }
+  return size;
+}
+
+bool DoesBuilderHaveFutureData(size_t index) {
+  return index < kTotalRawBlobs && (index % 2 != 0 || index % 3 == 0);
+}
+
+void PopulateDataInBuilder(BlobDataBuilder* builder,
+                           size_t index,
+                           base::TaskRunner* file_runner) {
+  if (index % 2 != 0) {
+    builder->PopulateFutureData(0, "abcde", 0, 5);
+    if (index % 3 == 0) {
+      builder->PopulateFutureData(1, "z", 0, 1);
+    }
+  } else if (index % 3 == 0) {
+    scoped_refptr<ShareableFileReference> file_ref =
+        ShareableFileReference::GetOrCreate(
+            base::FilePath::FromUTF8Unsafe(
+                base::SizeTToString(index + kTotalRawBlobs)),
+            ShareableFileReference::DONT_DELETE_ON_FINAL_RELEASE, file_runner);
+    builder->PopulateFutureFile(0, file_ref, base::Time::Max());
+  }
+}
+}  // namespace
+
+TEST_F(BlobStorageContextTest, BuildBlobCombinations) {
+  const std::string kId("id");
+
+  context_ =
+      base::MakeUnique<BlobStorageContext>(temp_dir_.GetPath(), file_runner_);
+
+  SetTestMemoryLimits();
+  std::unique_ptr<disk_cache::Backend> cache = CreateInMemoryDiskCache();
+  ASSERT_TRUE(cache);
+  disk_cache::ScopedEntryPtr entry =
+      CreateDiskCacheEntry(cache.get(), "test entry", kTestDiskCacheData);
+
+  // This tests mixed blob content with both synchronous and asynchronous
+  // construction. Blobs should also be paged to disk during execution.
+  std::vector<std::unique_ptr<BlobDataBuilder>> builders;
+  std::vector<size_t> sizes;
+  for (size_t i = 0; i < kTotalRawBlobs; i++) {
+    builders.emplace_back(new BlobDataBuilder(base::SizeTToString(i)));
+    auto& builder = *builders.back();
+    size_t size = AppendDataInBuilder(&builder, i, entry.get());
+    EXPECT_NE(0u, size);
+    sizes.push_back(size);
+  }
+
+  for (size_t i = 0; i < kTotalSlicedBlobs; i++) {
+    builders.emplace_back(
+        new BlobDataBuilder(base::SizeTToString(i + kTotalRawBlobs)));
+    size_t source_size = sizes[i];
+    size_t offset = source_size == 1 ? 0 : i % (source_size - 1);
+    size_t size = (i % (source_size - offset)) + 1;
+    builders.back()->AppendBlob(base::SizeTToString(i), offset, size);
+  }
+
+  size_t total_finished_blobs = 0;
+  std::vector<std::unique_ptr<BlobDataHandle>> handles;
+  std::vector<BlobStatus> statuses;
+  std::vector<bool> populated;
+  statuses.resize(kTotalRawBlobs,
+                  BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS);
+  populated.resize(kTotalRawBlobs, false);
+  for (size_t i = 0; i < builders.size(); i++) {
+    BlobDataBuilder& builder = *builders[i];
+    builder.set_content_type("text/plain");
+    bool has_pending_memory = DoesBuilderHaveFutureData(i);
+    std::unique_ptr<BlobDataHandle> handle = context_->BuildBlob(
+        builder,
+        has_pending_memory
+            ? base::Bind(&SaveBlobStatusAndFiles, &statuses[0] + i, &files_)
+            : BlobStorageContext::TransportAllowedCallback());
+    handle->RunOnConstructionComplete(
+        base::Bind(&IncrementNumber, &total_finished_blobs));
+    handles.push_back(std::move(handle));
+  }
+  base::RunLoop().RunUntilIdle();
+
+  // We should be needing to send a page or two to disk.
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  do {
+    file_runner_->RunPendingTasks();
+    base::RunLoop().RunUntilIdle();
+    // Continue populating data for items that can fit.
+    for (size_t i = 0; i < kTotalRawBlobs; i++) {
+      BlobDataBuilder* builder = builders[i].get();
+      if (DoesBuilderHaveFutureData(i) && !populated[i] &&
+          statuses[i] == BlobStatus::PENDING_TRANSPORT) {
+        PopulateDataInBuilder(builder, i, file_runner_.get());
+        context_->NotifyTransportComplete(base::SizeTToString(i));
+        populated[i] = true;
+      }
+    }
+    base::RunLoop().RunUntilIdle();
+  } while (file_runner_->HasPendingTask());
+
+  // Check all builders with future items were signalled and populated.
+  for (size_t i = 0; i < populated.size(); i++) {
+    if (DoesBuilderHaveFutureData(i)) {
+      EXPECT_EQ(BlobStatus::PENDING_TRANSPORT, statuses[i]) << i;
+      EXPECT_TRUE(populated[i]) << i;
+    }
+  }
+  base::RunLoop().RunUntilIdle();
+
+  // We should be completely built now.
+  EXPECT_EQ(kTotalRawBlobs + kTotalSlicedBlobs, total_finished_blobs);
+  for (std::unique_ptr<BlobDataHandle>& handle : handles) {
+    EXPECT_EQ(BlobStatus::DONE, handle->GetBlobStatus());
+  }
+  handles.clear();
+  base::RunLoop().RunUntilIdle();
+  files_.clear();
+  // We should have file cleanup tasks.
+  EXPECT_TRUE(file_runner_->HasPendingTask());
+  file_runner_->RunPendingTasks();
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(0lu, context_->memory_controller().memory_usage());
+  EXPECT_EQ(0lu, context_->memory_controller().disk_usage());
+}
+
+// TODO(michaeln): tests for the deprecated url stuff
+
+}  // namespace storage
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc
index 533d3f1..bd02e514 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -7,7 +7,14 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_util.h"
 #include "base/guid.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner.h"
+#include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/blob_handle.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
@@ -15,14 +22,35 @@
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_storage_context.h"
 
+using base::FilePath;
 using base::UserDataAdapter;
 using storage::BlobStorageContext;
 
 namespace content {
 
 namespace {
+const FilePath::CharType kBlobStorageContextKeyName[] =
+    FILE_PATH_LITERAL("content_blob_storage_context");
+const FilePath::CharType kBlobStorageParentDirectory[] =
+    FILE_PATH_LITERAL("blob_storage");
 
-const char kBlobStorageContextKeyName[] = "content_blob_storage_context";
+// Removes all folders in the parent directory except for the
+// |current_run_dir| folder. If this path is empty, then we delete all folders.
+void RemoveOldBlobStorageDirectories(FilePath blob_storage_parent,
+                                     const FilePath& current_run_dir) {
+  if (!base::DirectoryExists(blob_storage_parent)) {
+    return;
+  }
+  base::FileEnumerator enumerator(blob_storage_parent, false /* recursive */,
+                                  base::FileEnumerator::DIRECTORIES);
+  bool success = true;
+  for (FilePath name = enumerator.Next(); !name.empty();
+       name = enumerator.Next()) {
+    if (current_run_dir.empty() || name != current_run_dir)
+      success &= base::DeleteFile(name, true /* recursive */);
+  }
+  LOCAL_HISTOGRAM_BOOLEAN("Storage.Blob.CleanupSuccess", success);
+}
 
 class BlobHandleImpl : public BlobHandle {
  public:
@@ -49,11 +77,39 @@
     context->SetUserData(
         kBlobStorageContextKeyName,
         new UserDataAdapter<ChromeBlobStorageContext>(blob.get()));
+
     // Check first to avoid memory leak in unittests.
-    if (BrowserThread::IsMessageLoopValid(BrowserThread::IO)) {
+    bool io_thread_valid = BrowserThread::IsMessageLoopValid(BrowserThread::IO);
+
+    // Resolve our storage directories.
+    FilePath blob_storage_parent =
+        context->GetPath().Append(kBlobStorageParentDirectory);
+    FilePath blob_storage_dir = blob_storage_parent.Append(
+        FilePath::FromUTF8Unsafe(base::GenerateGUID()));
+
+    // Only populate the task runner if we're not off the record. This enables
+    // paging/saving blob data to disk.
+    scoped_refptr<base::TaskRunner> file_task_runner;
+
+    // If we're not incognito mode, schedule all of our file tasks to enable
+    // disk on the storage context.
+    if (!context->IsOffTheRecord() && io_thread_valid) {
+      file_task_runner =
+          BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
+              base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+      // Removes our old blob directories if they exist.
+      BrowserThread::PostAfterStartupTask(
+          FROM_HERE, file_task_runner,
+          base::Bind(&RemoveOldBlobStorageDirectories,
+                     base::Passed(&blob_storage_parent), blob_storage_dir));
+    }
+
+    if (io_thread_valid) {
       BrowserThread::PostTask(
           BrowserThread::IO, FROM_HERE,
-          base::Bind(&ChromeBlobStorageContext::InitializeOnIOThread, blob));
+          base::Bind(&ChromeBlobStorageContext::InitializeOnIOThread, blob,
+                     base::Passed(&blob_storage_dir),
+                     base::Passed(&file_task_runner)));
     }
   }
 
@@ -61,9 +117,12 @@
       context, kBlobStorageContextKeyName);
 }
 
-void ChromeBlobStorageContext::InitializeOnIOThread() {
+void ChromeBlobStorageContext::InitializeOnIOThread(
+    FilePath blob_storage_dir,
+    scoped_refptr<base::TaskRunner> file_task_runner) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  context_.reset(new BlobStorageContext());
+  context_.reset(new BlobStorageContext(std::move(blob_storage_dir),
+                                        std::move(file_task_runner)));
 }
 
 std::unique_ptr<BlobHandle> ChromeBlobStorageContext::CreateMemoryBackedBlob(
@@ -86,7 +145,7 @@
 }
 
 std::unique_ptr<BlobHandle> ChromeBlobStorageContext::CreateFileBackedBlob(
-    const base::FilePath& path,
+    const FilePath& path,
     int64_t offset,
     int64_t size,
     const base::Time& expected_modification_time) {
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.h b/content/browser/blob_storage/chrome_blob_storage_context.h
index bd02cb1..4c7cfac 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.h
+++ b/content/browser/blob_storage/chrome_blob_storage_context.h
@@ -10,12 +10,14 @@
 
 #include <memory>
 
+#include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner_helpers.h"
 #include "content/common/content_export.h"
 
 namespace base {
 class FilePath;
+class TaskRunner;
 class Time;
 }
 
@@ -44,7 +46,8 @@
   static ChromeBlobStorageContext* GetFor(
       BrowserContext* browser_context);
 
-  void InitializeOnIOThread();
+  void InitializeOnIOThread(base::FilePath blob_storage_dir,
+                            scoped_refptr<base::TaskRunner> file_task_runner);
 
   storage::BlobStorageContext* context() const { return context_.get(); }
 
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 14cfcee..d6b6f98 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -679,7 +679,7 @@
   {
     TRACE_EVENT0("startup",
                  "BrowserMainLoop::Subsystem:BrowserMediaPlayerManager");
-    if (parsed_command_line_.HasSwitch(switches::kSingleProcess)) {
+    if (UsingInProcessGpu()) {
       gpu::ScopedSurfaceRequestConduit::SetInstance(
           ScopedSurfaceRequestManager::GetInstance());
     }
diff --git a/content/browser/renderer_host/input/touch_emulator.cc b/content/browser/renderer_host/input/touch_emulator.cc
index 0fcc536..86cabdc 100644
--- a/content/browser/renderer_host/input/touch_emulator.cc
+++ b/content/browser/renderer_host/input/touch_emulator.cc
@@ -56,25 +56,12 @@
       gesture_provider_config_type_(
           ui::GestureProviderConfigType::CURRENT_PLATFORM),
       double_tap_enabled_(true),
+      use_2x_cursors_(false),
       emulated_stream_active_sequence_count_(0),
       native_stream_active_sequence_count_(0) {
   DCHECK(client_);
   ResetState();
-
-  bool use_2x = device_scale_factor > 1.5f;
-  float cursor_scale_factor = use_2x ? 2.f : 1.f;
-  cursor_size_ = InitCursorFromResource(&touch_cursor_,
-      cursor_scale_factor,
-      use_2x ? IDR_DEVTOOLS_TOUCH_CURSOR_ICON_2X :
-          IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
-  InitCursorFromResource(&pinch_cursor_,
-      cursor_scale_factor,
-      use_2x ? IDR_DEVTOOLS_PINCH_CURSOR_ICON_2X :
-          IDR_DEVTOOLS_PINCH_CURSOR_ICON);
-
-  WebCursor::CursorInfo cursor_info;
-  cursor_info.type = blink::WebCursorInfo::TypePointer;
-  pointer_cursor_.InitFromCursorInfo(cursor_info);
+  InitCursors(device_scale_factor, true);
 }
 
 TouchEmulator::~TouchEmulator() {
@@ -115,12 +102,40 @@
   ResetState();
 }
 
+void TouchEmulator::SetDeviceScaleFactor(float device_scale_factor) {
+  if (!InitCursors(device_scale_factor, false))
+    return;
+  if (enabled())
+    UpdateCursor();
+}
+
 void TouchEmulator::SetDoubleTapSupportForPageEnabled(bool enabled) {
   double_tap_enabled_ = enabled;
   if (gesture_provider_)
     gesture_provider_->SetDoubleTapSupportForPageEnabled(enabled);
 }
 
+bool TouchEmulator::InitCursors(float device_scale_factor, bool force) {
+  bool use_2x = device_scale_factor > 1.5f;
+  if (use_2x == use_2x_cursors_ && !force)
+    return false;
+  use_2x_cursors_ = use_2x;
+  float cursor_scale_factor = use_2x ? 2.f : 1.f;
+  cursor_size_ = InitCursorFromResource(&touch_cursor_,
+      cursor_scale_factor,
+      use_2x ? IDR_DEVTOOLS_TOUCH_CURSOR_ICON_2X :
+          IDR_DEVTOOLS_TOUCH_CURSOR_ICON);
+  InitCursorFromResource(&pinch_cursor_,
+      cursor_scale_factor,
+      use_2x ? IDR_DEVTOOLS_PINCH_CURSOR_ICON_2X :
+          IDR_DEVTOOLS_PINCH_CURSOR_ICON);
+
+  WebCursor::CursorInfo cursor_info;
+  cursor_info.type = blink::WebCursorInfo::TypePointer;
+  pointer_cursor_.InitFromCursorInfo(cursor_info);
+  return true;
+}
+
 gfx::SizeF TouchEmulator::InitCursorFromResource(
     WebCursor* cursor, float scale, int resource_id) {
   gfx::Image& cursor_image =
diff --git a/content/browser/renderer_host/input/touch_emulator.h b/content/browser/renderer_host/input/touch_emulator.h
index 187dee7..6baee6e 100644
--- a/content/browser/renderer_host/input/touch_emulator.h
+++ b/content/browser/renderer_host/input/touch_emulator.h
@@ -27,6 +27,9 @@
   void Enable(ui::GestureProviderConfigType config_type);
   void Disable();
 
+  // Call when device scale factor changes.
+  void SetDeviceScaleFactor(float device_scale_factor);
+
   // See GestureProvider::SetDoubleTapSupportForPageEnabled.
   void SetDoubleTapSupportForPageEnabled(bool enabled);
 
@@ -57,6 +60,7 @@
   // Returns cursor size in DIP.
   gfx::SizeF InitCursorFromResource(
       WebCursor* cursor, float scale, int resource_id);
+  bool InitCursors(float device_scale_factor, bool force);
   void ResetState();
   void UpdateCursor();
   bool UpdateShiftPressed(bool shift_pressed);
@@ -86,6 +90,7 @@
   ui::GestureProviderConfigType gesture_provider_config_type_;
   bool double_tap_enabled_;
 
+  bool use_2x_cursors_;
   // While emulation is on, default cursor is touch. Pressing shift changes
   // cursor to the pinch one.
   WebCursor pointer_cursor_;
diff --git a/content/browser/renderer_host/input/touch_emulator_unittest.cc b/content/browser/renderer_host/input/touch_emulator_unittest.cc
index 3d53db1f..600badd5 100644
--- a/content/browser/renderer_host/input/touch_emulator_unittest.cc
+++ b/content/browser/renderer_host/input/touch_emulator_unittest.cc
@@ -77,7 +77,9 @@
     }
   }
 
-  void SetCursor(const WebCursor& cursor) override {}
+  void SetCursor(const WebCursor& cursor) override {
+    cursor_ = cursor;
+  }
 
   void ShowContextMenuAtPoint(const gfx::Point& point) override {}
 
@@ -241,6 +243,12 @@
 
   void DisableSynchronousTouchAck() { ack_touches_synchronously_ = false; }
 
+  float GetCursorScaleFactor() {
+    WebCursor::CursorInfo info;
+    cursor_.GetCursorInfo(&info);
+    return info.image_scale_factor;
+  }
+
  private:
   std::unique_ptr<TouchEmulator> emulator_;
   std::vector<WebInputEvent::Type> forwarded_events_;
@@ -253,6 +261,7 @@
   int last_mouse_y_;
   std::vector<WebTouchEvent> touch_events_to_ack_;
   base::MessageLoopForUI message_loop_;
+  WebCursor cursor_;
 };
 
 
@@ -569,4 +578,25 @@
   TouchEmulator(this, 4.0f);
 }
 
+TEST_F(TouchEmulatorTest, CursorScaleFactor) {
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  emulator()->SetDeviceScaleFactor(3.0f);
+  EXPECT_EQ(2.0f, GetCursorScaleFactor());
+  emulator()->SetDeviceScaleFactor(1.33f);
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  emulator()->Disable();
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  emulator()->SetDeviceScaleFactor(3.0f);
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  emulator()->Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
+  EXPECT_EQ(2.0f, GetCursorScaleFactor());
+  emulator()->SetDeviceScaleFactor(1.0f);
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+
+  TouchEmulator another(this, 4.0f);
+  EXPECT_EQ(1.0f, GetCursorScaleFactor());
+  another.Enable(ui::GestureProviderConfigType::GENERIC_MOBILE);
+  EXPECT_EQ(2.0f, GetCursorScaleFactor());
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 72f3b1c..5945998 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -17,6 +17,7 @@
 #include "base/bind_helpers.h"
 #include "base/callback.h"
 #include "base/command_line.h"
+#include "base/debug/crash_logging.h"
 #include "base/debug/dump_without_crashing.h"
 #include "base/feature_list.h"
 #include "base/files/file.h"
@@ -3005,9 +3006,9 @@
                                         const std::string& error) {
   LOG(ERROR) << "Terminating render process for bad Mojo message: " << error;
 
-  // The ReceivedBadMessage call below will trigger a DumpWithoutCrashing. Alias
-  // enough information here so that we can determine what the bad message was.
-  base::debug::Alias(&error);
+  // The ReceivedBadMessage call below will trigger a DumpWithoutCrashing.
+  // Capture the error message in a crash key value.
+  base::debug::ScopedCrashKey error_key_value("mojo-message-error", error);
   bad_message::ReceivedBadMessage(render_process_id,
                                   bad_message::RPH_MOJO_PROCESS_ERROR);
 }
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index c088b30..6141da6d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -1420,6 +1420,11 @@
   // the screen info as well as the new size (if the screen has changed scale
   // factor).
   WasResized();
+
+  if (touch_emulator_) {
+    touch_emulator_->SetDeviceScaleFactor(
+        view_.get() ? content::GetScaleFactorForView(view_.get()) : 1.0f);
+  }
 }
 
 void RenderWidgetHostImpl::GetSnapshotFromBrowser(
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.cc b/content/browser/service_worker/service_worker_dispatcher_host.cc
index ed7b357..56d67cf 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host.cc
@@ -944,16 +944,22 @@
                          DispatchExtendableMessageEventInternal<
                              ServiceWorkerClientInfo>,
                      this, worker, message, source_origin, sent_message_ports,
-                     callback));
+                     base::nullopt, callback));
       break;
-    case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER:
+    case SERVICE_WORKER_PROVIDER_FOR_CONTROLLER: {
+      // Clamp timeout to the sending worker's remaining timeout, to prevent
+      // postMessage from keeping workers alive forever.
+      base::TimeDelta timeout =
+          sender_provider_host->running_hosted_version()->remaining_timeout();
       RunSoon(base::Bind(
           &ServiceWorkerDispatcherHost::DispatchExtendableMessageEventInternal<
               ServiceWorkerObjectInfo>,
-          this, worker, message, source_origin, sent_message_ports, callback,
+          this, worker, message, source_origin, sent_message_ports,
+          base::make_optional(timeout), callback,
           sender_provider_host->GetOrCreateServiceWorkerHandle(
               sender_provider_host->running_hosted_version())));
       break;
+    }
     case SERVICE_WORKER_PROVIDER_UNKNOWN:
     default:
       NOTREACHED() << sender_provider_host->provider_type();
@@ -1107,6 +1113,7 @@
     const base::string16& message,
     const url::Origin& source_origin,
     const std::vector<int>& sent_message_ports,
+    const base::Optional<base::TimeDelta>& timeout,
     const StatusCallback& callback,
     const SourceInfo& source_info) {
   if (!source_info.IsValid()) {
@@ -1114,12 +1121,22 @@
         sent_message_ports, source_info, callback, SERVICE_WORKER_ERROR_FAILED);
     return;
   }
+
+  // If not enough time is left to actually process the event don't even
+  // bother starting the worker and sending the event.
+  if (timeout && *timeout < base::TimeDelta::FromMilliseconds(100)) {
+    DidFailToDispatchExtendableMessageEvent<SourceInfo>(
+        sent_message_ports, source_info, callback,
+        SERVICE_WORKER_ERROR_TIMEOUT);
+    return;
+  }
+
   worker->RunAfterStartWorker(
       ServiceWorkerMetrics::EventType::MESSAGE,
       base::Bind(&ServiceWorkerDispatcherHost::
                      DispatchExtendableMessageEventAfterStartWorker,
                  this, worker, message, source_origin, sent_message_ports,
-                 ExtendableMessageEventSource(source_info), callback),
+                 ExtendableMessageEventSource(source_info), timeout, callback),
       base::Bind(
           &ServiceWorkerDispatcherHost::DidFailToDispatchExtendableMessageEvent<
               SourceInfo>,
@@ -1133,9 +1150,17 @@
         const url::Origin& source_origin,
         const std::vector<int>& sent_message_ports,
         const ExtendableMessageEventSource& source,
+        const base::Optional<base::TimeDelta>& timeout,
         const StatusCallback& callback) {
-  int request_id =
-      worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE, callback);
+  int request_id;
+  if (timeout) {
+    request_id = worker->StartRequestWithCustomTimeout(
+        ServiceWorkerMetrics::EventType::MESSAGE, callback, *timeout,
+        ServiceWorkerVersion::CONTINUE_ON_TIMEOUT);
+  } else {
+    request_id = worker->StartRequest(ServiceWorkerMetrics::EventType::MESSAGE,
+                                      callback);
+  }
 
   MessagePortMessageFilter* filter =
       worker->embedded_worker()->message_port_message_filter();
diff --git a/content/browser/service_worker/service_worker_dispatcher_host.h b/content/browser/service_worker/service_worker_dispatcher_host.h
index 08c5698c..ae1e551 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host.h
+++ b/content/browser/service_worker/service_worker_dispatcher_host.h
@@ -13,6 +13,7 @@
 #include "base/id_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/strings/string16.h"
 #include "content/browser/service_worker/service_worker_registration_status.h"
 #include "content/common/service_worker/service_worker.mojom.h"
@@ -188,6 +189,7 @@
       const base::string16& message,
       const url::Origin& source_origin,
       const std::vector<int>& sent_message_ports,
+      const base::Optional<base::TimeDelta>& timeout,
       const StatusCallback& callback,
       const SourceInfo& source_info);
   void DispatchExtendableMessageEventAfterStartWorker(
@@ -196,6 +198,7 @@
       const url::Origin& source_origin,
       const std::vector<int>& sent_message_ports,
       const ExtendableMessageEventSource& source,
+      const base::Optional<base::TimeDelta>& timeout,
       const StatusCallback& callback);
   template <typename SourceInfo>
   void DidFailToDispatchExtendableMessageEvent(
diff --git a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
index 7482226..ae1a5389 100644
--- a/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_dispatcher_host_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
+#include "base/test/simple_test_tick_clock.h"
 #include "base/time/time.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/message_port_service.h"
@@ -694,11 +695,34 @@
                                                 version_->version_id());
   const int ref_count = sender_worker_handle->ref_count();
 
+  // Set mock clock on version_ to check timeout behavior.
+  base::SimpleTestTickClock* tick_clock = new base::SimpleTestTickClock();
+  tick_clock->SetNowTicks(base::TimeTicks::Now());
+  version_->SetTickClockForTesting(base::WrapUnique(tick_clock));
+
+  // Make sure worker has a non-zero timeout.
+  bool called = false;
+  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+  version_->StartWorker(ServiceWorkerMetrics::EventType::UNKNOWN,
+                        base::Bind(&SaveStatusCallback, &called, &status));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(called);
+  EXPECT_EQ(SERVICE_WORKER_OK, status);
+  version_->StartRequestWithCustomTimeout(
+      ServiceWorkerMetrics::EventType::ACTIVATE,
+      base::Bind(&ServiceWorkerUtils::NoOpStatusCallback),
+      base::TimeDelta::FromSeconds(10), ServiceWorkerVersion::KILL_ON_TIMEOUT);
+
+  // Advance clock by a couple seconds.
+  tick_clock->Advance(base::TimeDelta::FromSeconds(4));
+  base::TimeDelta remaining_time = version_->remaining_timeout();
+  EXPECT_EQ(base::TimeDelta::FromSeconds(6), remaining_time);
+
   // Dispatch ExtendableMessageEvent.
   std::vector<int> ports;
   SetUpDummyMessagePort(&ports);
-  bool called = false;
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_MAX_VALUE;
+  called = false;
+  status = SERVICE_WORKER_ERROR_MAX_VALUE;
   DispatchExtendableMessageEvent(
       version_, base::string16(), url::Origin(version_->scope().GetOrigin()),
       ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status));
@@ -714,6 +738,9 @@
     EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port));
 
   EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
+
+  // Timeout of message event should not have extended life of service worker.
+  EXPECT_EQ(remaining_time, version_->remaining_timeout());
 }
 
 TEST_P(ServiceWorkerDispatcherHostTestP, DispatchExtendableMessageEvent_Fail) {
@@ -721,20 +748,9 @@
   GURL script_url = GURL("http://www.example.com/service_worker.js");
 
   Initialize(base::WrapUnique(new FailToStartWorkerTestHelper));
-  SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_CONTROLLER, pattern);
+  SendProviderCreated(SERVICE_WORKER_PROVIDER_FOR_WORKER, pattern);
   SetUpRegistration(pattern, script_url);
 
-  // Set the running hosted version so that we can retrieve a valid service
-  // worker object information for the source attribute of the message event.
-  provider_host_->running_hosted_version_ = version_;
-
-  // Set aside the initial refcount of the worker handle.
-  provider_host_->GetOrCreateServiceWorkerHandle(version_.get());
-  ServiceWorkerHandle* sender_worker_handle =
-      dispatcher_host_->FindServiceWorkerHandle(provider_host_->provider_id(),
-                                                version_->version_id());
-  const int ref_count = sender_worker_handle->ref_count();
-
   // Try to dispatch ExtendableMessageEvent. This should fail to start the
   // worker and to dispatch the event.
   std::vector<int> ports;
@@ -746,7 +762,6 @@
       ports, provider_host_, base::Bind(&SaveStatusCallback, &called, &status));
   for (int port : ports)
     EXPECT_TRUE(MessagePortService::GetInstance()->AreMessagesHeld(port));
-  EXPECT_EQ(ref_count + 1, sender_worker_handle->ref_count());
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(called);
   EXPECT_EQ(SERVICE_WORKER_ERROR_START_WORKER_FAILED, status);
@@ -754,7 +769,6 @@
   // The error callback should clean up the ports and handle.
   for (int port : ports)
     EXPECT_FALSE(MessagePortService::GetInstance()->AreMessagesHeld(port));
-  EXPECT_EQ(ref_count, sender_worker_handle->ref_count());
 }
 
 TEST_P(ServiceWorkerDispatcherHostTestP, OnSetHostedVersionId) {
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 63382242..5639c0f 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -572,6 +572,8 @@
   base::TimeTicks expiration_time = tick_clock_->NowTicks() + timeout;
   timeout_queue_.push(
       RequestInfo(request_id, event_type, expiration_time, timeout_behavior));
+  if (expiration_time > max_request_expiration_time_)
+    max_request_expiration_time_ = expiration_time;
   return request_id;
 }
 
@@ -863,26 +865,6 @@
 
 ServiceWorkerVersion::PendingRequest::~PendingRequest() {}
 
-ServiceWorkerVersion::BaseMojoServiceWrapper::BaseMojoServiceWrapper(
-    ServiceWorkerVersion* worker,
-    const char* service_name)
-    : worker_(worker), service_name_(service_name) {}
-
-ServiceWorkerVersion::BaseMojoServiceWrapper::~BaseMojoServiceWrapper() {
-  IDMap<std::unique_ptr<PendingRequest>>::iterator iter(
-      &worker_->pending_requests_);
-  while (!iter.IsAtEnd()) {
-    PendingRequest* request = iter.GetCurrentValue();
-    if (request->mojo_service == service_name_) {
-      TRACE_EVENT_ASYNC_END1("ServiceWorker", "ServiceWorkerVersion::Request",
-                             request, "Error", "Service Disconnected");
-      request->error_callback.Run(SERVICE_WORKER_ERROR_FAILED);
-      worker_->pending_requests_.Remove(iter.GetCurrentKey());
-    }
-    iter.Advance();
-  }
-}
-
 void ServiceWorkerVersion::OnThreadStarted() {
   DCHECK_EQ(EmbeddedWorkerStatus::STARTING, running_status());
   // Activate ping/pong now that JavaScript execution will start.
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 44079ce..8b6d2e2 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -410,6 +410,12 @@
     return external_request_uuid_to_request_id_.size();
   }
 
+  // Returns the amount of time left until the request with the latest
+  // expiration time expires.
+  base::TimeDelta remaining_timeout() const {
+    return max_request_expiration_time_ - tick_clock_->NowTicks();
+  }
+
  private:
   friend class base::RefCounted<ServiceWorkerVersion>;
   friend class ServiceWorkerMetrics;
@@ -484,15 +490,6 @@
     base::TimeTicks start_time_ticks;
     ServiceWorkerMetrics::EventType event_type;
 
-    // -------------------------------------------------------------------------
-    // For Mojo requests.
-    // -------------------------------------------------------------------------
-    // Name of the mojo service this request is associated with. Used to call
-    // the callback when a connection closes with outstanding requests. Compared
-    // as pointer, so should only contain static strings. Typically this would
-    // be Interface::Name_ for some mojo interface.
-    const char* mojo_service = nullptr;
-
     // ------------------------------------------------------------------------
     // For IPC message requests.
     // ------------------------------------------------------------------------
@@ -503,41 +500,6 @@
     bool is_dispatched = false;
   };
 
-  // Base class to enable storing a list of mojo interface pointers for
-  // arbitrary interfaces. The destructor is also responsible for calling the
-  // error callbacks for any outstanding requests using this service.
-  class CONTENT_EXPORT BaseMojoServiceWrapper {
-   public:
-    BaseMojoServiceWrapper(ServiceWorkerVersion* worker,
-                           const char* service_name);
-    virtual ~BaseMojoServiceWrapper();
-
-   private:
-    ServiceWorkerVersion* worker_;
-    const char* service_name_;
-
-    DISALLOW_COPY_AND_ASSIGN(BaseMojoServiceWrapper);
-  };
-
-  // Wrapper around a mojo::InterfacePtr, which passes out WeakPtr's to the
-  // interface.
-  template <typename Interface>
-  class MojoServiceWrapper : public BaseMojoServiceWrapper {
-   public:
-    MojoServiceWrapper(ServiceWorkerVersion* worker,
-                       mojo::InterfacePtr<Interface> interface_ptr)
-        : BaseMojoServiceWrapper(worker, Interface::Name_),
-          interface_(std::move(interface_ptr)),
-          weak_ptr_factory_(interface_.get()) {}
-
-    base::WeakPtr<Interface> GetWeakPtr() {
-      return weak_ptr_factory_.GetWeakPtr();
-    }
-
-   private:
-    mojo::InterfacePtr<Interface> interface_;
-    base::WeakPtrFactory<Interface> weak_ptr_factory_;
-  };
 
   typedef ServiceWorkerVersion self;
   using ServiceWorkerClients = std::vector<ServiceWorkerClientInfo>;
@@ -717,9 +679,6 @@
 
   void OnStoppedInternal(EmbeddedWorkerStatus old_status);
 
-  // Called when the remote side of a connection to a mojo service is lost.
-  void OnMojoConnectionError(const char* service_name);
-
   // Called at the beginning of each Dispatch*Event function: records
   // the time elapsed since idle (generally the time since the previous
   // event ended).
@@ -787,6 +746,11 @@
   // to update once the worker stops, but will also update if it stays alive too
   // long.
   base::TimeTicks stale_time_;
+  // The latest expiration time of all requests that have ever been started. In
+  // particular this is not just the maximum of the expiration times of all
+  // currently existing requests, but also takes into account the former
+  // expiration times of finished requests.
+  base::TimeTicks max_request_expiration_time_;
 
   // Keeps track of requests for timeout purposes. Requests are sorted by
   // their expiration time (soonest to expire on top of the priority queue). The
diff --git a/content/child/blob_storage/blob_transport_controller.cc b/content/child/blob_storage/blob_transport_controller.cc
index 5db46a24..1b01792 100644
--- a/content/child/blob_storage/blob_transport_controller.cc
+++ b/content/child/blob_storage/blob_transport_controller.cc
@@ -90,27 +90,23 @@
   return true;
 }
 
-base::Optional<base::Time> WriteSingleRequestToDisk(
-    const BlobConsolidation* consolidation,
-    const BlobItemBytesRequest& request,
-    File* file) {
+bool WriteSingleRequestToDisk(const BlobConsolidation* consolidation,
+                              const BlobItemBytesRequest& request,
+                              File* file) {
   if (!file->IsValid())
-    return base::nullopt;
+    return false;
   int64_t seek_distance = file->Seek(
       File::FROM_BEGIN, base::checked_cast<int64_t>(request.handle_offset));
   bool seek_failed = seek_distance < 0;
   UMA_HISTOGRAM_BOOLEAN("Storage.Blob.RendererFileSeekFailed", seek_failed);
-  if (seek_failed) {
-    return base::nullopt;
-  }
+  if (seek_failed)
+    return false;
   BlobConsolidation::ReadStatus status = consolidation->VisitMemory(
       request.renderer_item_index, request.renderer_item_offset, request.size,
       base::Bind(&WriteSingleChunk, file));
   if (status != BlobConsolidation::ReadStatus::OK)
-    return base::nullopt;
-  File::Info info;
-  file->GetInfo(&info);
-  return base::make_optional(info.last_modified);
+    return false;
+  return true;
 }
 
 base::Optional<std::vector<BlobItemBytesResponse>> WriteDiskRequests(
@@ -118,8 +114,6 @@
     std::unique_ptr<std::vector<BlobItemBytesRequest>> requests,
     const std::vector<IPC::PlatformFileForTransit>& file_handles) {
   std::vector<BlobItemBytesResponse> responses;
-  std::vector<base::Time> last_modified_times;
-  last_modified_times.resize(file_handles.size());
   // We grab ownership of the file handles here. When this vector is destroyed
   // it will close the files.
   std::vector<File> files;
@@ -128,13 +122,24 @@
     files.emplace_back(IPC::PlatformFileForTransitToFile(file_handle));
   }
   for (const auto& request : *requests) {
-    base::Optional<base::Time> last_modified = WriteSingleRequestToDisk(
-        consolidation.get(), request, &files[request.handle_index]);
-    if (!last_modified) {
+    if (!WriteSingleRequestToDisk(consolidation.get(), request,
+                                  &files[request.handle_index])) {
       return base::nullopt;
     }
-    last_modified_times[request.handle_index] = last_modified.value();
   }
+  // The last modified time needs to be collected after we flush the file.
+  std::vector<base::Time> last_modified_times;
+  last_modified_times.resize(file_handles.size());
+  for (size_t i = 0; i < files.size(); ++i) {
+    auto& file = files[i];
+    if (!file.Flush())
+      return base::nullopt;
+    File::Info info;
+    if (!file.GetInfo(&info))
+      return base::nullopt;
+    last_modified_times[i] = info.last_modified;
+  }
+
   for (const auto& request : *requests) {
     responses.push_back(BlobItemBytesResponse(request.request_number));
     responses.back().time_file_modified =
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 0550e19..2dc8a3c 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -547,6 +547,7 @@
     "../browser/background_sync/background_sync_browsertest.cc",
     "../browser/battery_status/battery_monitor_impl_browsertest.cc",
     "../browser/battery_status/battery_monitor_integration_browsertest.cc",
+    "../browser/blob_storage/blob_storage_browsertest.cc",
     "../browser/blob_storage/blob_url_browsertest.cc",
     "../browser/bookmarklet_browsertest.cc",
     "../browser/browser_side_navigation_browsertest.cc",
diff --git a/content/test/data/blob_storage/blob_creation_and_slicing.html b/content/test/data/blob_storage/blob_creation_and_slicing.html
new file mode 100644
index 0000000..e3f36c0
--- /dev/null
+++ b/content/test/data/blob_storage/blob_creation_and_slicing.html
@@ -0,0 +1,134 @@
+<html>
+  <head>
+    <title>Blob Creation & Slicing</title>
+    <script type="text/javascript" src="common.js"></script>
+    <script type="text/javascript">
+// We create < 3000 bytes of data, as that is the max for the browsertest.
+var MAX_BYTES = 3000;
+
+// Number of blobs constructed with raw data.
+var NUM_RAW_BLOBS = 100;
+// Number of blobs we create by slicing the raw data blobs.
+var NUM_SLICES = 100;
+// Number of blobs we create by sandwiching sliced blobs in between new data.
+var NUM_SANDWICHES = 100;
+var totalSize = 0;
+
+var generatePsuedoRandomUint8Array = function(length) {
+  var array = new Uint8Array(length);
+  for (let i = 0; i < length; ++i) {
+    array[i] = (17 + 23 * i) & 0xFF;
+  }
+  return array;
+}
+
+var test = function() {
+  var blobs = [];
+
+  // This should cause us to go straight to file.
+  var savedToDiskDataSize = 190;
+  var savedToDiskData = generatePsuedoRandomUint8Array(savedToDiskDataSize);
+
+  // This should require multiple shared memory segments.
+  var sharedMemoryDataSize = 15;
+  var sharedMemoryData = generatePsuedoRandomUint8Array(sharedMemoryDataSize);
+ 
+  var sandwichDataSize = 7;
+
+  // This should fit in IPC.
+  var ipcDataSize = 2;
+  var ipcData = generatePsuedoRandomUint8Array(ipcDataSize);
+  
+  var expectedBlobData = [];
+  for (let i = 0; i < NUM_RAW_BLOBS; ++i) {
+    let data = [];
+    if (i % 5 == 0) {
+      data.push(sharedMemoryData);
+    } else if (i % 13 == 0) {
+      data.push(savedToDiskData);
+    } else {
+      data.push(ipcData);
+    }
+    expectedBlobData.push(data[data.length - 1]);
+    let blob = new Blob(data, { content_type: "text/plain" });
+    blobs.push(blob);
+    totalSize += blob.size;
+  }
+
+  for (let i = 0; i < NUM_SLICES; ++i) {
+    let origSize;
+    let origData;
+    let rawIndex = i % NUM_RAW_BLOBS;
+    if (rawIndex % 5 == 0) {
+      origSize = sharedMemoryDataSize;
+      origData = sharedMemoryData;
+    } else if (rawIndex % 13 == 0) {
+      origSize = savedToDiskDataSize;
+      origData = savedToDiskData;
+     } else {
+      origSize = ipcDataSize;
+      origData = ipcData;
+    }
+    let blob;
+    let expectedData;
+    if (i % 2 == 0) {
+      blob = blobs[i].slice(origSize / 2);
+      expectedData = origData.slice(origSize / 2);
+    } else {
+      blob = blobs[i].slice(0, origSize / 2);
+      expectedData = origData.slice(0, origSize / 2);
+    }
+    expectedBlobData.push(expectedData);
+    blobs.push(blob);
+  }
+  
+  var getBytes = function(string) {
+    var bytes = [];
+    for (let i = 0; i < string.length; ++i) {
+      bytes.push(string.charCodeAt(i));
+    }
+    return bytes;
+  }
+
+  for (let i = 0; i < NUM_SANDWICHES; ++i) {
+    let sliceIndex = NUM_RAW_BLOBS + (i % NUM_SLICES);
+    let slicedDataSize = expectedBlobData[sliceIndex].length;
+    blobs.push(new Blob(['pre', blobs[sliceIndex], 'post'], { content_type: "text/plain" }));
+    totalSize += sandwichDataSize;
+
+    let expectedData = new Uint8Array(sandwichDataSize + slicedDataSize);
+    expectedData.set(getBytes("pre"), 0);
+    expectedData.set(expectedBlobData[sliceIndex], 3);
+    expectedData.set(getBytes("post"), 3 + slicedDataSize);
+    expectedBlobData.push(expectedData);
+  }
+  shouldBeTrue("totalSize <= MAX_BYTES");
+
+  var numRead = 0;
+  for (let i = 0; i < blobs.length; i++) {
+    (function(index, d) {
+      var reader = new FileReader();
+      reader.onloadend = function(e) {
+        if (reader.error) {
+          fail('Error when reading blob ' + index + ': ' + reader.error);
+          return;
+        }
+        numRead++;
+        debug('Finished reading blob ' + index);
+        shouldBe('event.target.result.byteLength', d.length + '');
+        shouldBe('new Uint8Array(event.target.result)',
+                 '[' + d + ']');
+        if (numRead >= blobs.length) {
+          done('Done!');
+        }
+      }
+      return reader;
+    })(i, expectedBlobData[i]).readAsArrayBuffer(blobs[i]);
+  }
+};
+    </script>
+  </head>
+  <body onLoad="test()">
+    <div id="status">Starting...<br/></div>
+  </body>
+</html>
diff --git a/content/test/data/blob_storage/common.js b/content/test/data/blob_storage/common.js
new file mode 100644
index 0000000..e9b3cc6a
--- /dev/null
+++ b/content/test/data/blob_storage/common.js
@@ -0,0 +1,105 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function debug(message) {
+  var span = document.createElement("span");
+  span.appendChild(document.createTextNode(message));
+  span.appendChild(document.createElement("br"));
+  document.getElementById('status').appendChild(span);
+}
+
+function done(message) {
+  if (document.location.hash == '#fail')
+    return;
+  if (message)
+    debug('PASS: ' + message);
+  else
+    debug('PASS');
+  document.location.hash = '#pass';
+}
+
+function fail(message) {
+  debug('FAILED: ' + message);
+  document.location.hash = '#fail';
+}
+
+function getLog() {
+  return "" + document.getElementById('status').innerHTML;
+}
+
+// The following functions are based on
+// WebKit/LayoutTests/fast/js/resources/js-test-pre.js
+// so that the tests will look similar to the existing layout tests.
+function stringify(v) {
+  if (v === 0 && 1/v < 0)
+    return "-0";
+  else return "" + v;
+}
+
+function areArraysEqual(a, b) {
+  try {
+    if (a.length !== b.length)
+      return false;
+    for (var i = 0; i < a.length; i++) {
+      if (a[i] !== b[i])
+        return false;
+    }
+  } catch (ex) {
+    return false;
+  }
+  return true;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+  if (_expected === 0)
+    return _actual === _expected && (1/_actual) === (1/_expected);
+  if (_actual === _expected)
+    return true;
+  if (typeof(_expected) == "number" && isNaN(_expected))
+    return typeof(_actual) == "number" && isNaN(_actual);
+  if (Object.prototype.toString.call(_expected) ==
+      Object.prototype.toString.call([]))
+    return areArraysEqual(_actual, _expected);
+  return false;
+}
+
+function shouldBe(_a, _b)
+{
+  if (typeof _a != "string" || typeof _b != "string")
+    debug("WARN: shouldBe() expects string arguments");
+  var exception;
+  var _av;
+  try {
+    _av = eval(_a);
+  } catch (e) {
+    exception = e;
+  }
+  var _bv = eval(_b);
+
+  if (exception)
+    fail(_a + " should be " + _bv + ". Threw exception " + exception);
+  else if (isResultCorrect(_av, _bv))
+    debug(_a + " is " + _b);
+  else if (typeof(_av) == typeof(_bv))
+    fail(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+  else
+    fail(_a + " should be " + _bv + " (of type " + typeof _bv + "). " +
+         "Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+function shouldBeEqualToString(a, b) {
+  var unevaledString = '"' + b.replace(/\\/g, "\\\\").replace(/"/g, "\"") + '"';
+  shouldBe(a, unevaledString);
+}
+
+if (typeof String.prototype.startsWith !== 'function') {
+  String.prototype.startsWith = function (str) {
+    return this.indexOf(str) === 0;
+  };
+}
\ No newline at end of file
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 4d27bc6..46e5e20 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -549,8 +549,6 @@
         ['linux', 'amd', 'intel'], bug=662644) # WebGL 2.0.1
     self.Fail('conformance2/rendering/clipping-wide-points.html',
         ['linux', 'amd', 'intel'], bug=662644) # WebGL 2.0.1
-    self.Fail('conformance2/textures/misc/tex-srgb-mipmap.html',
-        ['linux', 'amd', 'intel'], bug=662644) # WebGL 2.0.1
 
     # Linux NVIDIA
     # This test is flaky both with and without ANGLE.
@@ -585,6 +583,8 @@
     # Linux Intel with ANGLE only
     self.Fail('deqp/functional/gles3/framebufferblit/conversion_07.html',
         ['linux', 'intel', 'opengl'], bug=598902)
+    self.Fail('conformance2/textures/misc/tex-srgb-mipmap.html',
+        ['linux', 'intel', 'opengl'], bug=634519) # WebGL 2.0.1
 
     # Linux AMD only.
     # It looks like AMD shader compiler rejects many valid ES3 semantics.
@@ -777,6 +777,9 @@
     self.Fail('conformance2/rendering/blitframebuffer-filter-outofbounds.html',
         ['linux', 'amd'], bug=655147)
 
+    self.Fail('conformance2/textures/misc/tex-srgb-mipmap.html',
+        ['linux', 'amd'], bug=634519) # WebGL 2.0.1
+
     # Uniform buffer related failures
     self.Fail('deqp/functional/gles3/uniformbuffers/single_struct_array.html',
         ['linux', 'amd'], bug=483282)
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 04185fd..ff9399a 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -191,6 +191,10 @@
       "load_monitoring_extension_host_queue.h",
       "management_policy.cc",
       "management_policy.h",
+      "mojo/keep_alive_impl.cc",
+      "mojo/keep_alive_impl.h",
+      "mojo/service_registration.cc",
+      "mojo/service_registration.h",
       "notification_types.cc",
       "notification_types.h",
       "null_app_sorting.cc",
@@ -255,7 +259,6 @@
       "//extensions/browser/guest_view",
       "//extensions/browser/install",
       "//extensions/browser/kiosk",
-      "//extensions/browser/mojo",
       "//extensions/browser/updater",
       "//extensions/browser/value_store",
     ]
@@ -274,6 +277,8 @@
       "//device/serial",
       "//device/usb",
       "//extensions:extensions_browser_resources",
+      "//extensions/common:mojo",
+      "//services/service_manager/public/cpp",
     ]
 
     if (is_chromeos) {
diff --git a/extensions/browser/event_router.cc b/extensions/browser/event_router.cc
index 13b8b56e..0dc125a 100644
--- a/extensions/browser/event_router.cc
+++ b/extensions/browser/event_router.cc
@@ -397,7 +397,7 @@
     filtered_events = update.Create();
 
   ListValue* filter_list = nullptr;
-  if (!filtered_events->GetList(event_name, &filter_list)) {
+  if (!filtered_events->GetListWithoutPathExpansion(event_name, &filter_list)) {
     filter_list = new ListValue;
     filtered_events->SetWithoutPathExpansion(event_name,
                                              base::WrapUnique(filter_list));
@@ -419,10 +419,10 @@
   }
 
   for (size_t i = 0; i < filter_list->GetSize(); i++) {
-    DictionaryValue* filter = NULL;
-    CHECK(filter_list->GetDictionary(i, &filter));
-    if (filter->Equals(filter)) {
-      filter_list->Remove(i, NULL);
+    DictionaryValue* filter_value = nullptr;
+    CHECK(filter_list->GetDictionary(i, &filter_value));
+    if (filter_value->Equals(filter)) {
+      filter_list->Remove(i, nullptr);
       break;
     }
   }
diff --git a/extensions/browser/event_router.h b/extensions/browser/event_router.h
index 4e68f85..edd8257 100644
--- a/extensions/browser/event_router.h
+++ b/extensions/browser/event_router.h
@@ -198,6 +198,7 @@
                    bool did_enqueue);
 
  private:
+  friend class EventRouterFilterTest;
   friend class EventRouterTest;
 
   // The extension and process that contains the event listener for a given
diff --git a/extensions/browser/event_router_unittest.cc b/extensions/browser/event_router_unittest.cc
index 7fc725f..53cb9daa 100644
--- a/extensions/browser/event_router_unittest.cc
+++ b/extensions/browser/event_router_unittest.cc
@@ -14,13 +14,25 @@
 #include "base/memory/ptr_util.h"
 #include "base/test/histogram_tester.h"
 #include "base/values.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service_factory.h"
+#include "components/prefs/testing_pref_store.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/event_listener_map.h"
+#include "extensions/browser/extension_pref_value_map.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_prefs_factory.h"
 #include "extensions/browser/extensions_test.h"
 #include "extensions/common/extension_builder.h"
 #include "extensions/common/test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+
 namespace extensions {
 
 namespace {
@@ -106,6 +118,19 @@
   return builder.Build();
 }
 
+std::unique_ptr<DictionaryValue> CreateHostSuffixFilter(
+    const std::string& suffix) {
+  std::unique_ptr<DictionaryValue> filter(new DictionaryValue());
+  std::unique_ptr<ListValue> filter_list(new ListValue());
+  std::unique_ptr<DictionaryValue> filter_dict(new DictionaryValue());
+
+  filter_dict->Set("hostSuffix", base::MakeUnique<StringValue>(suffix));
+  filter_list->Append(std::move(filter_dict));
+  filter->Set("url", std::move(filter_list));
+
+  return filter;
+}
+
 }  // namespace
 
 class EventRouterTest : public ExtensionsTest {
@@ -163,6 +188,96 @@
   DISALLOW_COPY_AND_ASSIGN(EventRouterTest);
 };
 
+class EventRouterFilterTest : public ExtensionsTest {
+ public:
+  EventRouterFilterTest() {}
+
+  void SetUp() override {
+    ExtensionsTest::SetUp();
+
+    render_process_host_.reset(
+        new content::MockRenderProcessHost(browser_context()));
+
+    // Set up all the dependencies of ExtensionPrefs.
+    extension_pref_value_map_.reset(new ExtensionPrefValueMap());
+    PrefServiceFactory factory;
+    factory.set_user_prefs(new TestingPrefStore());
+    factory.set_extension_prefs(new TestingPrefStore());
+    user_prefs::PrefRegistrySyncable* pref_registry =
+        new user_prefs::PrefRegistrySyncable();
+    // Prefs should be registered before the PrefService is created.
+    ExtensionPrefs::RegisterProfilePrefs(pref_registry);
+    pref_service_ = factory.Create(pref_registry);
+
+    std::unique_ptr<ExtensionPrefs> extension_prefs(ExtensionPrefs::Create(
+        browser_context(), pref_service_.get(),
+        browser_context()->GetPath().AppendASCII("Extensions"),
+        extension_pref_value_map_.get(), false /* extensions_disabled */,
+        std::vector<ExtensionPrefsObserver*>()));
+
+    ExtensionPrefsFactory::GetInstance()->SetInstanceForTesting(
+        browser_context(), std::move(extension_prefs));
+
+    ASSERT_TRUE(EventRouter::Get(browser_context()));  // constructs EventRouter
+  }
+
+  void TearDown() override {
+    render_process_host_.reset();
+    ExtensionsTest::TearDown();
+  }
+
+  content::RenderProcessHost* render_process_host() const {
+    return render_process_host_.get();
+  }
+
+  EventRouter* event_router() { return EventRouter::Get(browser_context()); }
+
+  const DictionaryValue* GetFilteredEvents(const std::string& extension_id) {
+    return event_router()->GetFilteredEvents(extension_id);
+  }
+
+  bool ContainsFilter(const std::string& extension_id,
+                      const std::string& event_name,
+                      const DictionaryValue& to_check) {
+    const ListValue* filter_list = GetFilterList(extension_id, event_name);
+    if (!filter_list) {
+      ADD_FAILURE();
+      return false;
+    }
+
+    for (size_t i = 0; i < filter_list->GetSize(); ++i) {
+      const DictionaryValue* filter = nullptr;
+      if (!filter_list->GetDictionary(i, &filter)) {
+        ADD_FAILURE();
+        return false;
+      }
+      if (filter->Equals(&to_check))
+        return true;
+    }
+    return false;
+  }
+
+ private:
+  const ListValue* GetFilterList(const std::string& extension_id,
+                                 const std::string& event_name) {
+    const base::DictionaryValue* filtered_events =
+        GetFilteredEvents(extension_id);
+    DictionaryValue::Iterator iter(*filtered_events);
+    if (iter.key() != event_name)
+      return nullptr;
+
+    const base::ListValue* filter_list = nullptr;
+    iter.value().GetAsList(&filter_list);
+    return filter_list;
+  }
+
+  std::unique_ptr<content::RenderProcessHost> render_process_host_;
+  std::unique_ptr<ExtensionPrefValueMap> extension_pref_value_map_;
+  std::unique_ptr<PrefService> pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(EventRouterFilterTest);
+};
+
 TEST_F(EventRouterTest, GetBaseEventName) {
   // Normal event names are passed through unchanged.
   EXPECT_EQ("foo.onBar", EventRouter::GetBaseEventName("foo.onBar"));
@@ -275,4 +390,60 @@
   ExpectHistogramCounts(7, 3, 2, 2, 1, 2);
 }
 
+// Tests adding and removing events with filters.
+TEST_F(EventRouterFilterTest, Basic) {
+  // For the purpose of this test, "." is important in |event_name| as it
+  // exercises the code path that uses |event_name| as a key in DictionaryValue.
+  const std::string kEventName = "webNavigation.onBeforeNavigate";
+
+  const std::string kExtensionId = "mbflcebpggnecokmikipoihdbecnjfoj";
+  const std::string kHostSuffixes[] = {"foo.com", "bar.com", "baz.com"};
+  std::vector<std::unique_ptr<DictionaryValue>> filters;
+  for (size_t i = 0; i < arraysize(kHostSuffixes); ++i) {
+    std::unique_ptr<base::DictionaryValue> filter =
+        CreateHostSuffixFilter(kHostSuffixes[i]);
+    EventRouter::Get(browser_context())
+        ->AddFilteredEventListener(kEventName, render_process_host(),
+                                   kExtensionId, *filter, true);
+    filters.push_back(std::move(filter));
+  }
+
+  const base::DictionaryValue* filtered_events =
+      GetFilteredEvents(kExtensionId);
+  ASSERT_TRUE(filtered_events);
+  ASSERT_EQ(1u, filtered_events->size());
+
+  DictionaryValue::Iterator iter(*filtered_events);
+  ASSERT_EQ(kEventName, iter.key());
+  const base::ListValue* filter_list = nullptr;
+  ASSERT_TRUE(iter.value().GetAsList(&filter_list));
+  ASSERT_TRUE(filter_list);
+  ASSERT_EQ(3u, filter_list->GetSize());
+
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
+
+  // Remove the second filter.
+  event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
+                                              kExtensionId, *filters[1], true);
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
+
+  // Remove the first filter.
+  event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
+                                              kExtensionId, *filters[0], true);
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
+  ASSERT_TRUE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
+
+  // Remove the third filter.
+  event_router()->RemoveFilteredEventListener(kEventName, render_process_host(),
+                                              kExtensionId, *filters[2], true);
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[0]));
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[1]));
+  ASSERT_FALSE(ContainsFilter(kExtensionId, kEventName, *filters[2]));
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/mojo/BUILD.gn b/extensions/browser/mojo/BUILD.gn
deleted file mode 100644
index 2fdb51e..0000000
--- a/extensions/browser/mojo/BUILD.gn
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("mojo") {
-  sources = [
-    "keep_alive_impl.cc",
-    "keep_alive_impl.h",
-    "service_registration.cc",
-    "service_registration.h",
-  ]
-
-  deps = [
-    "//content/public/browser",
-    "//extensions/common:mojo",
-    "//services/service_manager/public/cpp",
-  ]
-}
diff --git a/extensions/renderer/BUILD.gn b/extensions/renderer/BUILD.gn
index e7b643fe..21acb51 100644
--- a/extensions/renderer/BUILD.gn
+++ b/extensions/renderer/BUILD.gn
@@ -310,7 +310,7 @@
     "//gin:gin_test",
 
     # TODO(brettw) these tests should not be including headers from browser.
-    "//extensions/browser/mojo",
+    "//extensions/browser",
     "//extensions/common",
     "//gin",
     "//mojo/edk/js",
diff --git a/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
index 1f85360..f52901b7 100644
--- a/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
+++ b/gpu/command_buffer/service/gles2_cmd_srgb_converter.cc
@@ -245,7 +245,7 @@
     glBindTexture(GL_TEXTURE_2D, srgb_converter_textures_[1]);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
                  c.width(), c.height(),
-                 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+                 0, GL_RGBA, GL_FLOAT, nullptr);
     glBindFramebufferEXT(GL_FRAMEBUFFER, srgb_decoder_fbo_);
     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                               GL_TEXTURE_2D, srgb_converter_textures_[1], 0);
@@ -279,7 +279,7 @@
         GL_TEXTURE_2D, 0, decode ? GL_RGBA32F : src_framebuffer_internal_format,
         width_draw, height_draw, 0,
         decode ? GL_RGBA : src_framebuffer_format,
-        decode ? GL_UNSIGNED_BYTE : src_framebuffer_type,
+        decode ? GL_FLOAT : src_framebuffer_type,
         nullptr);
 
     glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, srgb_encoder_fbo_);
@@ -354,9 +354,11 @@
   GLsizei depth;
   GLenum type = 0;
   GLenum internal_format = 0;
+  GLenum format = 0;
   GLsizei base_level = tex->base_level();
   tex->GetLevelSize(target, base_level, &width, &height, &depth);
   tex->GetLevelType(target, base_level, &type, &internal_format);
+  format = TextureManager::ExtractFormatFromStorageFormat(internal_format);
   const GLint mipmap_levels =
       TextureManager::ComputeMipMapCount(target, width, height, depth);
 
@@ -364,7 +366,7 @@
   if (feature_info_->ext_color_buffer_float_available() &&
       feature_info_->oes_texture_float_linear_available()) {
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA,
-                 GL_UNSIGNED_BYTE, nullptr);
+                 GL_FLOAT, nullptr);
   } else {
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA,
                  GL_UNSIGNED_BYTE, nullptr);
@@ -411,7 +413,7 @@
     // generate mipmap for tex manually
     glBindTexture(GL_TEXTURE_2D, tex->service_id());
     glTexImage2D(GL_TEXTURE_2D, level, internal_format, width, height, 0,
-                 GL_SRGB, type, NULL);
+                 format, type, nullptr);
     glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                               GL_TEXTURE_2D, tex->service_id(), level);
 
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index 1354f3fe..3e9141a 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -365,7 +365,7 @@
   *vendor_id = 0;
   *device_id = 0;
 
-  // Taken from http://developer.nvidia.com/object/device_ids.html
+  // Taken from http://www.nvidia.com/object/device_ids.html
   DISPLAY_DEVICE dd;
   dd.cb = sizeof(DISPLAY_DEVICE);
   std::wstring id;
@@ -411,7 +411,7 @@
                               DISPLAY_LINK_INSTALLATION_STATUS_MAX);
   }
 
-  // Taken from http://developer.nvidia.com/object/device_ids.html
+  // Taken from http://www.nvidia.com/object/device_ids.html
   DISPLAY_DEVICE dd;
   dd.cb = sizeof(DISPLAY_DEVICE);
   std::wstring id;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 8888a30..fb9c8e6 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -5252,10 +5252,6 @@
     didCommitNavigation:(WKNavigation*)navigation {
   DCHECK_EQ(_webView, webView);
   _certVerificationErrors->Clear();
-  // This point should closely approximate the document object change, so reset
-  // the list of injected scripts to those that are automatically injected.
-  _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
-  [self injectWindowID];
 
   // This is the point where the document's URL has actually changed, and
   // pending navigation information should be applied to state information.
@@ -5284,6 +5280,17 @@
           base::SysNSStringToUTF8(storedMIMEType));
     }
   }
+
+  // This point should closely approximate the document object change, so reset
+  // the list of injected scripts to those that are automatically injected.
+  _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
+  if ([self contentIsHTML] || self.webState->GetContentsMimeType().empty()) {
+    // In unit tests MIME type will be empty, because loadHTML:forURL: does not
+    // notify web view delegate about received response, so web controller does
+    // not get a chance to properly update MIME type.
+    [self injectWindowID];
+  }
+
   [self webPageChanged];
 
   [self updateSSLStatusForCurrentNavigationItem];
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index d8352510..2a28556b 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -368,11 +368,6 @@
 
 // static
 bool WebThread::CurrentlyOn(ID identifier) {
-  // This shouldn't use MessageLoop::current() since it uses LazyInstance which
-  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
-  // function.
-  // http://crbug.com/63678
-  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
   WebThreadGlobals& globals = g_globals.Get();
   base::AutoLock lock(globals.lock);
   DCHECK(identifier >= 0 && identifier < ID_COUNT);
@@ -456,11 +451,6 @@
   if (g_globals == nullptr)
     return false;
 
-  // This shouldn't use MessageLoop::current() since it uses LazyInstance which
-  // may be deleted by ~AtExitManager when a WorkerPool thread calls this
-  // function.
-  // http://crbug.com/63678
-  base::ThreadRestrictions::ScopedAllowSingleton allow_singleton;
   base::MessageLoop* cur_message_loop = base::MessageLoop::current();
   WebThreadGlobals& globals = g_globals.Get();
   for (int i = 0; i < ID_COUNT; ++i) {
diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc
index b0c90b23..af21274 100644
--- a/net/base/keygen_handler_unittest.cc
+++ b/net/base/keygen_handler_unittest.cc
@@ -15,7 +15,6 @@
 #include "base/logging.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/threading/thread_restrictions.h"
 #include "base/threading/worker_pool.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -176,9 +175,6 @@
                              base::WaitableEvent* event,
                              std::unique_ptr<KeygenHandler> handler,
                              std::string* result) {
-  // We allow Singleton use on the worker thread here since we use a
-  // WaitableEvent to synchronize, so it's safe.
-  base::ThreadRestrictions::ScopedAllowSingleton scoped_allow_singleton;
   handler->set_stores_key(false);  // Don't leave the key-pair behind.
   *result = handler->GenKeyAndSignChallenge();
   event->Signal();
diff --git a/net/log/trace_net_log_observer.cc b/net/log/trace_net_log_observer.cc
index bae83a5a..af69aca 100644
--- a/net/log/trace_net_log_observer.cc
+++ b/net/log/trace_net_log_observer.cc
@@ -101,12 +101,21 @@
   // Should only stop if is currently watching.
   DCHECK(net_log_to_watch_);
   base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+  // net_log() != nullptr iff NetLog::DeprecatedAddObserver() has been called.
+  // This implies that if the netlog category wasn't enabled, then
+  // NetLog::DeprecatedRemoveObserver() will not get called, and there won't be
+  // a crash in NetLog::DeprecatedRemoveObserver().
   if (net_log())
     net_log()->DeprecatedRemoveObserver(this);
-  net_log_to_watch_ = NULL;
+  net_log_to_watch_ = nullptr;
 }
 
 void TraceNetLogObserver::OnTraceLogEnabled() {
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kNetLogTracingCategory, &enabled);
+  if (!enabled)
+    return;
+
   net_log_to_watch_->DeprecatedAddObserver(this, NetLogCaptureMode::Default());
 }
 
diff --git a/net/log/trace_net_log_observer_unittest.cc b/net/log/trace_net_log_observer_unittest.cc
index 2cd4f01..6a3c5b0 100644
--- a/net/log/trace_net_log_observer_unittest.cc
+++ b/net/log/trace_net_log_observer_unittest.cc
@@ -398,6 +398,44 @@
   EXPECT_TRUE(item2_params.empty());
 }
 
+TEST(TraceNetLogObserverCategoryTest, DisabledCategory) {
+  TraceNetLogObserver observer;
+  NetLog net_log;
+  observer.WatchForTraceStart(&net_log);
+
+  EXPECT_FALSE(net_log.IsCapturing());
+
+  std::string disabled_netlog_category =
+      std::string("-") + kNetLogTracingCategory;
+  TraceLog::GetInstance()->SetEnabled(
+      base::trace_event::TraceConfig(disabled_netlog_category, ""),
+      TraceLog::RECORDING_MODE);
+
+  EXPECT_FALSE(net_log.IsCapturing());
+  observer.StopWatchForTraceStart();
+  EXPECT_FALSE(net_log.IsCapturing());
+
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST(TraceNetLogObserverCategoryTest, EnabledCategory) {
+  TraceNetLogObserver observer;
+  NetLog net_log;
+  observer.WatchForTraceStart(&net_log);
+
+  EXPECT_FALSE(net_log.IsCapturing());
+
+  TraceLog::GetInstance()->SetEnabled(
+      base::trace_event::TraceConfig(kNetLogTracingCategory, ""),
+      TraceLog::RECORDING_MODE);
+
+  EXPECT_TRUE(net_log.IsCapturing());
+  observer.StopWatchForTraceStart();
+  EXPECT_FALSE(net_log.IsCapturing());
+
+  TraceLog::GetInstance()->SetDisabled();
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/net.gypi b/net/net.gypi
index 3a532c16..484e83c 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -2032,6 +2032,7 @@
       'url_request/url_fetcher_impl_unittest.cc',
       'url_request/url_fetcher_response_writer_unittest.cc',
       'url_request/url_request_context_builder_unittest.cc',
+      'url_request/url_request_context_unittest.cc',
       'url_request/url_request_data_job_unittest.cc',
       'url_request/url_request_file_dir_job_unittest.cc',
       'url_request/url_request_file_job_unittest.cc',
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index 46babc7..bf4055d 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -558,14 +558,6 @@
   return IPAddress::IPv4AllZeros();
 }
 
-void GenerateBody(string* body, int length) {
-  body->clear();
-  body->reserve(length);
-  for (int i = 0; i < length; ++i) {
-    body->append(1, static_cast<char>(32 + i % (126 - 32)));
-  }
-}
-
 QuicEncryptedPacket* ConstructEncryptedPacket(QuicConnectionId connection_id,
                                               bool version_flag,
                                               bool multipath_flag,
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index 6428c1e..617a686b 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -81,8 +81,6 @@
 // Returns an address for 0.0.0.0.
 IPAddress Any4();
 
-void GenerateBody(std::string* body, int length);
-
 // Create an encrypted packet for testing.
 // If versions == nullptr, uses &AllSupportedVersions().
 // Note that the packet is encrypted with NullEncrypter, so to decrypt the
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc
index f0db44e..1bb3add 100644
--- a/net/tools/quic/quic_simple_server_session_test.cc
+++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -33,7 +33,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using net::test::CryptoTestUtils;
-using net::test::GenerateBody;
 using net::test::MockQuicConnection;
 using net::test::MockQuicConnectionHelper;
 using net::test::QuicConfigPeer;
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index 1e3dc4ea..14d6f548 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -8,6 +8,10 @@
 #include "base/debug/alias.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/process_memory_dump.h"
 #include "net/cookies/cookie_store.h"
 #include "net/dns/host_resolver.h"
 #include "net/http/http_transaction_factory.h"
@@ -37,10 +41,15 @@
       sdch_manager_(nullptr),
       network_quality_estimator_(nullptr),
       url_requests_(new std::set<const URLRequest*>),
-      enable_brotli_(false) {}
+      enable_brotli_(false) {
+  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, "URLRequestContext", base::ThreadTaskRunnerHandle::Get());
+}
 
 URLRequestContext::~URLRequestContext() {
   AssertNoURLRequests();
+  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+      this);
 }
 
 void URLRequestContext::CopyFrom(const URLRequestContext* other) {
@@ -108,4 +117,17 @@
   }
 }
 
+bool URLRequestContext::OnMemoryDump(
+    const base::trace_event::MemoryDumpArgs& args,
+    base::trace_event::ProcessMemoryDump* pmd) {
+  if (name_.empty())
+    name_ = "unknown";
+  base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
+      base::StringPrintf("net/url_request_context/%s_%p", name_.c_str(), this));
+  dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
+                  base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+                  url_requests_->size());
+  return true;
+}
+
 }  // namespace net
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index 0158d9ac..24b03bb 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -16,6 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
+#include "base/trace_event/memory_dump_provider.h"
 #include "net/base/net_export.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_network_session.h"
@@ -24,6 +25,12 @@
 #include "net/ssl/ssl_config_service.h"
 #include "net/url_request/url_request.h"
 
+namespace base {
+namespace trace_event {
+class ProcessMemoryDump;
+}
+}
+
 namespace net {
 class CertVerifier;
 class ChannelIDService;
@@ -51,10 +58,11 @@
 // URLRequestContext rather than creating a new one, as guaranteeing that the
 // URLRequestContext is destroyed before its members can be difficult.
 class NET_EXPORT URLRequestContext
-    : NON_EXPORTED_BASE(public base::NonThreadSafe) {
+    : NON_EXPORTED_BASE(public base::NonThreadSafe),
+      public base::trace_event::MemoryDumpProvider {
  public:
   URLRequestContext();
-  virtual ~URLRequestContext();
+  ~URLRequestContext() override;
 
   // Copies the state from |other| into this context.
   void CopyFrom(const URLRequestContext* other);
@@ -230,6 +238,15 @@
 
   bool enable_brotli() const { return enable_brotli_; }
 
+  // Sets a name for this URLRequestContext. Currently the name is used in
+  // MemoryDumpProvier to annotate memory usage. The name does not need to be
+  // unique.
+  void set_name(const std::string& name) { name_ = name; }
+
+  // MemoryDumpProvider implementation:
+  bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+                    base::trace_event::ProcessMemoryDump* pmd) override;
+
  private:
   // ---------------------------------------------------------------------------
   // Important: When adding any new members below, consider whether they need to
@@ -269,6 +286,11 @@
   // Enables Brotli Content-Encoding support.
   bool enable_brotli_;
 
+  // An optional name which can be set to describe this URLRequestContext.
+  // Used in MemoryDumpProvier to annotate memory usage. The name does not need
+  // to be unique.
+  std::string name_;
+
   DISALLOW_COPY_AND_ASSIGN(URLRequestContext);
 };
 
diff --git a/net/url_request/url_request_context_unittest.cc b/net/url_request/url_request_context_unittest.cc
new file mode 100644
index 0000000..627e6f9
--- /dev/null
+++ b/net/url_request/url_request_context_unittest.cc
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/url_request/url_request_context.h"
+
+#include <memory>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "net/proxy/proxy_config_service_fixed.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// Checks if the dump provider runs without crashing and dumps root objects.
+TEST(URLRequestContextTest, MemoryDumpProvider) {
+  base::trace_event::MemoryDumpArgs dump_args = {
+      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
+      new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
+  URLRequestContextBuilder builder;
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  builder.set_proxy_config_service(
+      base::MakeUnique<ProxyConfigServiceFixed>(ProxyConfig::CreateDirect()));
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+  std::unique_ptr<URLRequestContext> context(builder.Build());
+  context->OnMemoryDump(dump_args, process_memory_dump.get());
+  const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
+      allocator_dumps = process_memory_dump->allocator_dumps();
+
+  bool did_dump_url_request_context = false;
+  // bool did_dump_space_stats = false;
+  // bool did_dump_objects_stats = false;
+  for (const auto& it : allocator_dumps) {
+    const std::string& dump_name = it.first;
+    if (dump_name.find("net/url_request_context") != std::string::npos)
+      did_dump_url_request_context = true;
+  }
+
+  ASSERT_TRUE(did_dump_url_request_context);
+}
+
+}  // namespace net
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index 5c7aede..9a31773 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -889,6 +889,9 @@
     // TODO(beng): There may be some cases where it's valid to have an empty
     // spec, so we should probably include a return value in |result|.
     if (result->interface_provider_specs.empty()) {
+      LOG(ERROR)
+          << "Error: The catalog was unable to read a manifest for service \""
+          << result->name << "\".";
       if (!params->connect_callback().is_null())
         params->connect_callback().Run(mojom::ConnectResult::ACCESS_DENIED, "");
       return;
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index 794f258a..381daf2 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -315,19 +315,29 @@
   InFlightWindowManagerChange change;
   if (!GetAndClearInFlightWindowManagerChange(window_manager_change_id,
                                               &change)) {
-    return;
-  }
-  if (!window) {
-    WindowManagerSentBogusMessage();
+    DVLOG(1) << "WindowManager responded with invalid change id; most "
+             << "likely bug in WindowManager processing WmCreateTopLevelWindow "
+             << "change_id=" << window_manager_change_id;
     return;
   }
 
   WindowTree* tree = GetTreeWithId(change.client_id);
   // The window manager should have created the window already, and it should
   // be ready for embedding.
-  if (!tree->IsWaitingForNewTopLevelWindow(window_manager_change_id) ||
-      !window || window->id().client_id != wm_tree->id() ||
-      !window->children().empty() || GetTreeWithRoot(window)) {
+  if (!tree->IsWaitingForNewTopLevelWindow(window_manager_change_id)) {
+    DVLOG(1) << "WindowManager responded with valid change id, but client "
+             << "is not waiting for top-level; possible bug in mus, change_id="
+             << window_manager_change_id;
+    WindowManagerSentBogusMessage();
+    return;
+  }
+  if (window && (window->id().client_id != wm_tree->id() ||
+                 !window->children().empty() || GetTreeWithRoot(window))) {
+    DVLOG(1)
+        << "WindowManager responded with invalid window; window should "
+        << "not have any children, not be the root of a client and should be "
+        << "created by the WindowManager, window_manager_change_id="
+        << window_manager_change_id;
     WindowManagerSentBogusMessage();
     return;
   }
diff --git a/services/ui/ws/window_tree.cc b/services/ui/ws/window_tree.cc
index 23e6d68..a85c4a2 100644
--- a/services/ui/ws/window_tree.cc
+++ b/services/ui/ws/window_tree.cc
@@ -463,6 +463,10 @@
   // We were paused, so the id should still be valid.
   DCHECK(IsValidIdForNewWindow(
       waiting_for_top_level_window_info->client_window_id));
+  if (!window) {
+    client()->OnChangeCompleted(client_change_id, false);
+    return;
+  }
   client_id_to_window_id_map_[waiting_for_top_level_window_info
                                   ->client_window_id] = window->id();
   window_id_to_client_id_map_[window->id()] =
diff --git a/storage/browser/blob/blob_entry.cc b/storage/browser/blob/blob_entry.cc
index 094eb365..8ccc037e 100644
--- a/storage/browser/blob/blob_entry.cc
+++ b/storage/browser/blob/blob_entry.cc
@@ -36,7 +36,19 @@
       transport_allowed_callback(transport_allowed_callback),
       num_building_dependent_blobs(num_building_dependent_blobs) {}
 
-BlobEntry::BuildingState::~BuildingState() {}
+BlobEntry::BuildingState::~BuildingState() {
+  DCHECK(!copy_quota_request);
+  DCHECK(!transport_quota_request);
+}
+
+void BlobEntry::BuildingState::CancelRequests() {
+  if (copy_quota_request) {
+    copy_quota_request->Cancel();
+  }
+  if (transport_quota_request) {
+    transport_quota_request->Cancel();
+  }
+}
 
 BlobEntry::BlobEntry(const std::string& content_type,
                      const std::string& content_disposition)
diff --git a/storage/browser/blob/blob_entry.h b/storage/browser/blob/blob_entry.h
index 3c3869e..72d21fcb 100644
--- a/storage/browser/blob/blob_entry.h
+++ b/storage/browser/blob/blob_entry.h
@@ -24,16 +24,15 @@
 class ShareableBlobDataItem;
 class ViewBlobInternalsJob;
 
-// This class represents a blob in BlobStorageRegistry. We export this only for
-// unit tests.
+// Represents a blob in BlobStorageRegistry. Exported only for unit tests.
 class STORAGE_EXPORT BlobEntry {
  public:
   using TransportAllowedCallback =
       base::Callback<void(BlobStatus,
                           std::vector<BlobMemoryController::FileCreationInfo>)>;
 
-  // This records a copy from a referenced blob. When we finish building our
-  // blob we perform all of these copies.
+  // Records a copy from a referenced blob. Copies happen after referenced blobs
+  // are complete & quota for the copies is granted.
   struct STORAGE_EXPORT ItemCopyEntry {
     ItemCopyEntry(scoped_refptr<ShareableBlobDataItem> source_item,
                   size_t source_item_offset,
@@ -50,11 +49,11 @@
     DISALLOW_COPY_AND_ASSIGN(ItemCopyEntry);
   };
 
-  // This keeps track of our building state for our blob. While building, four
-  // things can be happening mostly simultaneously:
-  // 1. Waiting for quota to be reserved for memory needed (PENDING_QUOTA)
+  // Building state for pending blobs. State can include:
+  // 1. Waiting for quota to be granted for transport data (PENDING_QUOTA)
   // 2. Waiting for user population of data after quota (PENDING_TRANSPORT)
-  // 3. Waiting for blobs we reference to complete (PENDING_INTERNALS)
+  // 3. Waiting for blobs we reference to complete & quota granted for possible
+  //    copies. (PENDING_INTERNALS)
   struct STORAGE_EXPORT BuildingState {
     // |transport_allowed_callback| is not null when data needs population. See
     // BlobStorageContext::BuildBlob for when the callback is called.
@@ -63,6 +62,9 @@
                   size_t num_building_dependent_blobs);
     ~BuildingState();
 
+    // Cancels pending memory or file requests.
+    void CancelRequests();
+
     const bool transport_items_present;
     // We can have trasnport data that's either populated or unpopulated. If we
     // need population, this is populated.
@@ -75,7 +77,10 @@
     size_t num_building_dependent_blobs;
 
     base::WeakPtr<BlobMemoryController::QuotaAllocationTask>
-        memory_quota_request;
+        transport_quota_request;
+
+    // Copy quota is always memory.
+    base::WeakPtr<BlobMemoryController::QuotaAllocationTask> copy_quota_request;
 
     // These are copies from a referenced blob item to our blob items. Some of
     // these entries may have changed from bytes to files if they were paged.
@@ -97,7 +102,9 @@
 
   // Returns if we're a pending blob that can finish building.
   bool CanFinishBuilding() const {
-    return status_ == BlobStatus::PENDING_INTERNALS &&
+    // PENDING_INTERNALS means transport is finished.
+    return status_ == BlobStatus::PENDING_INTERNALS && building_state_ &&
+           !building_state_->copy_quota_request &&
            building_state_->num_building_dependent_blobs == 0;
   }
 
diff --git a/storage/browser/blob/blob_memory_controller.cc b/storage/browser/blob/blob_memory_controller.cc
index 6cc6c3f..f4a002fc 100644
--- a/storage/browser/blob/blob_memory_controller.cc
+++ b/storage/browser/blob/blob_memory_controller.cc
@@ -5,6 +5,7 @@
 #include "storage/browser/blob/blob_memory_controller.h"
 
 #include <algorithm>
+#include <numeric>
 
 #include "base/callback.h"
 #include "base/callback_helpers.h"
@@ -45,6 +46,8 @@
   base::CreateDirectoryAndGetError(blob_storage_dir, &error);
   UMA_HISTOGRAM_ENUMERATION("Storage.Blob.CreateDirectoryResult", -error,
                             -File::FILE_ERROR_MAX);
+  DLOG_IF(ERROR, error != File::FILE_OK)
+      << "Error creating blob storage directory: " << error;
   return error;
 }
 
@@ -74,15 +77,6 @@
       return std::make_pair(std::vector<FileCreationInfo>(),
                             creation_info.error);
     }
-
-    // Grab the file info to get the "last modified" time and store the file.
-    File::Info file_info;
-    bool success = file.GetInfo(&file_info);
-    creation_info.error = success ? File::FILE_OK : File::FILE_ERROR_FAILED;
-    if (!success) {
-      return std::make_pair(std::vector<FileCreationInfo>(),
-                            creation_info.error);
-    }
     creation_info.file = std::move(file);
 
     result.push_back(std::move(creation_info));
@@ -134,6 +128,10 @@
     if (bytes_written < 0)
       break;
   }
+  if (!file.Flush()) {
+    creation_info.error = File::FILE_ERROR_FAILED;
+    return creation_info;
+  }
 
   File::Info info;
   bool success = file.GetInfo(&info);
@@ -162,6 +160,10 @@
   for (const auto& size_pair : file_id_to_sizes) {
     file_sizes_output->push_back(size_pair.second);
   }
+  DCHECK_EQ(std::accumulate(file_sizes_output->begin(),
+                            file_sizes_output->end(), 0ull),
+            total_size_output)
+      << "Illegal builder configuration, temporary files must be totally used.";
   return total_size_output;
 }
 
@@ -298,7 +300,7 @@
   }
   ~FileQuotaAllocationTask() override {}
 
-  void RunDoneCallback(bool success, std::vector<FileCreationInfo> file_info) {
+  void RunDoneCallback(std::vector<FileCreationInfo> file_info, bool success) {
     // Make sure we clear the weak pointers we gave to the caller beforehand.
     weak_factory_.InvalidateWeakPtrs();
 
@@ -313,7 +315,7 @@
       controller_->pending_file_quota_tasks_.erase(my_list_position_);
     }
 
-    done_callback_.Run(success, std::move(file_info));
+    done_callback_.Run(std::move(file_info), success);
   }
 
   base::WeakPtr<QuotaAllocationTask> GetWeakPtr() {
@@ -341,7 +343,7 @@
     for (size_t i = 0; i < files.size(); i++) {
       files[i].file_reference = std::move(references[i]);
     }
-    RunDoneCallback(true, std::move(files));
+    RunDoneCallback(std::move(files), true);
   }
 
   // The my_list_position_ iterator is stored so that we can remove ourself
@@ -379,6 +381,7 @@
 void BlobMemoryController::DisableFilePaging(base::File::Error reason) {
   UMA_HISTOGRAM_ENUMERATION("Storage.Blob.PagingDisabled", -reason,
                             -File::FILE_ERROR_MAX);
+  DLOG(ERROR) << "Blob storage paging disabled, reason: " << reason;
   file_paging_enabled_ = false;
   in_flight_memory_used_ = 0;
   items_paging_to_file_.clear();
@@ -398,7 +401,7 @@
     memory_request->RunDoneCallback(false);
   }
   for (auto& file_request : old_file_tasks) {
-    file_request->RunDoneCallback(false, std::vector<FileCreationInfo>());
+    file_request->RunDoneCallback(std::vector<FileCreationInfo>(), false);
   }
 }
 
diff --git a/storage/browser/blob/blob_memory_controller.h b/storage/browser/blob/blob_memory_controller.h
index 068e22b..865d3e0 100644
--- a/storage/browser/blob/blob_memory_controller.h
+++ b/storage/browser/blob/blob_memory_controller.h
@@ -103,7 +103,7 @@
   // The bool argument is true if we successfully received file quota, and the
   // vector argument provides the file info.
   using FileQuotaRequestCallback =
-      base::Callback<void(bool, std::vector<FileCreationInfo>)>;
+      base::Callback<void(std::vector<FileCreationInfo>, bool)>;
 
   // We enable file paging if |file_runner| isn't a nullptr.
   BlobMemoryController(const base::FilePath& storage_directory,
diff --git a/storage/browser/blob/blob_reader.cc b/storage/browser/blob/blob_reader.cc
index 1ec3002..5584036 100644
--- a/storage/browser/blob/blob_reader.cc
+++ b/storage/browser/blob/blob_reader.cc
@@ -14,6 +14,7 @@
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
+#include "base/debug/stack_trace.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index 1fecda8..acc086e 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -92,9 +92,13 @@
   size_t num_files_with_unknown_size = 0;
   size_t num_building_dependent_blobs = 0;
 
+  bool found_memory_transport = false;
+  bool found_file_transport = false;
+
   base::CheckedNumeric<uint64_t> checked_total_size = 0;
   base::CheckedNumeric<uint64_t> checked_total_memory_size = 0;
-  base::CheckedNumeric<uint64_t> checked_memory_quota_needed = 0;
+  base::CheckedNumeric<uint64_t> checked_transport_quota_needed = 0;
+  base::CheckedNumeric<uint64_t> checked_copy_quota_needed = 0;
 
   for (scoped_refptr<BlobDataItem> input_item : input_builder.items_) {
     const DataElement& input_element = input_item->data_element();
@@ -105,11 +109,19 @@
 
     if (IsBytes(type)) {
       DCHECK_NE(0 + DataElement::kUnknownSize, input_element.length());
-      checked_memory_quota_needed += length;
+      found_memory_transport = true;
+      if (found_file_transport) {
+        // We cannot have both memory and file transport items.
+        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+        return;
+      }
+      contains_unpopulated_transport_items |=
+          (type == DataElement::TYPE_BYTES_DESCRIPTION);
+      checked_transport_quota_needed += length;
       checked_total_size += length;
       scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
           std::move(input_item), ShareableBlobDataItem::QUOTA_NEEDED);
-      pending_memory_items.push_back(item);
+      pending_transport_items.push_back(item);
       transport_items.push_back(item.get());
       output_blob->AppendSharedBlobItem(std::move(item));
       continue;
@@ -174,14 +186,14 @@
         copies.push_back(ItemCopyEntry(slice.first_source_item,
                                        slice.first_item_slice_offset,
                                        slice.dest_items.front()));
-        pending_memory_items.push_back(slice.dest_items.front());
+        pending_copy_items.push_back(slice.dest_items.front());
       }
       if (slice.last_source_item) {
         copies.push_back(
             ItemCopyEntry(slice.last_source_item, 0, slice.dest_items.back()));
-        pending_memory_items.push_back(slice.dest_items.back());
+        pending_copy_items.push_back(slice.dest_items.back());
       }
-      checked_memory_quota_needed += slice.copying_memory_size;
+      checked_copy_quota_needed += slice.copying_memory_size;
 
       for (auto& shareable_item : slice.dest_items) {
         output_blob->AppendSharedBlobItem(std::move(shareable_item));
@@ -189,14 +201,30 @@
       continue;
     }
 
-    DCHECK(!BlobDataBuilder::IsFutureFileItem(input_element))
-        << "File allocation not implemented.";
+    // If the source item is a temporary file item, then we need to keep track
+    // of that and mark it as needing quota.
+    scoped_refptr<ShareableBlobDataItem> item;
+    if (BlobDataBuilder::IsFutureFileItem(input_element)) {
+      found_file_transport = true;
+      if (found_memory_transport) {
+        // We cannot have both memory and file transport items.
+        status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
+        return;
+      }
+      contains_unpopulated_transport_items = true;
+      item = new ShareableBlobDataItem(std::move(input_item),
+                                       ShareableBlobDataItem::QUOTA_NEEDED);
+      pending_transport_items.push_back(item);
+      transport_items.push_back(item.get());
+      checked_transport_quota_needed += length;
+    } else {
+      item = new ShareableBlobDataItem(
+          std::move(input_item),
+          ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
+    }
     if (length == DataElement::kUnknownSize)
       num_files_with_unknown_size++;
 
-    scoped_refptr<ShareableBlobDataItem> item = new ShareableBlobDataItem(
-        std::move(input_item), ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);
-
     checked_total_size += length;
     output_blob->AppendSharedBlobItem(std::move(item));
   }
@@ -206,14 +234,18 @@
     return;
   }
   if (!checked_total_size.IsValid() || !checked_total_memory_size.IsValid() ||
-      !checked_memory_quota_needed.IsValid()) {
+      !checked_transport_quota_needed.IsValid() ||
+      !checked_copy_quota_needed.IsValid()) {
     status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
     return;
   }
   total_size = checked_total_size.ValueOrDie();
   total_memory_size = checked_total_memory_size.ValueOrDie();
-  memory_quota_needed = checked_memory_quota_needed.ValueOrDie();
-  if (memory_quota_needed) {
+  transport_quota_needed = checked_transport_quota_needed.ValueOrDie();
+  copy_quota_needed = checked_copy_quota_needed.ValueOrDie();
+  transport_quota_type = found_file_transport ? TransportQuotaType::FILE
+                                              : TransportQuotaType::MEMORY;
+  if (transport_quota_needed) {
     status = BlobStatus::PENDING_QUOTA;
   } else {
     status = BlobStatus::PENDING_INTERNALS;
@@ -298,8 +330,16 @@
         data_item =
             new BlobDataItem(std::move(element), source_item->data_handle_);
 
-        DCHECK(!BlobDataBuilder::IsFutureFileItem(source_item->data_element()))
-            << "File allocation unimplemented.";
+        if (BlobDataBuilder::IsFutureFileItem(source_item->data_element())) {
+          // The source file isn't a real file yet (path is fake), so store the
+          // items we need to copy from later.
+          if (item_index == first_item_index) {
+            first_item_slice_offset = item_offset;
+            first_source_item = source_items[item_index];
+          } else {
+            last_source_item = source_items[item_index];
+          }
+        }
         break;
       }
       case DataElement::TYPE_FILE_FILESYSTEM: {
@@ -341,8 +381,13 @@
     : memory_controller_(base::FilePath(), scoped_refptr<base::TaskRunner>()),
       ptr_factory_(this) {}
 
-BlobStorageContext::~BlobStorageContext() {
-}
+BlobStorageContext::BlobStorageContext(
+    base::FilePath storage_directory,
+    scoped_refptr<base::TaskRunner> file_runner)
+    : memory_controller_(std::move(storage_directory), std::move(file_runner)),
+      ptr_factory_(this) {}
+
+BlobStorageContext::~BlobStorageContext() {}
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID(
     const std::string& uuid) {
@@ -414,14 +459,9 @@
   // stores the complete item representation in the internal data.
   BlobFlattener flattener(content, entry, &registry_);
 
-  DCHECK(flattener.status != BlobStatus::PENDING_TRANSPORT ||
-         !transport_allowed_callback)
-      << "There is no pending content for the user to populate, so the "
-         "callback should be null.";
-  DCHECK(flattener.status != BlobStatus::PENDING_TRANSPORT ||
+  DCHECK(!flattener.contains_unpopulated_transport_items ||
          transport_allowed_callback)
-      << "If we have pending content then there needs to be a callback "
-         "present.";
+      << "If we have pending unpopulated content then a callback is required";
 
   entry->set_size(flattener.total_size);
   entry->set_status(flattener.status);
@@ -430,8 +470,14 @@
   UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->items().size());
   UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize",
                        flattener.total_memory_size / 1024);
+
+  uint64_t total_memory_needed =
+      flattener.copy_quota_needed +
+      (flattener.transport_quota_type == TransportQuotaType::MEMORY
+           ? flattener.transport_quota_needed
+           : 0);
   UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize",
-                       flattener.memory_quota_needed / 1024);
+                       total_memory_needed / 1024);
 
   size_t num_building_dependent_blobs = 0;
   std::vector<std::unique_ptr<BlobDataHandle>> dependent_blobs;
@@ -454,7 +500,7 @@
   }
 
   entry->set_building_state(base::MakeUnique<BlobEntry::BuildingState>(
-      !flattener.transport_items.empty(), transport_allowed_callback,
+      !flattener.pending_transport_items.empty(), transport_allowed_callback,
       num_building_dependent_blobs));
   BlobEntry::BuildingState* building_state = entry->building_state_.get();
   std::swap(building_state->copies, flattener.copies);
@@ -468,21 +514,52 @@
     return handle;
   }
 
-  if (!memory_controller_.CanReserveQuota(flattener.memory_quota_needed)) {
+  // Avoid the state where we might grant only one quota.
+  if (!memory_controller_.CanReserveQuota(flattener.copy_quota_needed +
+                                          flattener.transport_quota_needed)) {
     CancelBuildingBlobInternal(entry, BlobStatus::ERR_OUT_OF_MEMORY);
     return handle;
   }
 
-  if (flattener.memory_quota_needed > 0) {
-    // The blob can complete during the execution of this line.
+  if (flattener.copy_quota_needed > 0) {
+    // The blob can complete during the execution of |ReserveMemoryQuota|.
     base::WeakPtr<QuotaAllocationTask> pending_request =
         memory_controller_.ReserveMemoryQuota(
-            std::move(flattener.pending_memory_items),
-            base::Bind(&BlobStorageContext::OnEnoughSizeForMemory,
+            std::move(flattener.pending_copy_items),
+            base::Bind(&BlobStorageContext::OnEnoughSpaceForCopies,
                        ptr_factory_.GetWeakPtr(), content.uuid_));
     // Building state will be null if the blob is already finished.
     if (entry->building_state_)
-      entry->building_state_->memory_quota_request = std::move(pending_request);
+      entry->building_state_->copy_quota_request = std::move(pending_request);
+  }
+
+  if (flattener.transport_quota_needed > 0) {
+    base::WeakPtr<QuotaAllocationTask> pending_request;
+
+    switch (flattener.transport_quota_type) {
+      case TransportQuotaType::MEMORY: {
+        // The blob can complete during the execution of |ReserveMemoryQuota|.
+        std::vector<BlobMemoryController::FileCreationInfo> empty_files;
+        pending_request = memory_controller_.ReserveMemoryQuota(
+            std::move(flattener.pending_transport_items),
+            base::Bind(&BlobStorageContext::OnEnoughSpaceForTransport,
+                       ptr_factory_.GetWeakPtr(), content.uuid_,
+                       base::Passed(&empty_files)));
+        break;
+      }
+      case TransportQuotaType::FILE:
+        pending_request = memory_controller_.ReserveFileQuota(
+            std::move(flattener.pending_transport_items),
+            base::Bind(&BlobStorageContext::OnEnoughSpaceForTransport,
+                       ptr_factory_.GetWeakPtr(), content.uuid_));
+        break;
+    }
+
+    // Building state will be null if the blob is already finished.
+    if (entry->building_state_) {
+      entry->building_state_->transport_quota_request =
+          std::move(pending_request);
+    }
   }
 
   if (entry->CanFinishBuilding())
@@ -622,8 +699,26 @@
           const char* src_data =
               copy.source_item->item()->bytes() + copy.source_item_offset;
           copy.dest_item->item()->item_->SetToBytes(src_data, dest_size);
-        } break;
-        case DataElement::TYPE_FILE:
+          break;
+        }
+        case DataElement::TYPE_FILE: {
+          // If we expected a memory item (and our source was paged to disk) we
+          // free that memory.
+          if (dest_type == DataElement::TYPE_BYTES_DESCRIPTION)
+            copy.dest_item->set_memory_allocation(nullptr);
+
+          const DataElement& source_element =
+              copy.source_item->item()->data_element();
+          std::unique_ptr<DataElement> new_element(new DataElement());
+          new_element->SetToFilePathRange(
+              source_element.path(),
+              source_element.offset() + copy.source_item_offset, dest_size,
+              source_element.expected_modification_time());
+          scoped_refptr<BlobDataItem> new_item(new BlobDataItem(
+              std::move(new_element), copy.source_item->item()->data_handle_));
+          copy.dest_item->set_item(std::move(new_item));
+          break;
+        }
         case DataElement::TYPE_UNKNOWN:
         case DataElement::TYPE_BLOB:
         case DataElement::TYPE_BYTES_DESCRIPTION:
@@ -670,8 +765,10 @@
   NotifyTransportCompleteInternal(entry);
 }
 
-void BlobStorageContext::OnEnoughSizeForMemory(const std::string& uuid,
-                                               bool success) {
+void BlobStorageContext::OnEnoughSpaceForTransport(
+    const std::string& uuid,
+    std::vector<BlobMemoryController::FileCreationInfo> files,
+    bool success) {
   if (!success) {
     CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY);
     return;
@@ -680,15 +777,25 @@
   if (!entry || !entry->building_state_.get())
     return;
   BlobEntry::BuildingState& building_state = *entry->building_state_;
-  DCHECK(!building_state.memory_quota_request);
+  DCHECK(!building_state.transport_quota_request);
+  DCHECK(building_state.transport_items_present);
 
-  if (building_state.transport_items_present) {
-    entry->set_status(BlobStatus::PENDING_TRANSPORT);
-    RequestTransport(entry,
-                     std::vector<BlobMemoryController::FileCreationInfo>());
-  } else {
-    entry->set_status(BlobStatus::PENDING_INTERNALS);
+  entry->set_status(BlobStatus::PENDING_TRANSPORT);
+  RequestTransport(entry, std::move(files));
+
+  if (entry->CanFinishBuilding())
+    FinishBuilding(entry);
+}
+
+void BlobStorageContext::OnEnoughSpaceForCopies(const std::string& uuid,
+                                                bool success) {
+  if (!success) {
+    CancelBuildingBlob(uuid, BlobStatus::ERR_OUT_OF_MEMORY);
+    return;
   }
+  BlobEntry* entry = registry_.GetEntry(uuid);
+  if (!entry)
+    return;
 
   if (entry->CanFinishBuilding())
     FinishBuilding(entry);
@@ -716,12 +823,8 @@
 }
 
 void BlobStorageContext::ClearAndFreeMemory(BlobEntry* entry) {
-  if (entry->building_state_) {
-    BlobEntry::BuildingState* building_state = entry->building_state_.get();
-    if (building_state->memory_quota_request) {
-      building_state->memory_quota_request->Cancel();
-    }
-  }
+  if (entry->building_state_)
+    entry->building_state_->CancelRequests();
   entry->ClearItems();
   entry->ClearOffsets();
   entry->set_size(0);
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
index c64581e9..9e068a7 100644
--- a/storage/browser/blob/blob_storage_context.h
+++ b/storage/browser/blob/blob_storage_context.h
@@ -36,6 +36,7 @@
 namespace content {
 class BlobDispatcherHost;
 class BlobDispatcherHostTest;
+class BlobStorageBrowserTest;
 }
 
 namespace storage {
@@ -46,14 +47,17 @@
 class ShareableBlobDataItem;
 
 // This class handles the logistics of blob storage within the browser process.
-// We are single threaded and should only be used on the IO thread. In Chromium
-// there is one instance per profile.
+// This class is not threadsafe, access on IO thread. In Chromium there is one
+// instance per profile.
 class STORAGE_EXPORT BlobStorageContext {
  public:
   using TransportAllowedCallback = BlobEntry::TransportAllowedCallback;
 
   // Initializes the context without disk support.
   BlobStorageContext();
+  // Disk support is enabled if |file_runner| isn't null.
+  BlobStorageContext(base::FilePath storage_directory,
+                     scoped_refptr<base::TaskRunner> file_runner);
   ~BlobStorageContext();
 
   std::unique_ptr<BlobDataHandle> GetBlobDataFromUUID(const std::string& uuid);
@@ -125,6 +129,7 @@
  protected:
   friend class content::BlobDispatcherHost;
   friend class content::BlobDispatcherHostTest;
+  friend class content::BlobStorageBrowserTest;
   friend class BlobTransportHost;
   friend class BlobTransportHostTest;
   friend class BlobDataHandle;
@@ -133,6 +138,8 @@
   friend class BlobSliceTest;
   friend class BlobStorageContextTest;
 
+  enum class TransportQuotaType { MEMORY, FILE };
+
   // Transforms a BlobDataBuilder into a BlobEntry with no blob references.
   // BlobSlice is used to flatten out these references. Records the total size
   // and items for memory and file quota requests.
@@ -152,6 +159,8 @@
     //   reference ourself.
     BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
 
+    bool contains_unpopulated_transport_items = false;
+
     // This is the total size of the blob, including all memory, files, etc.
     uint64_t total_size = 0;
     // Total memory size of the blob (not including files, etc).
@@ -159,14 +168,19 @@
 
     std::vector<std::pair<std::string, BlobEntry*>> dependent_blobs;
 
-    uint64_t memory_quota_needed = 0;
-    std::vector<scoped_refptr<ShareableBlobDataItem>> pending_memory_items;
-
+    TransportQuotaType transport_quota_type = TransportQuotaType::MEMORY;
+    uint64_t transport_quota_needed = 0;
+    std::vector<scoped_refptr<ShareableBlobDataItem>> pending_transport_items;
+    // Hold a separate vector of pointers to declare them as populated.
     std::vector<ShareableBlobDataItem*> transport_items;
 
+    // Copy quota is always memory quota.
+    uint64_t copy_quota_needed = 0;
+    std::vector<scoped_refptr<ShareableBlobDataItem>> pending_copy_items;
+
     // These record all future copies we'll need to do from referenced blobs.
-    // This
-    // happens when we do a partial slice from a pending data or file item.
+    // This happens when we do a partial slice from a pending data or file
+    // item.
     std::vector<BlobEntry::ItemCopyEntry> copies;
 
    private:
@@ -235,7 +249,13 @@
       BlobEntry* entry,
       std::vector<BlobMemoryController::FileCreationInfo> files);
 
-  void OnEnoughSizeForMemory(const std::string& uuid, bool can_fit);
+  // The files array is empty for memory quota request responses.
+  void OnEnoughSpaceForTransport(
+      const std::string& uuid,
+      std::vector<BlobMemoryController::FileCreationInfo> files,
+      bool can_fit);
+
+  void OnEnoughSpaceForCopies(const std::string& uuid, bool can_fit);
 
   void OnDependentBlobFinished(const std::string& owning_blob_uuid,
                                BlobStatus reason);
diff --git a/storage/common/blob_storage/blob_storage_constants.h b/storage/common/blob_storage/blob_storage_constants.h
index f54d20a..b94e886 100644
--- a/storage/common/blob_storage/blob_storage_constants.h
+++ b/storage/common/blob_storage/blob_storage_constants.h
@@ -28,8 +28,8 @@
   size_t max_blob_in_memory_space = 500 * 1024 * 1024;
 
   // This is the maximum amount of disk space we can use.
-  // TODO(dmurph): Consider storage size of the device.
-  uint64_t max_blob_disk_space = 5ull * 1024 * 1024 * 1024;
+  // TODO(dmurph): Determine initial heuristic based on disk usage & arch.
+  uint64_t max_blob_disk_space = 0ull;
 
   // This is the minimum file size we can use when paging blob items to disk.
   // We combine items until we reach at least this size.
@@ -73,12 +73,13 @@
   // Blob state section:
   // The blob has finished.
   DONE = 200,
-  // The system is pending on quota being granted, the transport layer
-  // populating pending data, and/or copying data from dependent blobs. See
-  // BlobEntry::BuildingState determine which of these are happening, as they
-  // all can happen concurrently.
+  // Waiting for memory or file quota for the to-be transported data.
   PENDING_QUOTA = 201,
+  // Waiting for data to be transported (quota has been granted).
   PENDING_TRANSPORT = 202,
+  // Waiting for any operations involving dependent blobs after transport data
+  // has been populated. See BlobEntry::BuildingState for more info.
+  // TODO(dmurph): Change to PENDING_REFERENCED_BLOBS (crbug.com/670398).
   PENDING_INTERNALS = 203,
   LAST = PENDING_INTERNALS
 };
diff --git a/testing/buildbot/filters/OWNERS b/testing/buildbot/filters/OWNERS
index 72e8ffc..ed0dda6 100644
--- a/testing/buildbot/filters/OWNERS
+++ b/testing/buildbot/filters/OWNERS
@@ -1 +1,11 @@
 *
+# PlzNavigate: please check with team before disabling any tests.
+per-file browser-side-navigation*=set noparent
+per-file browser-side-navigation*=ananta@chromium.org
+per-file browser-side-navigation*=arthursonzogni@chromium.org
+per-file browser-side-navigation*=clamy@chromium.org
+per-file browser-side-navigation*=creis@chromium.org
+per-file browser-side-navigation*=jam@chromium.org
+per-file browser-side-navigation*=nasko@chromium.org
+per-file browser-side-navigation*=scottmg@chromium.org
+per-file browser-side-navigation*=yzshen@chromium.org
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=SlimmingPaintInvalidation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=SlimmingPaintInvalidation
index 730bc90..c42f151 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=SlimmingPaintInvalidation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=SlimmingPaintInvalidation
@@ -1,28 +1,6 @@
 # Expectations for SlimmingPaintInvalidation feature
 
-# Rebaselined because of different clipping behavior, sometimes more accurate
-# (e.g. about css clip), sometimes less accurate (e.g. when clip has transforms)
-# which doesn't matter.
-# paint/invalidation/outline-clip-change.html
-# paint/invalidation/scroll-in-transformed-layer.html
-# paint/invalidation/scroll-with-transformed-parent-layer.html
-# paint/invalidation/shift-relative-positioned-container-with-image-addition.html
-
-# Rebaselined: We use FrameView::x() and FrameView::y() which are integers to
-# generate FrameViewpreTranslation, but the old path uses offsets in the layout tree.
-# paint/invalidation/repaint-during-scroll-with-zoom.html
-
-# Rebaselined because we expand local paint invalidation rect to whole pixels
-# before mapping it to backing so it may cover extra pixels causing incremental
-# invalidation not applicable.
-# paint/invalidation/border-radius-repaint-2.html
-# paint/invalidation/flexbox/repaint-rtl-column.html
-# paint/invalidation/flexbox/repaint.html
-# paint/invalidation/line-flow-with-floats-4.html
-# paint/invalidation/line-flow-with-floats-5.html
-# paint/invalidation/window-resize-percent-html.html
-
-# Rebaselined paint/invalidation/svg because we do more accurate pixel snapping
-# for SVGRoot instead of enclosingIntRect() on SVGRoot during rect mapping.
+# These tests run in virtual/spinvalidation suite.
+Bug(none) paint/invalidation [ Skip ]
 
 crbug.com/648274 fast/multicol/span/abspos-containing-block-outside-spanner.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index c9d2be4..c365aec 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -74,6 +74,7 @@
 crbug.com/614910 [ Mac ] virtual/gpu-rasterization/images/pixel-crack-image-background-webkit-transform-scale.html [ Pass Failure ]
 
 crbug.com/619103 paint/invalidation/background-resize-width.html [ Failure ]
+crbug.com/619103 virtual/spinvalidation/paint/invalidation/background-resize-width.html [ Skip ]
 crbug.com/619103 paint/selection/text-selection-newline-mixed-ltr-rtl.html [ Failure ]
 
 # TODO(fmalita): re-enable
@@ -87,6 +88,8 @@
 
 crbug.com/626748 paint/invalidation/table/cached-change-row-border-color.html [ Failure ]
 crbug.com/626748 paint/invalidation/table/cached-change-tbody-border-color.html [ Failure ]
+crbug.com/626748 virtual/spinvalidation/paint/invalidation/table/cached-change-row-border-color.html [ Skip ]
+crbug.com/626748 virtual/spinvalidation/paint/invalidation/table/cached-change-tbody-border-color.html [ Skip ]
 
 # Very slight rendering changes caused by Skia rect clipping change.
 crbug.com/627844 virtual/gpu/fast/canvas/canvas-createImageBitmap-colorClamping.html [ Pass Failure ]
@@ -95,7 +98,8 @@
 
 crbug.com/632000 [ Win ] images/paint-subrect-grid.html [ Pass Failure ]
 
-crbug.com/636271 paint/invalidation/resize-iframe-text.html [ Pass Failure ]
+crbug.com/636271 [ Mac10.10 ] paint/invalidation/resize-iframe-text.html [ Pass Failure ]
+crbug.com/636271 [ Mac10.10 ] virtual/spinvalidation/paint/invalidation/resize-iframe-text.html [ Skip ]
 
 crbug.com/639147 svg/wicd/test-rightsizing-b.xhtml [ Failure Pass ]
 
@@ -110,7 +114,17 @@
 
 crbug.com/646010 paint/selection/text-selection-newline-rtl-double-linebreak.html [ Failure ]
 crbug.com/646015 paint/invalidation/hover-invalidation-table.html [ Failure ]
+crbug.com/646015 virtual/spinvalidation/paint/invalidation/hover-invalidation-table.html [ Skip ]
 crbug.com/646016 paint/invalidation/selected-replaced.html [ Failure ]
+crbug.com/646016 virtual/spinvalidation/paint/invalidation/selected-replaced.html [ Skip ]
+
+crbug.com/671097 virtual/spinvalidation/paint/invalidation/filter-on-html-element-with-fixed-position-child.html [ Crash ]
+crbug.com/671097 virtual/spinvalidation/paint/invalidation/reflection-redraw.html [ Crash ]
+crbug.com/671097 virtual/spinvalidation/paint/invalidation/scroll-fixed-reflected-layer.html [ Crash ]
+
+crbug.com/646176 virtual/spinvalidation/paint/invalidation/svg/resize-svg-invalidate-children-2.html [ Failure ]
+crbug.com/646176 virtual/spinvalidation/paint/invalidation/svg/text-rescale.html [ Failure ]
+crbug.com/646176 virtual/spinvalidation/paint/invalidation/video-paint-invalidation.html [ Failure ]
 
 # ====== Paint team owned tests to here ======
 
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index cf2621d..0cf67f8 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -328,5 +328,10 @@
     "prefix": "feature-policy",
     "base": "http/tests/feature-policy",
     "args": ["--enable-blink-features=FeaturePolicy"]
+  },
+  {
+    "prefix": "spinvalidation",
+    "base": "paint/invalidation",
+    "args": ["--enable-blink-features=SlimmingPaintInvalidation"]
   }
 ]
diff --git a/third_party/WebKit/LayoutTests/fast/block/shrink-to-fit-with-height-stretched-abspos-and-auto-scrollbar-sibling.html b/third_party/WebKit/LayoutTests/fast/block/shrink-to-fit-with-height-stretched-abspos-and-auto-scrollbar-sibling.html
new file mode 100644
index 0000000..b87a6c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/block/shrink-to-fit-with-height-stretched-abspos-and-auto-scrollbar-sibling.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<p>There should be a green square below. No red.</p>
+<div style="float:left; position:relative; background:red;">
+    <div id="abspos" style="position:absolute; top:0; right:0; bottom:0; left:0; background:green;"></div>
+    <div style="width:150px; max-height:150px; overflow:auto;">
+        <div id="child" style="width:100px; height:100px;"></div>
+    </div>
+</div>
+<div style="clear:both;"></div>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+    test(() => {
+        var abspos = document.getElementById("abspos");
+        var child = document.getElementById("child");
+        assert_equals(abspos.offsetWidth, 150);
+        assert_equals(abspos.offsetHeight, 100);
+        document.body.offsetLeft;
+        child.style.height = "400px";
+        assert_equals(abspos.offsetWidth, 150);
+        assert_equals(abspos.offsetHeight, 150);
+    }, "Add content to an overflow:auto container, so that scrollbars appear");
+</script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt
deleted file mode 100644
index 42a2243..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "drawsContent": true,
-      "paintInvalidations": [
-        {
-          "object": "LayoutSVGPath polygon id='polygon'",
-          "rect": [264, 219, 163, 106],
-          "reason": "full"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutSVGPath polygon id='polygon'",
-      "reason": "full"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/fragmentation/auto-scrollbar-shrink-to-fit.html b/third_party/WebKit/LayoutTests/fragmentation/auto-scrollbar-shrink-to-fit.html
new file mode 100644
index 0000000..3d04c7e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fragmentation/auto-scrollbar-shrink-to-fit.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<style>
+    /* Prevent double initial layout. */
+    body { overflow:scroll; }
+</style>
+<p>There should be a blue square below.</p>
+<div style="columns:2; column-fill:auto; height:110px; line-height:20px; orphans:1; widows:1;">
+    <div style="position:relative;">
+        <div style="height:80px;"></div>
+        <div style="position:absolute;">
+            <div><br></div>
+            <!-- #elm doesn't fit in the first column (only 10px left, and it needs 20px),
+                 so it has to be pushed to the next one. -->
+            <div id="elm" style="width:20px; background:blue;"><br></div>
+            <div style="visibility:hidden; overflow-y:auto; height:30px;">
+                <br>
+                <br>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    var elm = document.getElementById("elm");
+    assert_equals(elm.offsetTop, 30);
+}, "Shrink-to-fit with auto vertical scrollbar inside");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/thorough/redirect.js b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/thorough/redirect.js
index 9d72f30..a47e699 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/thorough/redirect.js
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/script-tests/thorough/redirect.js
@@ -211,20 +211,21 @@
   //  [fetchResolved, noContentLength, noServerHeader, hasBody, typeCors],
   //  [methodIsPOST]],
 
-  // Once CORS preflight flag is set, redirecting to the cross-origin is not
-  // allowed.
   // Custom method
   [OTHER_REDIRECT_URL +
    encodeURIComponent(BASE_URL + 'ACAOrigin=*&ACAMethods=PUT') +
    '&mode=cors&credentials=same-origin&method=PUT&ACAOrigin=*&ACAMethods=PUT',
-   [fetchRejected]],
+   [fetchResolved, noContentLength, noServerHeader, hasBody, typeCors],
+   [methodIsPUT, authCheckNone]],
   // Custom header
   [OTHER_REDIRECT_URL +
    encodeURIComponent(
        BASE_URL +
-       'ACAOrigin=' + BASE_ORIGIN + '&ACAHeaders=x-serviceworker-test') +
-   '&mode=cors&credentials=same-origin&method=GET&headers=CUSTOM&ACAOrigin=*',
-   [fetchRejected]],
+       'ACAOrigin=*&ACAHeaders=x-serviceworker-test') +
+   '&mode=cors&credentials=same-origin&method=GET&headers=CUSTOM' +
+   '&ACAOrigin=*&ACAHeaders=x-serviceworker-test',
+   [fetchResolved, noContentLength, noServerHeader, hasBody, typeCors],
+   [methodIsGET, hasCustomHeader, authCheckNone]],
 
   // Redirect: other origin -> other origin
   [OTHER_REDIRECT_URL + encodeURIComponent(OTHER_BASE_URL) +
@@ -293,13 +294,12 @@
    [fetchResolved, noContentLength, hasServerHeader, hasBody, typeCors],
    [methodIsGET, authCheckNone]],
 
-  // Once CORS preflight flag is set, redirecting to the cross-origin is not
-  // allowed.
   // Custom method
   [OTHER_REDIRECT_URL +
    encodeURIComponent(OTHER_BASE_URL + 'ACAOrigin=*&ACAMethods=PUT') +
    '&mode=cors&credentials=same-origin&method=PUT&ACAOrigin=*&ACAMethods=PUT',
-   [fetchRejected]],
+   [fetchResolved, noContentLength, noServerHeader, hasBody, typeCors],
+   [methodIsPUT, authCheckNone]],
   // Custom header
   [OTHER_REDIRECT_URL +
    encodeURIComponent(
@@ -307,7 +307,8 @@
      'ACAOrigin=' + BASE_ORIGIN + '&ACAHeaders=x-serviceworker-test') +
    '&mode=cors&credentials=same-origin&method=GET&headers=CUSTOM' +
    '&ACAOrigin=' + BASE_ORIGIN + '&ACAHeaders=x-serviceworker-test',
-   [fetchRejected]],
+   [fetchResolved, noContentLength, noServerHeader, hasBody, typeCors],
+   [methodIsGET, hasCustomHeader, authCheckNone]],
 ];
 
 if (self.importScripts) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/redirect.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/redirect.php
index af37c0d6..7a24a5fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/redirect.php
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/redirect.php
@@ -1,12 +1,14 @@
 <?php
-if (isset($_GET['Status'])) {
-  header ("HTTP/1.1 " . $_GET["Status"]);
-} else {
-  header ("HTTP/1.1 302");
-}
-$url = $_GET['Redirect'];
-if ($url != "noLocation") {
-  header("Location: $url");
+if ($_SERVER['REQUEST_METHOD'] !== 'OPTIONS') {
+  $url = $_GET['Redirect'];
+  if ($url != "noLocation") {
+    header("Location: $url");
+  }
+  if (isset($_GET['Status'])) {
+    header("HTTP/1.1 " . $_GET["Status"]);
+  } else {
+    header("HTTP/1.1 302");
+  }
 }
 if (isset($_GET['ACAOrigin'])) {
   $origins = explode(',', $_GET['ACAOrigin']);
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt
index bb2e1cd..78bfea2 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async-expected.txt
@@ -1,21 +1,21 @@
 CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' to 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://localhost:8000. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://localhost:8000' to 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000' that is not equal to the supplied origin. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://localhost:8000. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://localhost:8000' has been blocked by CORS policy: Redirect location 'http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' contains userinfo, which is disallowed for cross-origin requests.
-CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&%20%20access-control-allow-origin=http://localhost:8000. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&%20%20access-control-allow-origin=http://localhost:8000' has been blocked by CORS policy: Redirect location 'foo://bar.cgi' has a disallowed scheme for cross-origin requests.
+CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://127.0.0.1:8000. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=http://127.0.0.1:8000' has been blocked by CORS policy: Redirect location 'http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' contains userinfo, which is disallowed for cross-origin requests.
+CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&%20%20access-control-allow-origin=http://127.0.0.1:8000. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&%20%20access-control-allow-origin=http://127.0.0.1:8000' has been blocked by CORS policy: Redirect location 'foo://bar.cgi' has a disallowed scheme for cross-origin requests.
 CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=true&%20%20url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=*. Response for preflight is invalid (redirect)
-CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=false&%20%20url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=*&%20%20access-control-allow-headers=x-webkit. Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=false&%20%20url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&%20%20access-control-allow-origin=*&%20%20access-control-allow-headers=x-webkit' to 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi' has been blocked by CORS policy: Request requires preflight, which is disallowed to follow cross-origin redirect.
+CONSOLE ERROR: XMLHttpRequest cannot load http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi. Request header field x-webkit is not allowed by Access-Control-Allow-Headers in preflight response.
 Tests that asynchronous XMLHttpRequests handle redirects according to the CORS standard.
 
 Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi without credentials
 Expecting success: false
 PASS: 0
-Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&  access-control-allow-origin=http://localhost:8000 without credentials
+Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&  access-control-allow-origin=http://127.0.0.1:8000 without credentials
 Expecting success: true
-FAIL: 0
-Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&  access-control-allow-origin=http://localhost:8000 without credentials
+PASS: PASS: Cross-domain access allowed.
+
+Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&  access-control-allow-origin=http://127.0.0.1:8000 without credentials
 Expecting success: false
 PASS: 0
-Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&  access-control-allow-origin=http://localhost:8000 without credentials
+Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&  access-control-allow-origin=http://127.0.0.1:8000 without credentials
 Expecting success: false
 PASS: 0
 Testing http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?redirect-preflight=true&  url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&  access-control-allow-origin=* without credentials
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async.html
index 83fc3b6..be73388 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async.html
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/access-control-and-redirects-async.html
@@ -49,20 +49,18 @@
 
 // Receives a redirect response with CORS headers. The redirect response passes the access check and the resource response
 // passes the access check.
-// FIXME: this test fails because the redirect is vetoed. There are continued bugs with redirects when the original
-// request was cross-origin.
 ["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
-  access-control-allow-origin=http://localhost:8000",
+  access-control-allow-origin=http://127.0.0.1:8000",
   withoutCredentials, noCustomHeader, succeeds],
 
 // Receives a redirect response with a URL containing the userinfo production.
 ["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=http://username:password@localhost:8000/xmlhttprequest/resources/access-control-basic-allow-star.cgi&\
-  access-control-allow-origin=http://localhost:8000",
+  access-control-allow-origin=http://127.0.0.1:8000",
   withoutCredentials, noCustomHeader, fails],
 
 // Receives a redirect response with a URL with an unsupported scheme.
 ["http://localhost:8000/xmlhttprequest/resources/redirect-cors.php?url=foo://bar.cgi&\
-  access-control-allow-origin=http://localhost:8000",
+  access-control-allow-origin=http://127.0.0.1:8000",
   withoutCredentials, noCustomHeader, fails],
 
 // 2) Test preflighted cross origin requests that receive redirects.
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.em-expected.txt b/third_party/WebKit/LayoutTests/imported/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.em-expected.txt
deleted file mode 100644
index bc79c7a..0000000
--- a/third_party/WebKit/LayoutTests/imported/wpt/offscreen-canvas/the-offscreen-canvas/size.attributes.parse.em-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is a testharness.js-based test.
-FAIL Parsing of non-negative integers assert_equals: offscreenCanvas.height === 100 (got 50[number], expected 100[number]) expected 100 but got 50
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
index 145a0c44..fc6222f 100644
--- a/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/imported/wpt/resources/testharnessreport.js
@@ -14,6 +14,8 @@
 
 (function() {
 
+    var output_document = document;
+
     // Setup for WebKit JavaScript tests
     if (self.testRunner) {
         testRunner.dumpAsText();
@@ -146,12 +148,17 @@
         }
     }, { once: true });
 
+    add_start_callback(function(properties) {
+      if (properties.output_document)
+        output_document = properties.output_document;
+    });
+
     // Using a callback function, test results will be added to the page in a
     // manner that allows dumpAsText to produce readable test results.
     add_completion_callback(function (tests, harness_status) {
 
         // Create element to hold results.
-        var results = document.createElement("pre");
+        var results = output_document.createElement("pre");
 
         // Declare result string.
         var resultStr = "This is a testharness.js-based test.\n";
@@ -167,7 +174,7 @@
         }
         // reflection tests contain huge number of tests, and Chromium code
         // review tool has the 1MB diff size limit. We merge PASS lines.
-        if (document.URL.indexOf("/html/dom/reflection") >= 0) {
+        if (output_document.URL.indexOf("/html/dom/reflection") >= 0) {
             for (var i = 0; i < tests.length; ++i) {
                 if (tests[i].status == 0) {
                     var colon = tests[i].name.indexOf(':');
@@ -215,26 +222,26 @@
                 if (isCSSWGTest() || isJSTest()) {
                     // Anything isn't material to the testrunner output, so
                     // should be hidden from the text dump.
-                    if (document.body && document.body.tagName == 'BODY')
-                        document.body.textContent = '';
+                    if (output_document.body && output_document.body.tagName == 'BODY')
+                        output_document.body.textContent = '';
                 }
             }
 
-            // Add results element to document.
-            if (!document.body || document.body.tagName != 'BODY') {
-                if (!document.documentElement)
-                    document.appendChild(document.createElement('html'));
-                else if (document.body) // document.body is <frameset>.
-                    document.body.remove();
-                document.documentElement.appendChild(document.createElement("body"));
+            // Add results element to output_document.
+            if (!output_document.body || output_document.body.tagName != 'BODY') {
+                if (!output_document.documentElement)
+                    output_document.appendChild(output_document.createElement('html'));
+                else if (output_document.body) // output_document.body is <frameset>.
+                    output_document.body.remove();
+                output_document.documentElement.appendChild(output_document.createElement("body"));
             }
-            document.body.appendChild(results);
+            output_document.body.appendChild(results);
 
             if (self.testRunner)
                 testRunner.notifyDone();
         }
 
-        if (didDispatchLoadEvent || document.readyState != 'loading') {
+        if (didDispatchLoadEvent || output_document.readyState != 'loading') {
             // This function might not be the last 'completion callback', and
             // another completion callback might generate more results.  So, we
             // don't dump the results immediately.
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap-expected.txt b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap-expected.txt
index 8c8bd02..b92608c 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap-expected.txt
@@ -2,6 +2,24 @@
 
 .red,body{color:red}body{background-color:red}
 /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1peGluLmxlc3MiLCJ0ZXN0Lmxlc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsS0NJQSxLREhFLE1BQUEsSUNHRixLQUVFLGlCQUFBIn0=*/
+[expanded] 
+element.style { ()
 
-header.sourceMapURL = data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1peGluLmxlc3MiLCJ0ZXN0Lmxlc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsS0NJQSxLREhFLE1BQUEsSUNHRixLQUVFLGlCQUFBIn0=
+[expanded] 
+body { (test.less:5 -> test.less:5:1)
+    background-color: red;
+
+[expanded] 
+.red, body { (test.less:5 -> test.less:5:1)
+    color: red;
+
+[expanded] 
+body { (user agent stylesheet)
+    display: block;
+    margin: 8px;
+        margin-top: 8px;
+        margin-right: 8px;
+        margin-bottom: 8px;
+        margin-left: 8px;
+
 
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap.html
index cf5470d..9eee6ee0 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap.html
+++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/inline-style-sourcemap.html
@@ -14,14 +14,15 @@
 
 function test()
 {
-    SDK.targetManager.addModelListener(SDK.CSSModel, SDK.CSSModel.Events.StyleSheetAdded, onStyleSheetAdded);
-    InspectorTest.evaluateInPage("embedInlineStyleSheet()", function() { });
+    SDK.targetManager.addModelListener(SDK.CSSModel, SDK.CSSModel.Events.StyleSheetAdded, function() { });
+    InspectorTest.evaluateInPage("embedInlineStyleSheet()", onEvaluated);
 
-    function onStyleSheetAdded(event)
-    {
-        var header = event.data;
+    function onEvaluated() {
+        InspectorTest.selectNodeAndWaitForStyles("inspect", onSelected);
+    }
 
-        InspectorTest.addResult("\nheader.sourceMapURL = " + header.sourceMapURL);
+    function onSelected() {
+        InspectorTest.dumpSelectedElementStyles(true, false, false);
         InspectorTest.completeTest();
     }
 };
@@ -30,7 +31,7 @@
 
 </head>
 
-<body onload="runTest()">
+<body id="inspect" onload="runTest()">
 <p>Verify that inline style sourceMappingURL is resolved properly.</p>
 <pre class="stylesheet-text">.red,body{color:red}body{background-color:red}
 /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm1peGluLmxlc3MiLCJ0ZXN0Lmxlc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsS0NJQSxLREhFLE1BQUEsSUNHRixLQUVFLGlCQUFBIn0=*/</pre>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/flexbox/repaint-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/outline-clip-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/outline-clip-change-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt
new file mode 100644
index 0000000..51d1419
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -0,0 +1,53 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [33, 23, 697, 194],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [33, 23, 697, 194],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGText text",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='dynGrad'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
similarity index 96%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
index e9a7637..8b00c58 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -404,27 +404,27 @@
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
@@ -579,27 +579,27 @@
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
           "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupTriangle__3'",
@@ -699,27 +699,27 @@
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
           "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__0'",
@@ -1175,43 +1175,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Download'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Folder'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__1_content'",
@@ -1279,43 +1279,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Your'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Account'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__2_content'",
@@ -1335,43 +1335,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Help'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox '& Info'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__3_content'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/use-detach-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/use-detach-expected.txt
rename to third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
new file mode 100644
index 0000000..8df5a1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
@@ -0,0 +1,132 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='box'",
+          "rect": [61, 87, 178, 206],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [135, 360, 160, 196],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [135, 361, 159, 194],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [300, 300, 80, 179],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [300, 302, 80, 176],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='box'",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutInline (relative positioned) SPAN id='child'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'A B C'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'D E F'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'G H I'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'J K L'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'M N O'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'P Q R'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'S T U'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'V W X'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'Y Z'",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt
new file mode 100644
index 0000000..f7aa4527
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow OPTION id='option'",
+          "rect": [1, 35, 12, 15],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow OPTION id='option'",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..269125c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,174 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [138, 116, 654, 90],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [138, 116, 654, 90],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [138, 116, 652, 90],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [148, 116, 644, 108],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [148, 116, 644, 108],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [148, 116, 644, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [148, 116, 644, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [148, 116, 632, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [148, 116, 632, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [400, 116, 392, 162],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [400, 116, 392, 162],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [8, 224, 392, 54],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [400, 116, 391, 162],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [148, 116, 252, 162],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [8, 116, 140, 108],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow DIV id='left'",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='content'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'aliquet. Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'feugiat vehicula. Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'condimentum leo neque sed nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'id, faucibus id quam.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='left'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='content'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..6a2832d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,219 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 242, 406, 126],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 476, 406, 90],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 422, 406, 54],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 404, 355, 36],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 386, 304, 36],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 368, 304, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [178, 350, 145, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
+          "rect": [372, 371, 48, 81],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'begin again, it was very provoking to find that the hedgehog'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'unrolled itself, and was in the act of crawling away:'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'besides all\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'this, there was generally a ridge or furrow in the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'way wherever\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'she wanted to send the hedgehog to, and, as the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'doubled-up\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'soldiers were always getting up and walking off to'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'other parts of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the ground, Alice soon came to the conclusion'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'that it was a very\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'difficult game indeed.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'The players all played at once without waiting'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for turns,\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'a very short time '",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Queen'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox ' was in a furious passion, and went\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'stamping'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'her'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'head!\u2019 about once in a minute.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'yet'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'become of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'here; the great\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..2c818b1e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,229 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 242, 406, 126],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 476, 406, 90],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 422, 355, 54],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 404, 355, 36],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [49, 368, 320, 54],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 368, 304, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [49, 368, 301, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [178, 350, 145, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [162, 350, 145, 18],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
+          "rect": [14, 353, 48, 65],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'begin again, it was very provoking to find that the hedgehog'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'unrolled itself, and was in the act of crawling away:'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'besides all\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'this, there was generally a ridge or furrow in the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'way wherever\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'she wanted to send the hedgehog to, and, as the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'doubled-up\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'soldiers were always getting up and walking off to'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'other parts of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the ground, Alice soon came to the conclusion'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'that it was a very\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'difficult game indeed.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'The players all played at once without waiting\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'turns,\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'quarrelling all the while, and fighting for'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the hedgehogs; and in\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'a very short time '",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Queen'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox ' was in a furious passion, and went\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'stamping'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'yet'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'become of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'here; the great\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
new file mode 100644
index 0000000..65ad946
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
@@ -0,0 +1,41 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) A id='link' class='updated'",
+          "rect": [48, 102, 92, 23],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [48, 102, 87, 18],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) A id='link' class='updated'",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'Lorem Ipsum'",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
new file mode 100644
index 0000000..0a5ddfc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -0,0 +1,87 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#C0C0C0",
+      "paintInvalidations": [
+        {
+          "object": "LayoutIFrame (positioned) IFRAME",
+          "rect": [2, 64, 235, 236],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow BODY",
+          "rect": [2, 65, 235, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [2, 65, 235, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [2, 300, 235, 15],
+          "reason": "scroll"
+        },
+        {
+          "object": "LayoutBlockFlow HTML",
+          "rect": [2, 65, 225, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [2, 65, 58, 16],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [237, 65, 15, 235],
+          "reason": "scroll"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutIFrame (positioned) IFRAME",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow HTML",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow BODY",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'scroll me'",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt
new file mode 100644
index 0000000..25617f4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/select-option-background-color-expected.txt
@@ -0,0 +1,28 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow OPTION id='option'",
+          "rect": [1, 35, 11, 15],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow OPTION id='option'",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
new file mode 100644
index 0000000..631b966
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
@@ -0,0 +1,80 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [203, 335, 120, 42],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text id='text'",
+          "rect": [203, 335, 120, 42],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [247, 89, 119, 42],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text id='text'",
+          "rect": [247, 89, 119, 42],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect id='rect'",
+          "rect": [355, 123, 103, 104],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect id='rect'",
+          "rect": [109, 82, 103, 101],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGImage image id='image'",
+          "rect": [90, 206, 98, 97],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGImage image id='image'",
+          "rect": [353, 396, 97, 98],
+          "reason": "full"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGRect rect id='rect'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGText text id='text'",
+      "reason": "full"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'This is some text'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGImage image id='image'",
+      "reason": "full"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
new file mode 100644
index 0000000..5daaef5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
@@ -0,0 +1,122 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='content'",
+          "rect": [0, 14, 753, 366],
+          "reason": "became visible"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 246, 753, 134],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 246, 753, 134],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 129, 596, 135],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 129, 596, 135],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 14, 443, 131],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 14, 443, 131],
+          "reason": "layoutObject insertion"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='fillLinearGradient'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='strokeLinearGradient'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='content'",
+      "reason": "became visible"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on stroke'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill/stroke'",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
new file mode 100644
index 0000000..98798672
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
@@ -0,0 +1,146 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='content'",
+          "rect": [0, 14, 678, 366],
+          "reason": "became visible"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 246, 678, 134],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 246, 678, 134],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 129, 520, 135],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 129, 520, 135],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 14, 367, 131],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 14, 367, 131],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [16, 16, 18, 18],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [16, 16, 18, 18],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [8, 8, 17, 17],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [8, 8, 17, 17],
+          "reason": "layoutObject insertion"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGResourcePattern pattern id='fillPattern'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGResourcePattern pattern id='strokePattern'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='content'",
+      "reason": "became visible"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on fill'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on stroke'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on fill/stroke'",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
similarity index 88%
copy from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
copy to third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
index e9a7637..a1ffc87 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -208,37 +208,37 @@
         },
         {
           "object": "LayoutSVGContainer g id='tabgroupTriangle__0_content'",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text id='contentTabGroupTriangle0'",
-          "rect": [15, 291, 211, 37],
+          "rect": [15, 292, 211, 35],
           "reason": "layoutObject insertion"
         },
         {
@@ -323,482 +323,482 @@
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [15, 291, 150, 25],
+          "rect": [15, 292, 148, 23],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [15, 291, 150, 25],
+          "rect": [15, 292, 148, 23],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [15, 291, 150, 25],
+          "rect": [15, 292, 148, 23],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [15, 291, 150, 25],
+          "rect": [15, 292, 148, 23],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [7, 33, 150, 25],
+          "rect": [7, 34, 148, 23],
           "reason": "layoutObject removal"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [7, 33, 150, 25],
+          "rect": [7, 34, 148, 23],
           "reason": "layoutObject removal"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [7, 33, 150, 25],
+          "rect": [7, 34, 148, 23],
           "reason": "layoutObject removal"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [7, 33, 150, 25],
+          "rect": [7, 34, 148, 23],
           "reason": "layoutObject removal"
         },
         {
-          "object": "LayoutSVGPath path id='tabgroupTriangle__1'",
-          "rect": [61, 256, 67, 31],
+          "object": "LayoutSVGPath path id='tabgroupRectRound__0'",
+          "rect": [362, 279, 63, 62],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectTriangle__0'",
-          "rect": [506, 233, 66, 18],
+          "rect": [506, 233, 63, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRound__0'",
-          "rect": [389, 38, 66, 18],
+          "rect": [389, 38, 63, 18],
           "reason": "layoutObject insertion"
         },
         {
-          "object": "LayoutSVGPath path id='tabgroupRectRound__0'",
-          "rect": [362, 279, 64, 63],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGPath path id='tabgroupRectTriangle__1'",
-          "rect": [569, 233, 64, 18],
+          "object": "LayoutSVGPath path id='tabgroupTriangle__1'",
+          "rect": [60, 256, 62, 31],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectRound__1'",
-          "rect": [415, 331, 63, 63],
+          "rect": [413, 329, 60, 60],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath path id='tabgroupRectTriangle__1'",
+          "rect": [567, 233, 59, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRound__1'",
-          "rect": [452, 38, 63, 18],
+          "rect": [449, 38, 59, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupTriangle__0'",
-          "rect": [6, 256, 58, 31],
+          "rect": [6, 256, 56, 31],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [66, 257, 57, 29],
+          "rect": [394, 39, 54, 15],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [66, 257, 57, 29],
+          "rect": [394, 39, 54, 15],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [66, 257, 57, 29],
+          "rect": [394, 39, 54, 15],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [511, 234, 56, 16],
+          "rect": [511, 235, 54, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [511, 234, 56, 16],
+          "rect": [511, 235, 54, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [511, 234, 56, 16],
+          "rect": [511, 235, 54, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [394, 38, 56, 16],
-          "reason": "layoutObject insertion"
+          "rect": [64, 258, 53, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [64, 258, 53, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [394, 38, 56, 16],
-          "reason": "layoutObject insertion"
+          "rect": [64, 258, 53, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [64, 258, 53, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [394, 38, 56, 16],
-          "reason": "layoutObject insertion"
+          "rect": [64, 258, 53, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupTriangle__2'",
-          "rect": [125, 256, 55, 31],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [574, 234, 54, 16],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [574, 234, 54, 16],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [574, 234, 54, 16],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [457, 38, 54, 16],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [457, 38, 54, 16],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [457, 38, 54, 16],
+          "rect": [120, 256, 52, 31],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectRound__3'",
-          "rect": [506, 422, 53, 53],
+          "rect": [501, 417, 51, 51],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectRound__2'",
-          "rect": [466, 382, 51, 52],
+          "rect": [461, 377, 51, 51],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [370, 285, 50, 50],
+          "rect": [571, 235, 50, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [370, 285, 50, 50],
+          "rect": [571, 235, 50, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [370, 285, 50, 50],
+          "rect": [571, 235, 50, 14],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [454, 39, 50, 14],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [454, 39, 50, 14],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [454, 39, 50, 14],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [370, 286, 48, 47],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [370, 286, 48, 47],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [370, 286, 48, 47],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectTriangle__3'",
-          "rect": [674, 233, 50, 18],
+          "rect": [667, 233, 48, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRound__3'",
-          "rect": [557, 38, 50, 18],
+          "rect": [549, 38, 48, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [422, 337, 49, 49],
+          "rect": [11, 258, 46, 27],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [11, 258, 46, 27],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [422, 337, 49, 49],
+          "rect": [11, 258, 46, 27],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [11, 258, 46, 27],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [422, 337, 49, 49],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [11, 257, 48, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [11, 257, 48, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [11, 257, 48, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [11, 257, 48, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGText text",
-          "rect": [11, 257, 48, 29],
+          "rect": [11, 258, 46, 27],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRectTriangle__2'",
-          "rect": [630, 233, 47, 18],
+          "rect": [623, 233, 46, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRound__2'",
-          "rect": [513, 38, 47, 18],
+          "rect": [506, 38, 46, 18],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGInlineText #text",
-          "rect": [129, 257, 45, 29],
+          "rect": [421, 336, 45, 45],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
-        },
-        {
-          "object": "LayoutSVGTSpan tspan",
-          "rect": [129, 257, 45, 29],
+          "rect": [421, 336, 45, 45],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [129, 257, 45, 29],
+          "rect": [421, 336, 45, 45],
           "reason": "layoutObject insertion"
         },
         {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [124, 258, 44, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [124, 258, 44, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [124, 258, 44, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [124, 258, 44, 27],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [124, 258, 44, 27],
+          "reason": "subtree"
+        },
+        {
           "object": "LayoutSVGPath path id='tabgroupTriangle__3'",
-          "rect": [177, 256, 42, 31],
+          "rect": [170, 256, 41, 31],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [679, 234, 40, 16],
+          "rect": [671, 235, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [679, 234, 40, 16],
+          "rect": [671, 235, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [679, 234, 40, 16],
+          "rect": [671, 235, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [562, 38, 40, 16],
+          "rect": [554, 39, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [562, 38, 40, 16],
+          "rect": [554, 39, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [562, 38, 40, 16],
+          "rect": [554, 39, 39, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [513, 429, 39, 39],
+          "rect": [508, 424, 37, 37],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [513, 429, 39, 39],
+          "rect": [508, 424, 37, 37],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [513, 429, 39, 39],
+          "rect": [508, 424, 37, 37],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [473, 389, 38, 38],
+          "rect": [510, 39, 37, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [473, 389, 38, 38],
+          "rect": [510, 39, 37, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [473, 389, 38, 38],
+          "rect": [510, 39, 37, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [635, 234, 38, 16],
+          "rect": [469, 385, 36, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [635, 234, 38, 16],
+          "rect": [469, 385, 36, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [635, 234, 38, 16],
+          "rect": [469, 385, 36, 35],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [517, 38, 38, 16],
+          "rect": [628, 235, 36, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [517, 38, 38, 16],
+          "rect": [628, 235, 36, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [517, 38, 38, 16],
+          "rect": [628, 235, 36, 14],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [174, 258, 32, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [174, 258, 32, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [174, 258, 32, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [174, 258, 32, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [174, 258, 32, 27],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__0'",
-          "rect": [178, 6, 19, 66],
+          "rect": [178, 6, 19, 63],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__1'",
-          "rect": [178, 69, 19, 64],
+          "rect": [178, 67, 19, 59],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__3'",
-          "rect": [178, 174, 19, 50],
+          "rect": [178, 167, 19, 48],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__2'",
-          "rect": [178, 130, 19, 47],
+          "rect": [178, 123, 19, 46],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [180, 11, 16, 56],
+          "rect": [181, 11, 14, 54],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [180, 11, 16, 56],
+          "rect": [181, 11, 14, 54],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [180, 11, 16, 56],
+          "rect": [181, 11, 14, 54],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [180, 74, 16, 54],
+          "rect": [181, 71, 14, 50],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [180, 74, 16, 54],
+          "rect": [181, 71, 14, 50],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [180, 74, 16, 54],
+          "rect": [181, 71, 14, 50],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [180, 179, 16, 40],
+          "rect": [181, 171, 14, 39],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [180, 179, 16, 40],
+          "rect": [181, 171, 14, 39],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [180, 179, 16, 40],
+          "rect": [181, 171, 14, 39],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [180, 135, 16, 38],
+          "rect": [181, 128, 14, 36],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [180, 135, 16, 38],
+          "rect": [181, 128, 14, 36],
           "reason": "layoutObject insertion"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [180, 135, 16, 38],
+          "rect": [181, 128, 14, 36],
           "reason": "layoutObject insertion"
         }
       ]
@@ -1175,43 +1175,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Download'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Folder'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__1_content'",
@@ -1279,43 +1279,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Your'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Account'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__2_content'",
@@ -1335,43 +1335,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Help'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox '& Info'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__3_content'",
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/window-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/window-expected.txt
new file mode 100644
index 0000000..6eb131e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/svg/window-expected.txt
@@ -0,0 +1,2054 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='Windows'",
+          "rect": [38, 81, 760, 454],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGContainer g id='Windows'",
+          "rect": [38, 92, 760, 443],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [38, 142, 549, 394],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='bigWindow'",
+          "rect": [38, 143, 549, 392],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupbigWindow'",
+          "rect": [38, 143, 549, 392],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect id='titleBarbigWindow'",
+          "rect": [38, 142, 549, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupbigWindow'",
+          "rect": [38, 143, 549, 15],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [38, 523, 549, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [77, 181, 315, 238],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='nestedWindow'",
+          "rect": [77, 182, 315, 236],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupnestedWindow'",
+          "rect": [77, 182, 315, 236],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect id='titleBarnestedWindow'",
+          "rect": [77, 181, 315, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupnestedWindow'",
+          "rect": [77, 182, 315, 15],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [77, 406, 315, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='navWindow'",
+          "rect": [613, 81, 185, 169],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGContainer g id='decoGroupnavWindow'",
+          "rect": [613, 81, 185, 159],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupnavWindow'",
+          "rect": [613, 81, 185, 159],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRect rect id='decoGroupMinimizednavWindow'",
+          "rect": [613, 81, 185, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [624, 92, 174, 159],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='navWindow'",
+          "rect": [624, 92, 174, 158],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupnavWindow'",
+          "rect": [624, 92, 174, 158],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='colourPickerWindow'",
+          "rect": [77, 195, 174, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupcolourPickerWindow'",
+          "rect": [77, 195, 174, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [77, 195, 174, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect id='titleBarcolourPickerWindow'",
+          "rect": [77, 195, 174, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupcolourPickerWindow'",
+          "rect": [77, 195, 174, 15],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [624, 238, 174, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [77, 325, 174, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='textNavWindow'",
+          "rect": [632, 102, 160, 97],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [311, 377, 159, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect id='titleBarsmallWindow'",
+          "rect": [311, 377, 159, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [311, 507, 159, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='smallWindow'",
+          "rect": [312, 377, 158, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupsmallWindow'",
+          "rect": [312, 377, 158, 143],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupsmallWindow'",
+          "rect": [312, 377, 158, 15],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [249, 343, 143, 65],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='statusWindow'",
+          "rect": [249, 344, 143, 64],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupstatusWindow'",
+          "rect": [249, 344, 143, 64],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect id='titleBarstatusWindow'",
+          "rect": [249, 343, 143, 16],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupstatusWindow'",
+          "rect": [249, 344, 143, 15],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [80, 327, 139, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [80, 327, 139, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='textSmallWindow'",
+          "rect": [320, 399, 135, 63],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [80, 183, 132, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [80, 183, 132, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [80, 407, 127, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [80, 407, 127, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [38, 475, 120, 50],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='textStatusWindow'",
+          "rect": [257, 365, 120, 38],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='minimalWindow'",
+          "rect": [39, 476, 119, 48],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowMainGroupminimalWindow'",
+          "rect": [39, 476, 119, 48],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGTSpan tspan",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='textMinimalWindow'",
+          "rect": [43, 481, 112, 36],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [41, 525, 102, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [41, 525, 102, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [314, 509, 91, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [314, 509, 91, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [252, 345, 74, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [252, 345, 74, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [314, 379, 71, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [314, 379, 71, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [80, 197, 67, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [80, 197, 67, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [41, 144, 59, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [41, 144, 59, 13],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='windowTitlebarGroupnavWindow'",
+          "rect": [757, 94, 36, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [627, 239, 34, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [627, 239, 34, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [613, 81, 16, 159],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [615, 99, 12, 11],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [571, 145, 12, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [571, 145, 12, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [235, 197, 12, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [235, 197, 12, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [616, 83, 11, 12],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [616, 83, 11, 12],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [376, 345, 11, 12],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [782, 94, 11, 11],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [782, 94, 11, 11],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [782, 94, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [782, 94, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonnavWindow'",
+          "rect": [769, 94, 11, 11],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonnavWindow'",
+          "rect": [769, 94, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [769, 94, 11, 11],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [769, 94, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [769, 94, 11, 11],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [769, 94, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonbigWindow'",
+          "rect": [558, 145, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [558, 145, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [558, 145, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [454, 379, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [454, 379, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [441, 379, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [376, 184, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [376, 184, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonnestedWindow'",
+          "rect": [363, 184, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [363, 184, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [363, 184, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [222, 197, 11, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonsmallWindow'",
+          "rect": [441, 380, 11, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [441, 380, 11, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonstatusWindow'",
+          "rect": [376, 346, 11, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [376, 346, 11, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [545, 153, 11, 3],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [363, 354, 11, 3],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [756, 103, 11, 2],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [756, 103, 11, 2],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [209, 206, 11, 2],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [617, 153, 10, 81],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [617, 153, 10, 81],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonnestedWindow'",
+          "rect": [377, 184, 10, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [377, 184, 10, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonnavWindow'",
+          "rect": [783, 95, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonnavWindow'",
+          "rect": [783, 95, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [783, 95, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [783, 95, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtonnavWindow'",
+          "rect": [616, 100, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [616, 100, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonnavWindow'",
+          "rect": [616, 84, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [616, 84, 10, 10],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [616, 84, 10, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonbigWindow'",
+          "rect": [572, 145, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [572, 145, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtonsmallWindow'",
+          "rect": [455, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [455, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [455, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonsmallWindow'",
+          "rect": [428, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [428, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [428, 380, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonnestedWindow'",
+          "rect": [350, 185, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [350, 185, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='closeButtoncolourPickerWindow'",
+          "rect": [236, 198, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [236, 198, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='closeButton'",
+          "rect": [236, 198, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='maximizeButtoncolourPickerWindow'",
+          "rect": [223, 198, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+          "rect": [223, 198, 10, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [783, 95, 10, 9],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [783, 95, 10, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonnavWindow'",
+          "rect": [616, 116, 10, 9],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [616, 116, 10, 9],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [616, 116, 10, 9],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [572, 146, 10, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [350, 185, 10, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [616, 123, 10, 3],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [350, 192, 10, 3],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [428, 388, 10, 2],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonnavWindow'",
+          "rect": [757, 95, 9, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonnavWindow'",
+          "rect": [757, 95, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [757, 95, 9, 10],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [757, 95, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonbigWindow'",
+          "rect": [546, 146, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [546, 146, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtonstatusWindow'",
+          "rect": [364, 346, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [364, 346, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [364, 346, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use id='minimizeButtoncolourPickerWindow'",
+          "rect": [210, 198, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [210, 198, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+          "rect": [210, 198, 9, 10],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [757, 95, 9, 9],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [757, 95, 9, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [546, 146, 9, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [377, 185, 9, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [-1, 21, 7, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [-1, 21, 7, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [-1, 21, 7, 11],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGPath line",
+          "rect": [-1, 29, 6, 3],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [0, 22, 5, 9],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [0, 22, 5, 9],
+          "reason": "layoutObject insertion"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGHiddenContainer symbol id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGHiddenContainer symbol id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGHiddenContainer symbol id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='Windows'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='navWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='textNavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This window should'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'contain navigation tools'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Click on button'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox ''Resize Navigation Window' for a'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'random resize of this Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Note that this window also'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'features a window decoration'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Statusbar'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtonnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='bigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This is a big movable window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='nestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This window contains other windows'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='colourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupcolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Changing a colour changes background'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupcolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='titleBarcolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Colour Picker'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtoncolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtoncolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtoncolourPickerWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='statusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupstatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='textStatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This is a none-moveable'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'none-closeable status'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupstatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='titleBarstatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Status Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonstatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonstatusWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='titleBarnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Nested middlesize Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtonnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonnestedWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='smallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='textSmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This window has a callback'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'function indicating mouse'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'movements in the statusbar'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'and alerting window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'events'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Callback function is active'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='titleBarsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Small Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtonsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonsmallWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='minimalWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowMainGroupminimalWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='textMinimalWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'This is a minimal window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'without title and status bar.'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGTSpan tspan",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'it is also not moveable'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupminimalWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='titleBarbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Big Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtonbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonbigWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='Windows'",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGContainer g id='navWindow'",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGContainer g id='windowTitlebarGroupnavWindow'",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGContainer g id='decoGroupnavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect id='decoGroupMinimizednavWindow'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Navigation Window'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use id='closeButtonnavWindow'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='closeButton'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGContainer use id='maximizeButtonnavWindow'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='maximizeButton'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGContainer use id='minimizeButtonnavWindow'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGViewportContainer svg id='minimizeButton'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutSVGPath line",
+      "reason": "bounds change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
new file mode 100644
index 0000000..b15fac01
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
@@ -0,0 +1,132 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='box'",
+          "rect": [66, 85, 168, 192],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [139, 359, 151, 181],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [139, 359, 151, 181],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [300, 300, 80, 162],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [300, 301, 80, 161],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='box'",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutInline (relative positioned) SPAN id='child'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'A B C'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'D E F'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'G H I'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'J K L'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'M N O'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'P Q R'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'S T U'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'V W X'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'Y Z'",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
new file mode 100644
index 0000000..bf4f9a6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/flexbox/repaint-expected.txt
@@ -0,0 +1,174 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [138, 116, 654, 90],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [138, 116, 654, 90],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [138, 116, 652, 89],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [148, 116, 644, 108],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [148, 116, 644, 108],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [148, 116, 644, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [148, 116, 644, 108],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [148, 116, 632, 107],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [148, 116, 632, 107],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='content'",
+          "rect": [400, 116, 392, 162],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow P",
+          "rect": [400, 116, 392, 162],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [8, 224, 392, 54],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [400, 116, 391, 161],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [148, 116, 252, 162],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='left'",
+          "rect": [8, 116, 140, 108],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow DIV id='left'",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='content'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'aliquet. Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'penatibus et magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'feugiat vehicula. Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'condimentum leo neque sed nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'id, faucibus id quam.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='left'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='content'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow P",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
new file mode 100644
index 0000000..230b50ce
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-4-expected.txt
@@ -0,0 +1,219 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 242, 406, 125],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 476, 406, 89],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 422, 406, 53],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 404, 355, 35],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 368, 304, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 386, 303, 35],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [178, 350, 146, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
+          "rect": [372, 371, 48, 81],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'begin again, it was very provoking to find that the hedgehog'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'unrolled itself, and was in the act of crawling away:'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'besides all\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'this, there was generally a ridge or furrow in the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'way wherever\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'she wanted to send the hedgehog to, and, as the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'doubled-up\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'soldiers were always getting up and walking off to'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'other parts of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the ground, Alice soon came to the conclusion'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'that it was a very\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'difficult game indeed.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'The players all played at once without waiting'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow (floating) SPAN id='greenFloat'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for turns,\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'quarrelling all the while, and fighting'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for the hedgehogs; and in\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'a very short time '",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Queen'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox ' was in a furious passion, and went\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'stamping'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'her'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'head!\u2019 about once in a minute.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'yet'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'become of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'here; the great\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
new file mode 100644
index 0000000..17d67d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/line-flow-with-floats-5-expected.txt
@@ -0,0 +1,229 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 242, 406, 125],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 476, 406, 89],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 422, 355, 53],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [14, 404, 355, 35],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [49, 368, 320, 53],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [65, 368, 304, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [49, 368, 301, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [178, 350, 146, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [162, 350, 146, 17],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
+          "rect": [14, 353, 48, 65],
+          "reason": "border box change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'begin again, it was very provoking to find that the hedgehog'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'unrolled itself, and was in the act of crawling away:'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'besides all\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'this, there was generally a ridge or furrow in the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'way wherever\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'she wanted to send the hedgehog to, and, as the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'doubled-up\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'soldiers were always getting up and walking off to'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'other parts of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the ground, Alice soon came to the conclusion'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'that it was a very\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow (floating) SPAN id='blueFloat'",
+      "reason": "border box change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'difficult game indeed.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'The players all played at once without waiting\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'for'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'turns,\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'quarrelling all the while, and fighting for'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the hedgehogs; and in\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'a very short time '",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'the'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Queen'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox ' was in a furious passion, and went\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'stamping'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'about, and shouting \u2018Off with his head!\u2019 or \u2018Off with'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'her head!\u2019 about once in a minute.\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Alice began to feel very uneasy: to be sure, she had not as\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'yet'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'had any dispute with the Queen, but she knew that it might'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'become of\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'me? They\u2019re dreadfully fond of beheading people'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'here; the great\n'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
+      "reason": "forced by layout"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
new file mode 100644
index 0000000..29c6331a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/outline-clip-change-expected.txt
@@ -0,0 +1,41 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) A id='link' class='updated'",
+          "rect": [48, 102, 92, 23],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [48, 102, 87, 17],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) A id='link' class='updated'",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'Lorem Ipsum'",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
new file mode 100644
index 0000000..959466b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -0,0 +1,87 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#C0C0C0",
+      "paintInvalidations": [
+        {
+          "object": "LayoutIFrame (positioned) IFRAME",
+          "rect": [2, 64, 235, 236],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow BODY",
+          "rect": [2, 65, 235, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [2, 65, 235, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [2, 300, 235, 15],
+          "reason": "scroll"
+        },
+        {
+          "object": "LayoutBlockFlow HTML",
+          "rect": [2, 65, 225, 235],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [2, 65, 58, 15],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [237, 65, 15, 235],
+          "reason": "scroll"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutIFrame (positioned) IFRAME",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow HTML",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow BODY",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'scroll me'",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
new file mode 100644
index 0000000..1520256
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/animated-path-inside-transformed-html-expected.txt
@@ -0,0 +1,80 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [247, 88, 120, 43],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text id='text'",
+          "rect": [247, 88, 120, 43],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [203, 334, 120, 43],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text id='text'",
+          "rect": [203, 334, 120, 43],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect id='rect'",
+          "rect": [355, 123, 103, 104],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGRect rect id='rect'",
+          "rect": [109, 82, 103, 101],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGImage image id='image'",
+          "rect": [90, 206, 98, 97],
+          "reason": "full"
+        },
+        {
+          "object": "LayoutSVGImage image id='image'",
+          "rect": [353, 396, 97, 98],
+          "reason": "full"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGRect rect id='rect'",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGText text id='text'",
+      "reason": "full"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "full"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'This is some text'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGImage image id='image'",
+      "reason": "full"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
new file mode 100644
index 0000000..82f9c38
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-and-object-creation-expected.txt
@@ -0,0 +1,122 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='content'",
+          "rect": [0, 15, 759, 362],
+          "reason": "became visible"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 247, 759, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 247, 759, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 130, 596, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 130, 596, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 15, 449, 127],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 15, 449, 127],
+          "reason": "layoutObject insertion"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='fillLinearGradient'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='strokeLinearGradient'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='content'",
+      "reason": "became visible"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on stroke'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill/stroke'",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt
new file mode 100644
index 0000000..62c94821a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-gradient-creation-expected.txt
@@ -0,0 +1,53 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [33, 23, 699, 189],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [33, 23, 699, 189],
+          "reason": "style change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGText text",
+      "reason": "style change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "InlineTextBox 'Gradient on fill'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGResourceLinearGradient linearGradient id='dynGrad'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGGradientStop stop",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
new file mode 100644
index 0000000..f17e76c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/js-late-pattern-and-object-creation-expected.txt
@@ -0,0 +1,146 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='content'",
+          "rect": [0, 15, 684, 362],
+          "reason": "became visible"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 247, 684, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 247, 684, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 130, 520, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 130, 520, 130],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [0, 15, 374, 127],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text",
+          "rect": [0, 15, 374, 127],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [16, 16, 18, 18],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [16, 16, 18, 18],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [8, 8, 17, 17],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGRect rect",
+          "rect": [8, 8, 17, 17],
+          "reason": "layoutObject insertion"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGResourcePattern pattern id='fillPattern'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGResourcePattern pattern id='strokePattern'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGRect rect",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer g id='content'",
+      "reason": "became visible"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on fill'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on stroke'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'Pattern on fill/stroke'",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
similarity index 95%
copy from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
index e9a7637..caba1b3d 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/tabgroup-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/tabgroup-expected.txt
@@ -404,27 +404,27 @@
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
           "rect": [66, 257, 57, 29],
-          "reason": "layoutObject insertion"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
@@ -458,7 +458,7 @@
         },
         {
           "object": "LayoutSVGPath path id='tabgroupTriangle__2'",
-          "rect": [125, 256, 55, 31],
+          "rect": [125, 256, 54, 31],
           "reason": "layoutObject insertion"
         },
         {
@@ -578,32 +578,32 @@
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "rect": [130, 257, 44, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "rect": [130, 257, 44, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "rect": [130, 257, 44, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "rect": [130, 257, 44, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [129, 257, 45, 29],
-          "reason": "layoutObject insertion"
+          "rect": [130, 257, 44, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupTriangle__3'",
-          "rect": [177, 256, 42, 31],
+          "rect": [176, 256, 42, 31],
           "reason": "layoutObject insertion"
         },
         {
@@ -698,28 +698,28 @@
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [181, 257, 32, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGInlineText #text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [181, 257, 32, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [181, 257, 32, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGTSpan tspan",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [181, 257, 32, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGText text",
-          "rect": [182, 257, 31, 29],
-          "reason": "layoutObject insertion"
+          "rect": [181, 257, 32, 29],
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGPath path id='tabgroupRect__0'",
@@ -1175,43 +1175,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Download'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Folder'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__1_content'",
@@ -1279,43 +1279,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Your'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Account'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__2_content'",
@@ -1335,43 +1335,43 @@
     },
     {
       "object": "LayoutSVGText text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "RootInlineBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox 'Help'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGTSpan tspan",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineFlowBox",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGInlineText #text",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "InlineTextBox '& Info'",
-      "reason": "layoutObject insertion"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGHiddenContainer g id='tabgroupTriangle__3_content'",
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
new file mode 100644
index 0000000..a35a3b7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
@@ -0,0 +1,348 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutSVGContainer g id='use'",
+          "rect": [210, 58, 44, 64],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='use'",
+          "rect": [210, 58, 44, 64],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer g id='use'",
+          "rect": [210, 58, 44, 64],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGInlineText #text",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGText text id='use_text'",
+          "rect": [210, 58, 44, 37],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGContainer use",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        },
+        {
+          "object": "LayoutSVGEllipse circle id='use_circle'",
+          "rect": [218, 94, 28, 28],
+          "reason": "layoutObject removal"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGHiddenContainer g id='use'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer g id='use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer g id='use'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGHiddenContainer g id='use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGHiddenContainer g id='use'",
+      "reason": "layoutObject removal"
+    },
+    {
+      "object": "LayoutSVGContainer g id='use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGText text id='use_text'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGInlineText #text",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "InlineTextBox 'use'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGContainer use",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutSVGEllipse circle id='use_circle'",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
new file mode 100644
index 0000000..1b971517
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/spinvalidation/paint/invalidation/transform-inline-layered-child-expected.txt
@@ -0,0 +1,132 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (positioned) DIV id='box'",
+          "rect": [66, 85, 168, 192],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [139, 359, 151, 180],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [139, 359, 151, 180],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutInline (relative positioned) SPAN id='child'",
+          "rect": [300, 300, 80, 161],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [300, 301, 80, 160],
+          "reason": "subtree"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='box'",
+      "reason": "subtree"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutInline (relative positioned) SPAN id='child'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineFlowBox",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'A B C'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'D E F'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'G H I'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'J K L'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'M N O'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'P Q R'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'S T U'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'V W X'",
+      "reason": "subtree"
+    },
+    {
+      "object": "InlineTextBox 'Y Z'",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "subtree"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/resources/testharnessreport.js b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
index 145a0c44..fc6222f 100644
--- a/third_party/WebKit/LayoutTests/resources/testharnessreport.js
+++ b/third_party/WebKit/LayoutTests/resources/testharnessreport.js
@@ -14,6 +14,8 @@
 
 (function() {
 
+    var output_document = document;
+
     // Setup for WebKit JavaScript tests
     if (self.testRunner) {
         testRunner.dumpAsText();
@@ -146,12 +148,17 @@
         }
     }, { once: true });
 
+    add_start_callback(function(properties) {
+      if (properties.output_document)
+        output_document = properties.output_document;
+    });
+
     // Using a callback function, test results will be added to the page in a
     // manner that allows dumpAsText to produce readable test results.
     add_completion_callback(function (tests, harness_status) {
 
         // Create element to hold results.
-        var results = document.createElement("pre");
+        var results = output_document.createElement("pre");
 
         // Declare result string.
         var resultStr = "This is a testharness.js-based test.\n";
@@ -167,7 +174,7 @@
         }
         // reflection tests contain huge number of tests, and Chromium code
         // review tool has the 1MB diff size limit. We merge PASS lines.
-        if (document.URL.indexOf("/html/dom/reflection") >= 0) {
+        if (output_document.URL.indexOf("/html/dom/reflection") >= 0) {
             for (var i = 0; i < tests.length; ++i) {
                 if (tests[i].status == 0) {
                     var colon = tests[i].name.indexOf(':');
@@ -215,26 +222,26 @@
                 if (isCSSWGTest() || isJSTest()) {
                     // Anything isn't material to the testrunner output, so
                     // should be hidden from the text dump.
-                    if (document.body && document.body.tagName == 'BODY')
-                        document.body.textContent = '';
+                    if (output_document.body && output_document.body.tagName == 'BODY')
+                        output_document.body.textContent = '';
                 }
             }
 
-            // Add results element to document.
-            if (!document.body || document.body.tagName != 'BODY') {
-                if (!document.documentElement)
-                    document.appendChild(document.createElement('html'));
-                else if (document.body) // document.body is <frameset>.
-                    document.body.remove();
-                document.documentElement.appendChild(document.createElement("body"));
+            // Add results element to output_document.
+            if (!output_document.body || output_document.body.tagName != 'BODY') {
+                if (!output_document.documentElement)
+                    output_document.appendChild(output_document.createElement('html'));
+                else if (output_document.body) // output_document.body is <frameset>.
+                    output_document.body.remove();
+                output_document.documentElement.appendChild(output_document.createElement("body"));
             }
-            document.body.appendChild(results);
+            output_document.body.appendChild(results);
 
             if (self.testRunner)
                 testRunner.notifyDone();
         }
 
-        if (didDispatchLoadEvent || document.readyState != 'loading') {
+        if (didDispatchLoadEvent || output_document.readyState != 'loading') {
             // This function might not be the last 'completion callback', and
             // another completion callback might generate more results.  So, we
             // don't dump the results immediately.
diff --git a/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/README.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/README.txt
new file mode 100644
index 0000000..0160820
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/README.txt
@@ -0,0 +1,2 @@
+# This suite runs tests with --enable-blink-features=SlimmingPaintInvalidation
+# Owner: wangxianzhu@chromium.org
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/flexbox/repaint-rtl-column-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/flexbox/repaint-rtl-column-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/scroll-in-transformed-layer-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/scroll-in-transformed-layer-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/scroll-in-transformed-layer-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/scroll-in-transformed-layer-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/scroll-with-transformed-parent-layer-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/scroll-with-transformed-parent-layer-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/scroll-with-transformed-parent-layer-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/scroll-with-transformed-parent-layer-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
new file mode 100644
index 0000000..16c08a5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -0,0 +1,100 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [785, 829],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutView #document",
+          "rect": [0, 735, 785, 94],
+          "reason": "incremental"
+        },
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
+          "rect": [8, 180, 769, 641],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
+          "rect": [8, 86, 769, 641],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutIFrame IFRAME id='iframe'",
+          "rect": [8, 86, 732, 94],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutBlockFlow HTML",
+          "rect": [10, 88, 728, 90],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutView #document",
+          "rect": [10, 88, 728, 90],
+          "reason": "style change"
+        },
+        {
+          "object": "LayoutBlockFlow BODY",
+          "rect": [18, 96, 712, 74],
+          "reason": "layoutObject insertion"
+        },
+        {
+          "object": "LayoutImage IMG",
+          "rect": [58, 230, 489, 537],
+          "reason": "bounds change"
+        },
+        {
+          "object": "LayoutImage IMG",
+          "rect": [58, 136, 489, 537],
+          "reason": "bounds change"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutView #document",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutIFrame IFRAME id='iframe'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutBlockFlow (relative positioned) DIV class='relative paddingTop'",
+      "reason": "bounds change"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutImage IMG",
+      "reason": "bounds change"
+    },
+    {
+      "object": "LayoutText #text",
+      "reason": "location change"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow HTML",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutBlockFlow BODY",
+      "reason": "layoutObject insertion"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/absolute-sized-document-no-scrollbars-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/deep-dynamic-updates-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/deep-dynamic-updates-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/deep-dynamic-updates-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/deep-dynamic-updates-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-late-marker-and-object-creation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-marker-creation-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-late-marker-creation-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-late-marker-creation-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-late-marker-creation-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-bounce-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-bounce-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-bounce-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-bounce-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-container-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-container-expected.txt
similarity index 81%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-container-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-container-expected.txt
index f2e512b5..193f53f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-container-expected.txt
@@ -9,17 +9,17 @@
         {
           "object": "LayoutSVGContainer g id='group'",
           "rect": [0, 0, 76, 76],
-          "reason": "full"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGRect rect",
           "rect": [0, 0, 76, 76],
-          "reason": "style change"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGRect rect",
           "rect": [-1, -1, 41, 41],
-          "reason": "style change"
+          "reason": "subtree"
         }
       ]
     }
@@ -27,11 +27,11 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGContainer g id='group'",
-      "reason": "full"
+      "reason": "subtree"
     },
     {
       "object": "LayoutSVGRect rect",
-      "reason": "style change"
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-polygon-changes-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-polygon-changes-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-polygon-changes-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-polygon-changes-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-polygon-removal-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-polygon-removal-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-polygon-removal-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-polygon-removal-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
similarity index 87%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
index 42a2243..2415a2e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutSVGPath polygon id='polygon'",
           "rect": [264, 219, 163, 106],
-          "reason": "full"
+          "reason": "subtree"
         }
       ]
     }
@@ -17,7 +17,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGPath polygon id='polygon'",
-      "reason": "full"
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt
similarity index 87%
copy from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
copy to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt
index 42a2243..2415a2e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/js-update-transform-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/js-update-transform-changes-expected.txt
@@ -9,7 +9,7 @@
         {
           "object": "LayoutSVGPath polygon id='polygon'",
           "rect": [264, 219, 163, 106],
-          "reason": "full"
+          "reason": "subtree"
         }
       ]
     }
@@ -17,7 +17,7 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutSVGPath polygon id='polygon'",
-      "reason": "full"
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/paintorder-filtered-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/paintorder-filtered-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/paintorder-filtered-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/paintorder-filtered-expected.txt
diff --git a/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
new file mode 100644
index 0000000..81243c31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
@@ -0,0 +1,56 @@
+{
+  "layers": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow div id='contentBox'",
+          "rect": [8, 68, 402, 402],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGEllipse circle",
+          "rect": [48, 108, 322, 322],
+          "reason": "SVG resource change"
+        },
+        {
+          "object": "LayoutSVGRoot svg",
+          "rect": [48, 108, 322, 322],
+          "reason": "forced by layout"
+        },
+        {
+          "object": "LayoutSVGEllipse circle",
+          "rect": [8, 151, 102, 236],
+          "reason": "SVG resource change"
+        },
+        {
+          "object": "LayoutSVGRoot svg",
+          "rect": [9, 151, 100, 236],
+          "reason": "forced by layout"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "LayoutBlockFlow div id='contentBox'",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGRoot svg",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutSVGEllipse circle",
+      "reason": "SVG resource change"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/repaint-paintorder-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/repaint-paintorder-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/repaint-paintorder-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/repaint-paintorder-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/stroke-opacity-update-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/stroke-opacity-update-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/stroke-opacity-update-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/stroke-opacity-update-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/use-detach-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
similarity index 100%
copy from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/use-detach-expected.txt
copy to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/use-detach-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/window-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/window-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/svg/window-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/svg/window-expected.txt
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/window-resize-percent-html-expected.txt b/third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/window-resize-percent-html-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=SlimmingPaintInvalidation/paint/invalidation/window-resize-percent-html-expected.txt
rename to third_party/WebKit/LayoutTests/virtual/spinvalidation/paint/invalidation/window-resize-percent-html-expected.txt
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index 02d27786..8d1bdb0 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -391,6 +391,7 @@
   return false;
 }
 
+DISABLE_CFI_PERF
 void LayoutBlockFlow::layoutBlock(bool relayoutChildren) {
   ASSERT(needsLayout());
   ASSERT(isInlineBlockOrInlineTable() || !isInline());
@@ -401,11 +402,39 @@
   LayoutAnalyzer::BlockScope analyzer(*this);
   SubtreeLayoutScope layoutScope(*this);
 
+  LayoutUnit previousHeight = logicalHeight();
+  LayoutUnit oldLeft = logicalLeft();
+  bool logicalWidthChanged = updateLogicalWidthAndColumnWidth();
+  relayoutChildren |= logicalWidthChanged;
+
+  TextAutosizer::LayoutScope textAutosizerLayoutScope(this, &layoutScope);
+  LayoutState state(*this, logicalWidthChanged);
+
+  if (m_paginationStateChanged) {
+    // We now need a deep layout to clean up struts after pagination, if we
+    // just ceased to be paginated, or, if we just became paginated on the
+    // other hand, we now need the deep layout, to insert pagination struts.
+    m_paginationStateChanged = false;
+    state.setPaginationStateChanged();
+  }
+
+  bool preferredLogicalWidthsWereDirty = preferredLogicalWidthsDirty();
+
   // Multiple passes might be required for column based layout.
   // The number of passes could be as high as the number of columns.
   LayoutMultiColumnFlowThread* flowThread = multiColumnFlowThread();
   do {
-    layoutBlockFlow(relayoutChildren, layoutScope);
+    layoutChildren(relayoutChildren, layoutScope);
+
+    if (!preferredLogicalWidthsWereDirty && preferredLogicalWidthsDirty()) {
+      // The only thing that should dirty preferred widths at this point is the
+      // addition of overflow:auto scrollbars in a descendant. To avoid a
+      // potential infinite loop, run layout again with auto scrollbars frozen
+      // in their current state.
+      PaintLayerScrollableArea::FreezeScrollbarsScope freezeScrollbars;
+      relayoutChildren |= updateLogicalWidthAndColumnWidth();
+      layoutChildren(relayoutChildren, layoutScope);
+    }
 
     if (flowThread && flowThread->columnHeightsChanged()) {
       setChildNeedsLayout(MarkOnlyThis);
@@ -419,6 +448,29 @@
     break;
   } while (true);
 
+  // Remember the automatic logical height we got from laying out the children.
+  LayoutUnit unconstrainedHeight = logicalHeight();
+  LayoutUnit unconstrainedClientAfterEdge = clientLogicalBottom();
+
+  // Adjust logical height to satisfy whatever computed style requires.
+  updateLogicalHeight();
+
+  if (!childrenInline())
+    addOverhangingFloatsFromChildren(unconstrainedHeight);
+
+  if (logicalHeight() != previousHeight || isDocumentElement())
+    relayoutChildren = true;
+
+  PositionedLayoutBehavior behavior = DefaultLayout;
+  if (oldLeft != logicalLeft())
+    behavior = ForcedLayoutAfterContainingBlockMoved;
+  layoutPositionedObjects(relayoutChildren, behavior);
+
+  // Add overflow from children.
+  computeOverflow(unconstrainedClientAfterEdge);
+
+  m_descendantsWithFloatsMarkedForLayout = false;
+
   updateLayerTransformAfterLayout();
 
   updateAfterLayout();
@@ -474,23 +526,8 @@
 }
 
 DISABLE_CFI_PERF
-inline void LayoutBlockFlow::layoutBlockFlow(bool relayoutChildren,
-                                             SubtreeLayoutScope& layoutScope) {
-  LayoutUnit oldLeft = logicalLeft();
-  bool logicalWidthChanged = updateLogicalWidthAndColumnWidth();
-  relayoutChildren |= logicalWidthChanged;
-
-  LayoutState state(*this, logicalWidthChanged);
-
-  if (m_paginationStateChanged) {
-    // We now need a deep layout to clean up struts after pagination, if we
-    // just ceased to be paginated, or, if we just became paginated on the
-    // other hand, we now need the deep layout, to insert pagination struts.
-    m_paginationStateChanged = false;
-    state.setPaginationStateChanged();
-  }
-
-  LayoutUnit previousHeight = logicalHeight();
+void LayoutBlockFlow::layoutChildren(bool relayoutChildren,
+                                     SubtreeLayoutScope& layoutScope) {
   resetLayout();
 
   LayoutUnit beforeEdge = borderBefore() + paddingBefore();
@@ -498,55 +535,15 @@
       borderAfter() + paddingAfter() + scrollbarLogicalHeight();
   setLogicalHeight(beforeEdge);
 
-  TextAutosizer::LayoutScope textAutosizerLayoutScope(this, &layoutScope);
-
-  bool preferredLogicalWidthsWereDirty = preferredLogicalWidthsDirty();
-
   if (childrenInline())
     layoutInlineChildren(relayoutChildren, afterEdge);
   else
     layoutBlockChildren(relayoutChildren, layoutScope, beforeEdge, afterEdge);
 
-  bool preferredLogicalWidthsBecameDirty =
-      !preferredLogicalWidthsWereDirty && preferredLogicalWidthsDirty();
-  if (preferredLogicalWidthsBecameDirty) {
-    // The only thing that should dirty preferred widths at this point is the
-    // addition of overflow:auto scrollbars in a descendant. To avoid a
-    // potential infinite loop, run layout again with auto scrollbars frozen in
-    // their current state.
-    PaintLayerScrollableArea::FreezeScrollbarsScope freezeScrollbars;
-    layoutBlockFlow(relayoutChildren, layoutScope);
-    return;
-  }
-
   // Expand our intrinsic height to encompass floats.
   if (lowestFloatLogicalBottom() > (logicalHeight() - afterEdge) &&
       createsNewFormattingContext())
     setLogicalHeight(lowestFloatLogicalBottom() + afterEdge);
-
-  // Remember the automatic logical height we got from laying out the children.
-  LayoutUnit unconstrainedHeight = logicalHeight();
-  LayoutUnit unconstrainedClientAfterEdge = clientLogicalBottom();
-
-  // Adjust logical height to satisfy whatever computed style requires.
-  updateLogicalHeight();
-
-  if (!childrenInline())
-    addOverhangingFloatsFromChildren(unconstrainedHeight);
-
-  if (previousHeight != logicalHeight() || isDocumentElement())
-    relayoutChildren = true;
-
-  PositionedLayoutBehavior behavior = DefaultLayout;
-  if (oldLeft != logicalLeft())
-    behavior = ForcedLayoutAfterContainingBlockMoved;
-  layoutPositionedObjects(relayoutChildren, behavior);
-
-  // Add overflow from children (unless we're multi-column, since in that case
-  // all our child overflow is clipped anyway).
-  computeOverflow(unconstrainedClientAfterEdge);
-
-  m_descendantsWithFloatsMarkedForLayout = false;
 }
 
 void LayoutBlockFlow::addOverhangingFloatsFromChildren(
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index 4cb02a7..75f15e5a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -477,7 +477,7 @@
 
  private:
   void resetLayout();
-  void layoutBlockFlow(bool relayoutChildren, SubtreeLayoutScope&);
+  void layoutChildren(bool relayoutChildren, SubtreeLayoutScope&);
   void addOverhangingFloatsFromChildren(LayoutUnit unconstrainedHeight);
   void layoutBlockChildren(bool relayoutChildren,
                            SubtreeLayoutScope&,
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
index 91753db..1114647c 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_block_node.cc
@@ -97,9 +97,6 @@
     builder.SetAvailableSize(NGLogicalSize(LayoutUnit(), LayoutUnit()));
     builder.SetPercentageResolutionSize(
         NGLogicalSize(LayoutUnit(), LayoutUnit()));
-    // TODO(layoutng): Use builder.ToConstraintSpace.ToLogicalConstraintSpace
-    // once
-    // that's available.
     NGConstraintSpace* constraint_space =
         NGConstraintSpaceBuilder(
             FromPlatformWritingMode(Style()->getWritingMode()))
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index b027093..43e63d0 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -161,7 +161,6 @@
       m_forceDoNotAllowStoredCredentials(false),
       m_securityOrigin(m_resourceLoaderOptions.securityOrigin),
       m_sameOriginRequest(false),
-      m_crossOriginNonSimpleRequest(false),
       m_isUsingDataConsumerHandle(false),
       m_async(blockingBehavior == LoadAsynchronously),
       m_requestContext(WebURLRequest::RequestContextUnspecified),
@@ -374,8 +373,6 @@
     prepareCrossOriginRequest(crossOriginRequest);
     loadRequest(crossOriginRequest, crossOriginOptions);
   } else {
-    m_crossOriginNonSimpleRequest = true;
-
     bool shouldForcePreflight =
         request.isExternalRequest() ||
         InspectorInstrumentation::shouldForceCORSPreflight(m_document);
@@ -560,16 +557,8 @@
   bool allowRedirect = false;
   String accessControlErrorDescription;
 
-  if (m_crossOriginNonSimpleRequest) {
-    // Non-simple cross origin requests (both preflight and actual one) are not
-    // allowed to follow redirect.
-    accessControlErrorDescription =
-        "Redirect from '" + redirectResponse.url().getString() + "' to '" +
-        request.url().getString() +
-        "' has been blocked by CORS policy: Request requires preflight, which "
-        "is disallowed to follow cross-origin redirect.";
-  } else if (!CrossOriginAccessControl::isLegalRedirectLocation(
-                 request.url(), accessControlErrorDescription)) {
+  if (!CrossOriginAccessControl::isLegalRedirectLocation(
+          request.url(), accessControlErrorDescription)) {
     accessControlErrorDescription =
         "Redirect from '" + redirectResponse.url().getString() +
         "' has been blocked by CORS policy: " + accessControlErrorDescription;
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
index 75bd28f2..8af7fc9 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -199,8 +199,6 @@
   // True while the initial URL and all the URLs of the redirects this object
   // has followed, if any, are same-origin to getSecurityOrigin().
   bool m_sameOriginRequest;
-  // Set to true if the current request is cross-origin and not simple.
-  bool m_crossOriginNonSimpleRequest;
 
   // Set to true when the response data is given to a data consumer handle.
   bool m_isUsingDataConsumerHandle;
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 8ec346a..74afd920 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -1003,7 +1003,7 @@
      * @param {!Workspace.UISourceCode} uiSourceCode
      */
     function filterOutService(uiSourceCode) {
-      return !uiSourceCode.isFromServiceProject();
+      return !uiSourceCode.project().isServiceProject();
     }
 
     var uiSourceCodes = Workspace.workspace.uiSourceCodes();
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
index 320eb1c..085c4a46 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/CompilerScriptMapping.js
@@ -57,8 +57,8 @@
     this._stubUISourceCodes = new Map();
 
     var projectId = Bindings.CompilerScriptMapping.projectIdForTarget(this._target);
-    this._stubProject =
-        new Bindings.ContentProviderBasedProject(workspace, projectId, Workspace.projectTypes.Service, '');
+    this._stubProject = new Bindings.ContentProviderBasedProject(
+        workspace, projectId, Workspace.projectTypes.Service, '', true /* isServiceProject */);
     this._eventListeners = [
       workspace.addEventListener(
           Workspace.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedToWorkspace, this),
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
index 4bb95ea7..3e5a1ea 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ContentProviderBasedProject.js
@@ -38,11 +38,13 @@
    * @param {string} id
    * @param {!Workspace.projectTypes} type
    * @param {string} displayName
+   * @param {boolean} isServiceProject
    */
-  constructor(workspace, id, type, displayName) {
+  constructor(workspace, id, type, displayName, isServiceProject) {
     super(workspace, id, type, displayName);
     /** @type {!Object.<string, !Common.ContentProvider>} */
     this._contentProviders = {};
+    this._isServiceProject = isServiceProject;
     workspace.addProject(this);
   }
 
@@ -58,6 +60,14 @@
 
   /**
    * @override
+   * @return {boolean}
+   */
+  isServiceProject() {
+    return this._isServiceProject;
+  }
+
+  /**
+   * @override
    * @param {!Workspace.UISourceCode} uiSourceCode
    * @return {!Promise<?Workspace.UISourceCodeMetadata>}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
index 8e8f0287..095aafce 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/DefaultScriptMapping.js
@@ -41,7 +41,8 @@
     this._debuggerModel = debuggerModel;
     this._debuggerWorkspaceBinding = debuggerWorkspaceBinding;
     var projectId = Bindings.DefaultScriptMapping.projectIdForTarget(debuggerModel.target());
-    this._project = new Bindings.ContentProviderBasedProject(workspace, projectId, Workspace.projectTypes.Debugger, '');
+    this._project = new Bindings.ContentProviderBasedProject(
+        workspace, projectId, Workspace.projectTypes.Debugger, '', true /* isServiceProject */);
     /** @type {!Map.<string, !Workspace.UISourceCode>} */
     this._uiSourceCodeForScriptId = new Map();
     /** @type {!Map.<!Workspace.UISourceCode, string>} */
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
index fce7226..e75c0456 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -173,7 +173,8 @@
     if (project)
       return project;
 
-    project = new Bindings.ContentProviderBasedProject(this._workspace, projectId, projectType, '');
+    project = new Bindings.ContentProviderBasedProject(
+        this._workspace, projectId, projectType, '', false /* isServiceProject */);
     project[Bindings.NetworkProject._targetSymbol] = this.target();
     project[Bindings.NetworkProject._frameSymbol] = frame;
     this._workspaceProjects.set(projectId, project);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
index ef706d1..29e7dcd 100644
--- a/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
+++ b/third_party/WebKit/Source/devtools/front_end/bindings/ResourceScriptMapping.js
@@ -154,7 +154,7 @@
    */
   _uiSourceCodeAdded(event) {
     var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
-    if (uiSourceCode.isFromServiceProject())
+    if (uiSourceCode.project().isServiceProject())
       return;
     var scripts = this._scriptsForUISourceCode(uiSourceCode);
     if (!scripts.length)
@@ -168,7 +168,7 @@
    */
   _uiSourceCodeRemoved(event) {
     var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (event.data);
-    if (uiSourceCode.isFromServiceProject() || !this._boundUISourceCodes.has(uiSourceCode))
+    if (uiSourceCode.project().isServiceProject() || !this._boundUISourceCodes.has(uiSourceCode))
       return;
 
     this._unbindUISourceCode(uiSourceCode);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index 3409efd..badb3a6 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -610,8 +610,10 @@
         this.editable = false;
       } else {
         // Check this is a real CSSRule, not a bogus object coming from Elements.BlankStylePropertiesSection.
-        if (rule.styleSheetId)
-          this.navigable = !!rule.resourceURL();
+        if (rule.styleSheetId) {
+          var header = rule.cssModel().styleSheetHeaderForId(rule.styleSheetId);
+          this.navigable = !header.isAnonymousInlineStyleSheet();
+        }
       }
     }
 
@@ -655,7 +657,7 @@
     }
 
     var header = rule.styleSheetId ? matchedStyles.cssModel().styleSheetHeaderForId(rule.styleSheetId) : null;
-    if (ruleLocation && rule.styleSheetId && header && header.resourceURL()) {
+    if (ruleLocation && rule.styleSheetId && header && !header.isAnonymousInlineStyleSheet()) {
       return Elements.StylePropertiesSection._linkifyRuleLocation(
           matchedStyles.cssModel(), linkifier, rule.styleSheetId, ruleLocation);
     }
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemWorkspaceBinding.js
index a867498..8091642 100644
--- a/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemWorkspaceBinding.js
+++ b/third_party/WebKit/Source/devtools/front_end/persistence/FileSystemWorkspaceBinding.js
@@ -229,6 +229,14 @@
 
   /**
    * @override
+   * @return {boolean}
+   */
+  isServiceProject() {
+    return false;
+  }
+
+  /**
+   * @override
    * @param {!Workspace.UISourceCode} uiSourceCode
    * @return {!Promise<?Workspace.UISourceCodeMetadata>}
    */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js
index 7c3463e..835d7d1 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js
@@ -90,6 +90,13 @@
   isRegular() {
     return this.origin === Protocol.CSS.StyleSheetOrigin.Regular;
   }
+
+  /**
+   * @return {!SDK.CSSModel}
+   */
+  cssModel() {
+    return this._cssModel;
+  }
 };
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js
index 0c4d358..3595ca7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js
@@ -63,6 +63,13 @@
   }
 
   /**
+   * @return {boolean}
+   */
+  isAnonymousInlineStyleSheet() {
+    return !this.resourceURL() && !this._cssModel.sourceMapForHeader(this);
+  }
+
+  /**
    * @return {string}
    */
   resourceURL() {
diff --git a/third_party/WebKit/Source/devtools/front_end/services/ServiceManager.js b/third_party/WebKit/Source/devtools/front_end/services/ServiceManager.js
index f55a4bd..0d08aed 100644
--- a/third_party/WebKit/Source/devtools/front_end/services/ServiceManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/services/ServiceManager.js
@@ -31,7 +31,9 @@
   createAppService(appName, serviceName, isSharedWorker) {
     var url = appName + '.js';
     var remoteBase = Runtime.queryParam('remoteBase');
-    if (remoteBase)
+    // Do not pass additional query parameters to shared worker to avoid URLMismatchError
+    // in case another instance of DevTools with different remoteBase creates same shared worker.
+    if (remoteBase && !isSharedWorker)
       url += '?remoteBase=' + remoteBase;
 
     var worker = isSharedWorker ? new SharedWorker(url, appName) : new Worker(url);
diff --git a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
index f33e26c..0dc5259ff 100644
--- a/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/snippets/ScriptSnippetModel.js
@@ -552,7 +552,7 @@
    * @param {!Snippets.ScriptSnippetModel} model
    */
   constructor(workspace, model) {
-    super(workspace, 'snippets:', Workspace.projectTypes.Snippets, '');
+    super(workspace, 'snippets:', Workspace.projectTypes.Snippets, '', false /* isServiceProject */);
     this._model = model;
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
index 2ef3d1c..defaecf 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -236,7 +236,7 @@
    * @return {boolean}
    */
   accept(uiSourceCode) {
-    return !uiSourceCode.isFromServiceProject();
+    return !uiSourceCode.project().isServiceProject();
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js
index fdc7f3b..f9baca4 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/OpenResourceDialog.js
@@ -61,7 +61,7 @@
    * @return {boolean}
    */
   filterProject(project) {
-    return !Workspace.Project.isServiceProject(project);
+    return !project.isServiceProject();
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
index 80d2952..1576286 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScriptFormatterEditorAction.js
@@ -104,7 +104,8 @@
   constructor() {
     this._projectId = 'formatter:';
     this._project = new Bindings.ContentProviderBasedProject(
-        Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter');
+        Workspace.workspace, this._projectId, Workspace.projectTypes.Formatter, 'formatter',
+        true /* isServiceProject */);
 
     /** @type {!Map.<!SDK.Script, !Workspace.UISourceCode>} */
     this._uiSourceCodes = new Map();
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
index 8ac011a..1508ed0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -831,7 +831,7 @@
       return;
 
     var uiSourceCode = /** @type {!Workspace.UISourceCode} */ (target);
-    if (!uiSourceCode.isFromServiceProject() &&
+    if (!uiSourceCode.project().isServiceProject() &&
         !event.target.isSelfOrDescendant(this._navigatorTabbedLocation.widget().element)) {
       contextMenu.appendItem(
           Common.UIString.capitalize('Reveal in ^navigator'), this._handleContextMenuReveal.bind(this, uiSourceCode));
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
index 030602f..b6f8816 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -253,7 +253,7 @@
    * @param {!Workspace.UISourceCode} uiSourceCode
    */
   _addUISourceCode(uiSourceCode) {
-    if (uiSourceCode.isFromServiceProject())
+    if (uiSourceCode.project().isServiceProject())
       return;
     this._editorContainer.addUISourceCode(uiSourceCode);
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
index 6da0f29..1693e31c 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/UISourceCodeFrame.js
@@ -156,7 +156,7 @@
       return true;
     if (this._uiSourceCode.project().canSetFileContent())
       return true;
-    if (this._uiSourceCode.isFromServiceProject())
+    if (this._uiSourceCode.project().isServiceProject())
       return false;
     return this._uiSourceCode.contentType() !== Common.resourceTypes.Document;
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
index 176fa8e..13276a2 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
@@ -135,13 +135,6 @@
   /**
    * @return {boolean}
    */
-  isFromServiceProject() {
-    return Workspace.Project.isServiceProject(this._project);
-  }
-
-  /**
-   * @return {boolean}
-   */
   canRename() {
     return this._project.canRename();
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
index d908fd9d4..35c1539 100644
--- a/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
+++ b/third_party/WebKit/Source/devtools/front_end/workspace/Workspace.js
@@ -65,15 +65,6 @@
  */
 Workspace.Project = function() {};
 
-/**
- * @param {!Workspace.Project} project
- * @return {boolean}
- */
-Workspace.Project.isServiceProject = function(project) {
-  return project.type() === Workspace.projectTypes.Debugger || project.type() === Workspace.projectTypes.Formatter ||
-      project.type() === Workspace.projectTypes.Service;
-};
-
 Workspace.Project.prototype = {
   /**
    * @return {!Workspace.Workspace}
@@ -91,6 +82,11 @@
   type() {},
 
   /**
+   * @return {boolean}
+   */
+  isServiceProject() {},
+
+  /**
    * @return {string}
    */
   displayName() {},
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp
index 21504c2..b0ade79 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp
@@ -27,11 +27,13 @@
 void ForeignFetchRespondWithObserver::responseWasFulfilled(
     const ScriptValue& value) {
   ASSERT(getExecutionContext());
-  DummyExceptionStateForTesting exceptionState;
+  ExceptionState exceptionState(value.isolate(), ExceptionState::UnknownContext,
+                                "ForeignFetchEvent", "respondWith");
   ForeignFetchResponse foreignFetchResponse =
       ScriptValue::to<ForeignFetchResponse>(toIsolate(getExecutionContext()),
                                             value, exceptionState);
   if (exceptionState.hadException()) {
+    exceptionState.clearException();
     responseWasRejected(WebServiceWorkerResponseErrorNoForeignFetchResponse);
     return;
   }
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
index 700f5a31..cd8b179c 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.cpp
@@ -62,22 +62,46 @@
 }
 
 ServiceWorkerContainer* NavigatorServiceWorker::serviceWorker(
+    ExecutionContext* executionContext,
+    Navigator& navigator,
+    String& errorMessage) {
+  DCHECK(!navigator.frame() ||
+         executionContext->getSecurityOrigin()->canAccessCheckSuborigins(
+             navigator.frame()->securityContext()->getSecurityOrigin()));
+  return NavigatorServiceWorker::from(navigator).serviceWorker(
+      navigator.frame(), errorMessage);
+}
+
+ServiceWorkerContainer* NavigatorServiceWorker::serviceWorker(
     LocalFrame* frame,
     ExceptionState& exceptionState) {
+  String errorMessage;
+  ServiceWorkerContainer* result = serviceWorker(frame, errorMessage);
+  if (!errorMessage.isEmpty()) {
+    DCHECK(!result);
+    exceptionState.throwSecurityError(errorMessage);
+  }
+  return result;
+}
+
+ServiceWorkerContainer* NavigatorServiceWorker::serviceWorker(
+    LocalFrame* frame,
+    String& errorMessage) {
   if (frame &&
       !frame->securityContext()
            ->getSecurityOrigin()
            ->canAccessServiceWorkers()) {
-    if (frame->securityContext()->isSandboxed(SandboxOrigin))
-      exceptionState.throwSecurityError(
+    if (frame->securityContext()->isSandboxed(SandboxOrigin)) {
+      errorMessage =
           "Service worker is disabled because the context is sandboxed and "
-          "lacks the 'allow-same-origin' flag.");
-    else if (frame->securityContext()->getSecurityOrigin()->hasSuborigin())
-      exceptionState.throwSecurityError(
-          "Service worker is disabled because the context is in a suborigin.");
-    else
-      exceptionState.throwSecurityError(
-          "Access to service workers is denied in this document origin.");
+          "lacks the 'allow-same-origin' flag.";
+    } else if (frame->securityContext()->getSecurityOrigin()->hasSuborigin()) {
+      errorMessage =
+          "Service worker is disabled because the context is in a suborigin.";
+    } else {
+      errorMessage =
+          "Access to service workers is denied in this document origin.";
+    }
     return nullptr;
   }
   if (!m_serviceWorker && frame) {
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.h b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.h
index 9ca6e68e..c9abaf27 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigatorServiceWorker.h
@@ -31,12 +31,16 @@
   static ServiceWorkerContainer* serviceWorker(ExecutionContext*,
                                                Navigator&,
                                                ExceptionState&);
+  static ServiceWorkerContainer* serviceWorker(ExecutionContext*,
+                                               Navigator&,
+                                               String& errorMessage);
 
   DECLARE_VIRTUAL_TRACE();
 
  private:
   explicit NavigatorServiceWorker(Navigator&);
   ServiceWorkerContainer* serviceWorker(LocalFrame*, ExceptionState&);
+  ServiceWorkerContainer* serviceWorker(LocalFrame*, String& errorMessage);
 
   static const char* supplementName();
 
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerLinkResource.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerLinkResource.cpp
index 956a15ac..85013d5 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerLinkResource.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerLinkResource.cpp
@@ -79,19 +79,16 @@
     scopeURL = document.completeURL(scope);
   scopeURL.removeFragmentIdentifier();
 
-  DummyExceptionStateForTesting exceptionState;
-
+  String errorMessage;
   ServiceWorkerContainer* container = NavigatorServiceWorker::serviceWorker(
-      &document, *document.frame()->domWindow()->navigator(), exceptionState);
+      &document, *document.frame()->domWindow()->navigator(), errorMessage);
 
   if (!container) {
-    DCHECK(exceptionState.hadException());
-    String message = exceptionState.message();
     document.addConsoleMessage(ConsoleMessage::create(
         JSMessageSource, ErrorMessageLevel,
-        "Cannot register service worker with <link> element. " + message));
+        "Cannot register service worker with <link> element. " + errorMessage));
     makeUnique<RegistrationCallback>(m_owner)->onError(WebServiceWorkerError(
-        WebServiceWorkerError::ErrorTypeSecurity, message));
+        WebServiceWorkerError::ErrorTypeSecurity, errorMessage));
     return;
   }
 
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index bf45bbd..ddc5aa7b 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -201,7 +201,7 @@
 // Handles frame scrolling via the root PaintLayer instead of the FrameView.
 // crbug.com/417782 tracks enabling this by default.
 RootLayerScrolling
-RTCPeerConnectionNewGetStats status=test
+RTCPeerConnectionNewGetStats status=experimental
 ScriptedSpeech status=stable
 // Scrolls to compensate for layout movements (bit.ly/scroll-anchoring).
 ScrollAnchoring status=experimental, settable_from_internals=True
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
index 3d65e94e..ce1c5a6 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
@@ -226,7 +226,7 @@
 void TaskQueueThrottler::TimeBudgetPool::AsValueInto(
     base::trace_event::TracedValue* state,
     base::TimeTicks now) const {
-  state->BeginDictionary();
+  state->BeginDictionary(name_);
 
   state->SetString("name", name_);
   state->SetDouble("time_budget", cpu_percentage_);
diff --git a/tools/gn/command_gen.cc b/tools/gn/command_gen.cc
index aac61e7..26fc729 100644
--- a/tools/gn/command_gen.cc
+++ b/tools/gn/command_gen.cc
@@ -63,8 +63,6 @@
     write_info->rules[target->toolchain()].emplace_back(
         target, std::move(rule));
   }
-
-  g_scheduler->DecrementWorkCount();
 }
 
 // Called on the main thread.
@@ -73,7 +71,6 @@
   const Item* item = record->item();
   const Target* target = item->AsTarget();
   if (target) {
-    g_scheduler->IncrementWorkCount();
     g_scheduler->ScheduleWork(base::Bind(&BackgroundDoWrite,
                                          write_info, target));
   }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 486a2df..8b5e656 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -65569,7 +65569,7 @@
   <owner>zea@chromium.org</owner>
   <summary>
     Time taken from the start of sync shutdown (in ProfileSyncService) until the
-    backend (SyncBackendHost) is fully destroyed.
+    backend (SyncEngine) is fully destroyed.
   </summary>
 </histogram>
 
@@ -65607,7 +65607,7 @@
   <owner>jeremy@chromium.org</owner>
   <owner>zea@google.com</owner>
   <summary>
-    Time spent after ProfileSyncService *creation* but before SyncBackendHost
+    Time spent after ProfileSyncService *creation* but before SyncEngine
     initialization.
   </summary>
 </histogram>
@@ -65616,7 +65616,7 @@
   <owner>jeremy@chromium.org</owner>
   <owner>zea@google.com</owner>
   <summary>
-    Time spent after ProfileSyncService *creation* but before SyncBackendHost
+    Time spent after ProfileSyncService *creation* but before SyncEngine
     initialization.
   </summary>
 </histogram>
diff --git a/ui/aura/mus/window_tree_client.cc b/ui/aura/mus/window_tree_client.cc
index d8c702f..042d000 100644
--- a/ui/aura/mus/window_tree_client.cc
+++ b/ui/aura/mus/window_tree_client.cc
@@ -259,12 +259,13 @@
 }
 
 void WindowTreeClient::Embed(
-    Id window_id,
+    Window* window,
     ui::mojom::WindowTreeClientPtr client,
     uint32_t flags,
     const ui::mojom::WindowTree::EmbedCallback& callback) {
   DCHECK(tree_);
-  tree_->Embed(window_id, std::move(client), flags, callback);
+  tree_->Embed(WindowMus::Get(window)->server_id(), std::move(client), flags,
+               callback);
 }
 
 void WindowTreeClient::AttachCompositorFrameSink(
@@ -1360,6 +1361,11 @@
   }
   Window* window = window_manager_delegate_->OnWmCreateTopLevelWindow(
       window_type, &properties);
+  if (!window) {
+    window_manager_internal_client_->OnWmCreatedTopLevelWindow(
+        change_id, kInvalidServerId);
+    return;
+  }
   embedded_windows_[requesting_client_id].insert(window);
   if (window_manager_internal_client_) {
     window_manager_internal_client_->OnWmCreatedTopLevelWindow(
diff --git a/ui/aura/mus/window_tree_client.h b/ui/aura/mus/window_tree_client.h
index a0dc92a7..6178a69 100644
--- a/ui/aura/mus/window_tree_client.h
+++ b/ui/aura/mus/window_tree_client.h
@@ -115,8 +115,7 @@
                         bool visible,
                         mojo::TextInputStatePtr state);
 
-  // TODO: this should take a window, not an id.
-  void Embed(Id window_id,
+  void Embed(Window* window,
              ui::mojom::WindowTreeClientPtr client,
              uint32_t flags,
              const ui::mojom::WindowTree::EmbedCallback& callback);
diff --git a/ui/events/test/event_generator.cc b/ui/events/test/event_generator.cc
index 4a85eaa6..51e7ed24 100644
--- a/ui/events/test/event_generator.cc
+++ b/ui/events/test/event_generator.cc
@@ -79,7 +79,7 @@
 
 const int kAllButtonMask = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON;
 
-void ConvertToPenPointerEvent(ui::MouseEvent* event) {
+void ConvertToPenPointerEvent(ui::TouchEvent* event) {
   auto details = event->pointer_details();
   details.pointer_type = ui::EventPointerType::POINTER_TYPE_PEN;
   event->set_pointer_details(details);
@@ -660,8 +660,8 @@
 }
 
 void EventGenerator::DoDispatchEvent(ui::Event* event, bool async) {
-  if (pen_pointer_mode_ && event->IsMouseEvent())
-    ConvertToPenPointerEvent(static_cast<ui::MouseEvent*>(event));
+  if (pen_pointer_mode_ && event->IsTouchEvent())
+    ConvertToPenPointerEvent(static_cast<ui::TouchEvent*>(event));
 
   if (async) {
     std::unique_ptr<ui::Event> pending_event = ui::Event::Clone(*event);
diff --git a/ui/gl/gl_version_info.cc b/ui/gl/gl_version_info.cc
index bce8264..8561419 100644
--- a/ui/gl/gl_version_info.cc
+++ b/ui/gl/gl_version_info.cc
@@ -90,16 +90,19 @@
 
   bool has_transform_feedback =
       (IsAtLeastGL(4, 0) || has_extension("GL_ARB_transform_feedback2"));
-  bool has_sampler_indexing =
-      (IsAtLeastGL(4, 0) || has_extension("GL_ARB_gpu_shader5"));
+
+  // This code used to require the GL_ARB_gpu_shader5 extension in order to
+  // have support for dynamic indexing of sampler arrays, which was
+  // optionally supported in ESSL 1.00. However, since this is expressly
+  // forbidden in ESSL 3.00, and some desktop drivers (specifically
+  // Mesa/Gallium on AMD GPUs) don't support it, we no longer require it.
+
   // tex storage is available in core spec since GL 4.2.
   bool has_tex_storage = has_extension("GL_ARB_texture_storage");
 
   // TODO(cwallez) check for texture related extensions. See crbug.com/623577
 
-  return (has_transform_feedback &&
-          has_sampler_indexing &&
-          has_tex_storage);
+  return (has_transform_feedback && has_tex_storage);
 }
 
 void GLVersionInfo::ParseVersionString(const char* version_str,
diff --git a/ui/webui/resources/cr_elements/network/compiled_resources2.gyp b/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
index 89f20bc..decd8225 100644
--- a/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/network/compiled_resources2.gyp
@@ -26,6 +26,7 @@
     {
       'target_name': 'cr_network_list_item',
       'dependencies': [
+        '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.html b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
index c5d4e0e..d4df05a9 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.html
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.html
@@ -4,6 +4,8 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_icon.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html">
+<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
 
@@ -36,6 +38,7 @@
       }
 
       #divOuter {
+        align-items: center;
         border-style: none;
         display: flex;
         flex-direction: row;
@@ -80,6 +83,10 @@
         height: 24px;
         width: 24px;
       }
+
+      cr-policy-network-indicator {
+        padding: 0 var(--cr-icon-padding);
+      }
     </style>
     <div id="divOuter" actionable$="[[isListItem]]"
         first-custom-item$="[[item.isFirstCustomItem]]">
@@ -103,6 +110,11 @@
           [[getNetworkStateText_(networkState, isListItem)]]
         </div>
       </div>
+      <template is="dom-if" if="[[isPolicySource(networkState.Source)]]">
+        <cr-policy-network-indicator
+            indicator-type="[[getIndicatorTypeForSource(networkState.Source)]]">
+        </cr-policy-network-indicator>
+      </template>
       <template is="dom-if"
           if="[[isSettingsButtonVisible_(networkState, showButtons)]]">
         <div id="divButtons">
diff --git a/ui/webui/resources/cr_elements/network/cr_network_list_item.js b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
index 08af24e..8411957 100644
--- a/ui/webui/resources/cr_elements/network/cr_network_list_item.js
+++ b/ui/webui/resources/cr_elements/network/cr_network_list_item.js
@@ -57,7 +57,7 @@
     },
   },
 
-  behaviors: [I18nBehavior],
+  behaviors: [I18nBehavior, CrPolicyNetworkBehavior],
 
   /** @private */
   itemChanged_: function() {
@@ -130,6 +130,7 @@
    * @param {string} state The connection state.
    * @param {string} name The name of the network.
    * @return {string}
+   * @private
    */
   getConnectionStateText_: function(state, name) {
     if (state == CrOnc.ConnectionState.CONNECTED)
diff --git a/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp b/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
index b722f17e..f5974fb4d1 100644
--- a/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
+++ b/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp
@@ -30,6 +30,10 @@
     },
     {
       'target_name': 'cr_policy_network_behavior',
+      'dependencies': [
+        '../network/compiled_resources2.gyp:cr_onc_types',
+        'cr_policy_indicator_behavior',
+      ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
index 32b27be..c052016 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_behavior.js
@@ -68,4 +68,27 @@
     // If no 'Editable' sub-property exists, the policy value is enforced.
     return true;
   },
+
+  /**
+   * @param {String} source
+   * @return {boolean}
+   * @private
+   */
+  isPolicySource: function(source) {
+    return source == CrOnc.Source.DEVICE_POLICY ||
+        source == CrOnc.Source.USER_POLICY;
+  },
+
+  /**
+   * @param {String} source
+   * @return {!CrPolicyIndicatorType}
+   * @private
+   */
+  getIndicatorTypeForSource: function(source) {
+    if (source == CrOnc.Source.DEVICE_POLICY)
+      return CrPolicyIndicatorType.DEVICE_POLICY;
+    if (source == CrOnc.Source.USER_POLICY)
+      return CrPolicyIndicatorType.USER_POLICY;
+    return CrPolicyIndicatorType.NONE;
+  },
 };
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
index d3ca5f4d..ac1e779 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_network_indicator.js
@@ -77,7 +77,7 @@
    * @private
    */
   getTooltip_: function(type, property, recommended) {
-    if (type == CrPolicyIndicatorType.NONE || typeof property != 'object')
+    if (type == CrPolicyIndicatorType.NONE)
       return '';
     if (type == CrPolicyIndicatorType.RECOMMENDED) {
       var value = property.Active;
diff --git a/ui/webui/resources/cr_elements/shared_vars_css.html b/ui/webui/resources/cr_elements/shared_vars_css.html
index e583bca0..8c63992 100644
--- a/ui/webui/resources/cr_elements/shared_vars_css.html
+++ b/ui/webui/resources/cr_elements/shared_vars_css.html
@@ -7,6 +7,8 @@
       cursor: pointer;
     };
     --cr-focused-item-color: var(--google-grey-300);
+    /* Same padding as paper-icon-button. */
+    --cr-icon-padding: 8px;
     --cr-selectable-focus: {
       background-color: var(--cr-focused-item-color);
       outline: none;