diff --git a/DEPS b/DEPS
index 8d6fe70..c6f0fa7f 100644
--- a/DEPS
+++ b/DEPS
@@ -36,7 +36,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '4c1abdcd21d65bb34a6b4aea969ef4485e117e67',
+  'skia_revision': 'c6f411e72b1fea6608f540f64a57bcacbe3378cd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -88,7 +88,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': 'f09349b28951996a459ef05069110cadcddce01e',
+  'catapult_revision': '05755f0b45dad6bad16914ee87671253933d4669',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index 3fca2531..cefa086 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -9,7 +9,10 @@
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
+#include "ash/common/wm/wm_screen_util.h"
+#include "ash/common/wm_lookup.h"
 #include "ash/common/wm_shell.h"
+#include "ash/common/wm_window.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
@@ -78,11 +81,10 @@
 // This calculation excludes the virtual keyboard area. If the height of the
 // display area is less than |minimum_height|, its bottom will be extended to
 // that height (so that the app list never starts above the top of the screen).
-gfx::Point GetCenterOfDisplayForView(const views::View* view,
-                                     int minimum_height) {
-  aura::Window* window = view->GetWidget()->GetNativeView();
-  gfx::Rect bounds = ScreenUtil::GetShelfDisplayBoundsInRoot(window);
-  bounds = ScreenUtil::ConvertRectToScreen(window->GetRootWindow(), bounds);
+gfx::Point GetCenterOfDisplayForView(views::View* view, int minimum_height) {
+  WmWindow* window = WmLookup::Get()->GetWindowForWidget(view->GetWidget());
+  gfx::Rect bounds = wm::GetDisplayBoundsWithShelf(window);
+  bounds = window->GetRootWindow()->ConvertRectToScreen(bounds);
 
   // If the virtual keyboard is active, subtract it from the display bounds, so
   // that the app list is centered in the non-keyboard area of the display.
diff --git a/ash/aura/wm_shell_aura.cc b/ash/aura/wm_shell_aura.cc
index 026f2e07..66d5d94 100644
--- a/ash/aura/wm_shell_aura.cc
+++ b/ash/aura/wm_shell_aura.cc
@@ -97,6 +97,16 @@
   return Shell::GetInstance()->display_manager()->IsActiveDisplayId(display_id);
 }
 
+display::Display WmShellAura::GetFirstDisplay() const {
+  return Shell::GetInstance()
+      ->display_manager()
+      ->software_mirroring_display_list()[0];
+}
+
+bool WmShellAura::IsInUnifiedMode() const {
+  return Shell::GetInstance()->display_manager()->IsInUnifiedMode();
+}
+
 bool WmShellAura::IsForceMaximizeOnFirstRun() {
   return delegate()->IsForceMaximizeOnFirstRun();
 }
diff --git a/ash/aura/wm_shell_aura.h b/ash/aura/wm_shell_aura.h
index 64f7c1f..d6257f2 100644
--- a/ash/aura/wm_shell_aura.h
+++ b/ash/aura/wm_shell_aura.h
@@ -35,6 +35,8 @@
   WmWindow* GetRootWindowForDisplayId(int64_t display_id) override;
   const DisplayInfo& GetDisplayInfo(int64_t display_id) const override;
   bool IsActiveDisplayId(int64_t display_id) const override;
+  display::Display GetFirstDisplay() const override;
+  bool IsInUnifiedMode() const override;
   bool IsForceMaximizeOnFirstRun() override;
   bool IsPinned() override;
   void SetPinnedWindow(WmWindow* window) override;
diff --git a/ash/common/wm/wm_screen_util.cc b/ash/common/wm/wm_screen_util.cc
index 92a268f..fdc7396 100644
--- a/ash/common/wm/wm_screen_util.cc
+++ b/ash/common/wm/wm_screen_util.cc
@@ -5,8 +5,11 @@
 #include "ash/common/wm/wm_screen_util.h"
 
 #include "ash/common/wm_root_window_controller.h"
+#include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
 #include "ui/display/display.h"
+#include "ui/display/screen.h"
+#include "ui/gfx/geometry/size_conversions.h"
 
 namespace ash {
 namespace wm {
@@ -32,5 +35,17 @@
   return GetDisplayBoundsInParent(window);
 }
 
+gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window) {
+  if (WmShell::Get()->IsInUnifiedMode()) {
+    // In unified desktop mode, there is only one shelf in the first display.
+    gfx::SizeF size(WmShell::Get()->GetFirstDisplay().size());
+    float scale = window->GetRootWindow()->GetBounds().height() / size.height();
+    size.Scale(scale, scale);
+    return gfx::Rect(gfx::ToCeiledSize(size));
+  }
+
+  return window->GetRootWindow()->GetBounds();
+}
+
 }  // namespace wm
 }  // namespace ash
diff --git a/ash/common/wm/wm_screen_util.h b/ash/common/wm/wm_screen_util.h
index 6ba858a..6dcfc16 100644
--- a/ash/common/wm/wm_screen_util.h
+++ b/ash/common/wm/wm_screen_util.h
@@ -22,6 +22,12 @@
 ASH_EXPORT gfx::Rect GetDisplayBoundsInParent(WmWindow* window);
 ASH_EXPORT gfx::Rect GetMaximizedWindowBoundsInParent(WmWindow* window);
 
+// Returns the bounds of the physical display containing the shelf for |window|.
+// Physical displays can differ from logical displays in unified desktop mode.
+// TODO(oshima): Consider using physical displays in window layout, instead of
+// root windows, and only use logical display in display management code.
+ASH_EXPORT gfx::Rect GetDisplayBoundsWithShelf(WmWindow* window);
+
 }  // namespace wm
 }  // namespace ash
 
diff --git a/ash/common/wm_shell.h b/ash/common/wm_shell.h
index f672bb08..0f029eb4 100644
--- a/ash/common/wm_shell.h
+++ b/ash/common/wm_shell.h
@@ -18,6 +18,10 @@
 #include "base/observer_list.h"
 #include "ui/base/ui_base_types.h"
 
+namespace display {
+class Display;
+}
+
 namespace gfx {
 class Point;
 }
@@ -162,13 +166,22 @@
   WmWindow* GetRootWindowForNewWindows();
 
   // Retuns the display info associated with |display_id|.
-  // TODO(msw): Remove this when DisplayManager has been moved. crbug.com/622480
+  // TODO(mash): Remove when DisplayManager has been moved. crbug.com/622480
   virtual const DisplayInfo& GetDisplayInfo(int64_t display_id) const = 0;
 
   // Matches that of DisplayManager::IsActiveDisplayId().
-  // TODO: Remove this when DisplayManager has been moved. crbug.com/622480
+  // TODO(mash): Remove when DisplayManager has been moved. crbug.com/622480
   virtual bool IsActiveDisplayId(int64_t display_id) const = 0;
 
+  // Returns true if the desktop is in unified mode.
+  // TODO(mash): Remove when DisplayManager has been moved. crbug.com/622480
+  virtual bool IsInUnifiedMode() const = 0;
+
+  // Returns the first display; this is the first display listed by hardware,
+  // which corresponds to internal displays on devices with integrated displays.
+  // TODO(mash): Remove when DisplayManager has been moved. crbug.com/622480
+  virtual display::Display GetFirstDisplay() const = 0;
+
   // Returns true if the first window shown on first run should be
   // unconditionally maximized, overriding the heuristic that normally chooses
   // the window size.
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc
index a754e19..dd481bb0 100644
--- a/ash/display/window_tree_host_manager_unittest.cc
+++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -6,11 +6,13 @@
 
 #include <memory>
 
+#include "ash/aura/wm_window_aura.h"
 #include "ash/common/ash_switches.h"
 #include "ash/common/display/display_info.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/wm_event.h"
+#include "ash/common/wm/wm_screen_util.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/display_util.h"
@@ -1297,7 +1299,8 @@
   void OnWindowBoundsChanged(aura::Window* window,
                              const gfx::Rect& old_bounds,
                              const gfx::Rect& new_bounds) override {
-    shelf_display_bounds_ = ScreenUtil::GetShelfDisplayBoundsInRoot(window);
+    shelf_display_bounds_ =
+        wm::GetDisplayBoundsWithShelf(WmWindowAura::Get(window));
   }
 
   const gfx::Rect& shelf_display_bounds() const {
@@ -1312,8 +1315,8 @@
 
 }  // names
 
-// Make sure that GetShelfDisplayBoundsInRoot returns the correct bounds
-// when primary display gets replaced in a following scenario.
+// Make sure that GetDisplayBoundsWithShelf returns the correct bounds
+// when the primary display gets replaced in one of the following scenarios:
 // 1) Two displays connected: a) b)
 // 2) both are disconnected and new one with the same size as b) is connected
 // in one configuration event.
diff --git a/ash/mus/bridge/wm_shell_mus.cc b/ash/mus/bridge/wm_shell_mus.cc
index fd32eabc..02943f8d 100644
--- a/ash/mus/bridge/wm_shell_mus.cc
+++ b/ash/mus/bridge/wm_shell_mus.cc
@@ -33,6 +33,7 @@
 #include "services/ui/common/util.h"
 #include "services/ui/public/cpp/window.h"
 #include "services/ui/public/cpp/window_tree_client.h"
+#include "ui/display/screen.h"
 
 namespace ash {
 namespace mus {
@@ -210,17 +211,29 @@
 }
 
 const DisplayInfo& WmShellMus::GetDisplayInfo(int64_t display_id) const {
+  // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   static DisplayInfo fake_info;
   return fake_info;
 }
 
 bool WmShellMus::IsActiveDisplayId(int64_t display_id) const {
-  // TODO: implement http://crbug.com/622480.
+  // TODO(mash): implement http://crbug.com/622480.
   NOTIMPLEMENTED();
   return true;
 }
 
+display::Display WmShellMus::GetFirstDisplay() const {
+  // TODO(mash): implement http://crbug.com/622480.
+  NOTIMPLEMENTED();
+  return display::Screen::GetScreen()->GetPrimaryDisplay();
+}
+
+bool WmShellMus::IsInUnifiedMode() const {
+  // TODO(mash): implement http://crbug.com/622480.
+  return false;
+}
+
 bool WmShellMus::IsForceMaximizeOnFirstRun() {
   NOTIMPLEMENTED();
   return false;
diff --git a/ash/mus/bridge/wm_shell_mus.h b/ash/mus/bridge/wm_shell_mus.h
index 51f3c1d..b66450e 100644
--- a/ash/mus/bridge/wm_shell_mus.h
+++ b/ash/mus/bridge/wm_shell_mus.h
@@ -63,6 +63,8 @@
   WmWindow* GetRootWindowForDisplayId(int64_t display_id) override;
   const DisplayInfo& GetDisplayInfo(int64_t display_id) const override;
   bool IsActiveDisplayId(int64_t display_id) const override;
+  display::Display GetFirstDisplay() const override;
+  bool IsInUnifiedMode() const override;
   bool IsForceMaximizeOnFirstRun() override;
   bool IsPinned() override;
   void SetPinnedWindow(WmWindow* window) override;
diff --git a/ash/screen_util.cc b/ash/screen_util.cc
index 1ffa98c..8da7296 100644
--- a/ash/screen_util.cc
+++ b/ash/screen_util.cc
@@ -53,32 +53,6 @@
 }
 
 // static
-gfx::Rect ScreenUtil::GetShelfDisplayBoundsInRoot(aura::Window* window) {
-  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  if (display_manager->IsInUnifiedMode()) {
-    // In unified desktop mode, there is only one shelf in the 1st display.
-    const display::Display& first =
-        display_manager->software_mirroring_display_list()[0];
-    float scale =
-        static_cast<float>(window->GetRootWindow()->bounds().height()) /
-        first.size().height();
-    gfx::SizeF size(first.size());
-    size.Scale(scale, scale);
-    return gfx::Rect(gfx::ToCeiledSize(size));
-  }
-
-  if (Shell::GetInstance()->in_mus()) {
-    // In mus the RootWindow is the widget's root window, so use the display
-    // bounds.
-    display::Display display =
-        display::Screen::GetScreen()->GetDisplayNearestWindow(window);
-    return display.bounds();
-  }
-
-  return window->GetRootWindow()->bounds();
-}
-
-// static
 gfx::Rect ScreenUtil::ConvertRectToScreen(aura::Window* window,
                                           const gfx::Rect& rect) {
   gfx::Point point = rect.origin();
diff --git a/ash/screen_util.h b/ash/screen_util.h
index 853c12e..22d5a50 100644
--- a/ash/screen_util.h
+++ b/ash/screen_util.h
@@ -40,15 +40,6 @@
   // Returns the display's work area bounds in parent coordinates.
   static gfx::Rect GetDisplayWorkAreaBoundsInParent(aura::Window* window);
 
-  // Returns the physical display bounds containing the shelf that
-  // shares the same root window as |root|. Physical displays can
-  // differ from logical displays in unified desktop mode.
-  // TODO(oshima): If we need to expand the unified desktop support to
-  // general use, we should consider always using physical display in
-  // window layout instead of root window, and keep the logical
-  // display only in display management code.
-  static gfx::Rect GetShelfDisplayBoundsInRoot(aura::Window* window);
-
   // TODO(oshima): Move following two to wm/coordinate_conversion.h
   // Converts |rect| from |window|'s coordinates to the virtual screen
   // coordinates.
diff --git a/ash/screen_util_unittest.cc b/ash/screen_util_unittest.cc
index 095cabd..77d33c3 100644
--- a/ash/screen_util_unittest.cc
+++ b/ash/screen_util_unittest.cc
@@ -4,6 +4,9 @@
 
 #include "ash/screen_util.h"
 
+#include "ash/common/wm/wm_screen_util.h"
+#include "ash/common/wm_lookup.h"
+#include "ash/common/wm_window.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
 #include "ash/test/ash_md_test_base.h"
@@ -129,30 +132,23 @@
 
   views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
       NULL, CurrentContext(), gfx::Rect(10, 10, 100, 100));
+  WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget);
 
   UpdateDisplay("500x400");
-  EXPECT_EQ("0,0 500x400",
-            ScreenUtil::GetShelfDisplayBoundsInRoot(widget->GetNativeWindow())
-                .ToString());
+  EXPECT_EQ("0,0 500x400", wm::GetDisplayBoundsWithShelf(window).ToString());
 
   UpdateDisplay("500x400,600x400");
-  EXPECT_EQ("0,0 500x400",
-            ScreenUtil::GetShelfDisplayBoundsInRoot(widget->GetNativeWindow())
-                .ToString());
+  EXPECT_EQ("0,0 500x400", wm::GetDisplayBoundsWithShelf(window).ToString());
 
   // Move to the 2nd physical display. Shelf's display still should be
   // the first.
   widget->SetBounds(gfx::Rect(800, 0, 100, 100));
   ASSERT_EQ("800,0 100x100", widget->GetWindowBoundsInScreen().ToString());
 
-  EXPECT_EQ("0,0 500x400",
-            ScreenUtil::GetShelfDisplayBoundsInRoot(widget->GetNativeWindow())
-                .ToString());
+  EXPECT_EQ("0,0 500x400", wm::GetDisplayBoundsWithShelf(window).ToString());
 
   UpdateDisplay("600x500");
-  EXPECT_EQ("0,0 600x500",
-            ScreenUtil::GetShelfDisplayBoundsInRoot(widget->GetNativeWindow())
-                .ToString());
+  EXPECT_EQ("0,0 600x500", wm::GetDisplayBoundsWithShelf(window).ToString());
 }
 
 }  // namespace test
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 737785cb..01cad5a0 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -18,12 +18,12 @@
 #include "ash/common/wm/fullscreen_window_finder.h"
 #include "ash/common/wm/mru_window_tracker.h"
 #include "ash/common/wm/window_state.h"
+#include "ash/common/wm/wm_screen_util.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_root_window_controller_observer.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/screen_util.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_bezel_event_filter.h"
 #include "ash/shelf/shelf_layout_manager_observer.h"
@@ -248,8 +248,8 @@
 
 gfx::Rect ShelfLayoutManager::GetIdealBounds() {
   const int shelf_size = GetShelfConstant(SHELF_SIZE);
-  gfx::Rect rect(
-      ScreenUtil::GetDisplayBoundsInParent(shelf_widget_->GetNativeView()));
+  WmWindow* shelf_window = WmLookup::Get()->GetWindowForWidget(shelf_widget_);
+  gfx::Rect rect(wm::GetDisplayBoundsInParent(shelf_window));
   return SelectValueForShelfAlignment(
       gfx::Rect(rect.x(), rect.bottom() - shelf_size, rect.width(), shelf_size),
       gfx::Rect(rect.x(), rect.y(), shelf_size, rect.height()),
@@ -733,8 +733,8 @@
     GetLayer(shelf_widget_)->SetOpacity(target_bounds.opacity);
     // mash::wm::ShelfLayout manages window bounds when running in mash.
     if (!Shell::GetInstance()->in_mus()) {
-      shelf_widget_->SetBounds(ScreenUtil::ConvertRectToScreen(
-          shelf_widget_->GetNativeView()->parent(),
+      WmWindow* window = WmLookup::Get()->GetWindowForWidget(shelf_widget_);
+      shelf_widget_->SetBounds(window->GetParent()->ConvertRectToScreen(
           target_bounds.shelf_bounds_in_root));
     }
 
@@ -755,10 +755,10 @@
     status_bounds.Offset(target_bounds.shelf_bounds_in_root.OffsetFromOrigin());
     // mash::wm::ShelfLayout manages window bounds when running mash.
     if (!Shell::GetInstance()->in_mus()) {
+      WmWindow* window = WmLookup::Get()->GetWindowForWidget(
+          shelf_widget_->status_area_widget());
       shelf_widget_->status_area_widget()->SetBounds(
-          ScreenUtil::ConvertRectToScreen(
-              shelf_widget_->status_area_widget()->GetNativeView()->parent(),
-              status_bounds));
+          window->GetParent()->ConvertRectToScreen(status_bounds));
     }
     // For crbug.com/622431, when the shelf alignment is BOTTOM_LOCKED, we
     // don't set display work area, as it is not real user-set alignment.
@@ -807,8 +807,8 @@
     shelf_size = 0;
   }
 
-  gfx::Rect available_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(root_window_);
+  WmWindow* shelf_window = WmLookup::Get()->GetWindowForWidget(shelf_widget_);
+  gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(shelf_window);
   available_bounds.Inset(0, chromevox_panel_height_, 0, 0);
   int shelf_width = PrimaryAxisValue(available_bounds.width(), shelf_size);
   int shelf_height = PrimaryAxisValue(shelf_size, available_bounds.height());
@@ -892,16 +892,17 @@
 
   available_bounds.Subtract(target_bounds->shelf_bounds_in_root);
   available_bounds.Subtract(keyboard_bounds_);
-  user_work_area_bounds_ =
-      ScreenUtil::ConvertRectToScreen(root_window_, available_bounds);
+
+  WmWindow* root = shelf_window->GetRootWindow();
+  user_work_area_bounds_ = root->ConvertRectToScreen(available_bounds);
 }
 
 void ShelfLayoutManager::UpdateTargetBoundsForGesture(
     TargetBounds* target_bounds) const {
   CHECK_EQ(GESTURE_DRAG_IN_PROGRESS, gesture_drag_status_);
   bool horizontal = IsHorizontalAlignment();
-  gfx::Rect available_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(root_window_);
+  WmWindow* window = WmLookup::Get()->GetWindowForWidget(shelf_widget_);
+  gfx::Rect available_bounds = wm::GetDisplayBoundsWithShelf(window);
   int resistance_free_region = 0;
 
   if (gesture_drag_auto_hide_state_ == SHELF_AUTO_HIDE_HIDDEN &&
diff --git a/ash/system/toast/toast_manager_unittest.cc b/ash/system/toast/toast_manager_unittest.cc
index 7c79707..dd0482d 100644
--- a/ash/system/toast/toast_manager_unittest.cc
+++ b/ash/system/toast/toast_manager_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/system/toast/toast_manager.h"
+#include "ash/common/wm/wm_screen_util.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/display_manager.h"
 #include "ash/screen_util.h"
@@ -161,8 +162,7 @@
   EXPECT_EQ(1, GetToastSerial());
 
   gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
-  gfx::Rect root_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(Shell::GetPrimaryRootWindow());
+  gfx::Rect root_bounds = wm::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(shelf->GetUserWorkAreaBounds()));
   EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
@@ -191,8 +191,7 @@
   EXPECT_EQ(1, GetToastSerial());
 
   gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
-  gfx::Rect root_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(Shell::GetPrimaryRootWindow());
+  gfx::Rect root_bounds = wm::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(shelf->GetUserWorkAreaBounds()));
   EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
@@ -210,8 +209,7 @@
   EXPECT_EQ(1, GetToastSerial());
 
   gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
-  gfx::Rect root_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(Shell::GetPrimaryRootWindow());
+  gfx::Rect root_bounds = wm::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(shelf->GetUserWorkAreaBounds()));
   EXPECT_NEAR(root_bounds.CenterPoint().x(), toast_bounds.CenterPoint().x(), 1);
@@ -228,8 +226,7 @@
 
   gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
   gfx::RectF precise_toast_bounds(toast_bounds);
-  gfx::Rect root_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(Shell::GetPrimaryRootWindow());
+  gfx::Rect root_bounds = wm::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(shelf->GetUserWorkAreaBounds()));
   EXPECT_EQ(root_bounds.bottom() - 5, toast_bounds.bottom());
@@ -261,8 +258,7 @@
   EXPECT_EQ(1, GetToastSerial());
 
   gfx::Rect toast_bounds = GetCurrentWidget()->GetWindowBoundsInScreen();
-  gfx::Rect root_bounds =
-      ScreenUtil::GetShelfDisplayBoundsInRoot(Shell::GetPrimaryRootWindow());
+  gfx::Rect root_bounds = wm::GetDisplayBoundsWithShelf(shelf->GetWindow());
 
   EXPECT_TRUE(toast_bounds.Intersects(shelf->GetUserWorkAreaBounds()));
   EXPECT_TRUE(root_bounds.Contains(toast_bounds));
diff --git a/ash/wm/lock_window_state.cc b/ash/wm/lock_window_state.cc
index 4e1254f..59a6490 100644
--- a/ash/wm/lock_window_state.cc
+++ b/ash/wm/lock_window_state.cc
@@ -12,8 +12,9 @@
 #include "ash/common/wm/window_state_delegate.h"
 #include "ash/common/wm/window_state_util.h"
 #include "ash/common/wm/wm_event.h"
+#include "ash/common/wm/wm_screen_util.h"
+#include "ash/common/wm_shell.h"
 #include "ash/display/display_manager.h"
-#include "ash/screen_util.h"
 #include "ash/shell.h"
 #include "ash/wm/lock_layout_manager.h"
 #include "ash/wm/window_animations.h"
@@ -168,14 +169,9 @@
 }
 
 gfx::Rect GetBoundsForLockWindow(aura::Window* window) {
-  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
-  if (display_manager->IsInUnifiedMode()) {
-    const display::Display& first =
-        display_manager->software_mirroring_display_list()[0];
-    return first.bounds();
-  } else {
-    return ScreenUtil::GetDisplayBoundsInParent(window);
-  }
+  if (WmShell::Get()->IsInUnifiedMode())
+    return WmShell::Get()->GetFirstDisplay().bounds();
+  return wm::GetDisplayBoundsInParent(WmWindowAura::Get(window));
 }
 
 void LockWindowState::UpdateBounds(wm::WindowState* window_state) {
@@ -190,9 +186,7 @@
       keyboard_controller->keyboard_visible()) {
     keyboard_bounds = keyboard_controller->current_keyboard_bounds();
   }
-  gfx::Rect bounds = ScreenUtil::GetShelfDisplayBoundsInRoot(
-      ash::WmWindowAura::GetAuraWindow(window_state->window()));
-
+  gfx::Rect bounds = wm::GetDisplayBoundsWithShelf(window_state->window());
   bounds.set_height(bounds.height() - keyboard_bounds.height());
 
   VLOG(1) << "Updating window bounds to: " << bounds.ToString();
diff --git a/breakpad/BUILD.gn b/breakpad/BUILD.gn
index b15764c6..c7730e7 100644
--- a/breakpad/BUILD.gn
+++ b/breakpad/BUILD.gn
@@ -332,6 +332,15 @@
   }
 }
 
+if (is_ios) {
+  binary_symlink("dump_syms") {
+    binary_label = ":$target_name($host_toolchain)"
+  }
+  binary_symlink("symupload") {
+    binary_label = ":$target_name($host_toolchain)"
+  }
+}
+
 if (is_mac) {
   static_library("utilities") {
     sources = [
diff --git a/chrome/VERSION b/chrome/VERSION
index 3a948ae..1c44b7cf 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=54
 MINOR=0
-BUILD=2821
+BUILD=2822
 PATCH=0
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 0cbfdfe9..4ee80e02 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1632,7 +1632,19 @@
   <message name="IDS_NETWORK_ENABLE_DEV_FEATURES_LINK" desc="Text shown on continue button" meaning="Link shown on OOBE screens that opens enable debugging features dialog">
     Enable debugging features
   </message>
-  <message name="IDS_NETWORK_SECTION_TITE" desc="Tile of newtork selection screen" meaning="A title of the dialog where user should select network to connect to Internet">
+  <message name="IDS_LANGUAGE_DROPDOWN_TITLE" desc="Title of language selection dropdown menu" meaning="Small title near language dropdown menu suggesting that this is a language selector.">
+    Language
+  </message>
+  <message name="IDS_KEYBOARD_DROPDOWN_TITLE" desc="Title of keyboard selection dropdown menu" meaning="Small title near keyboard dropdown menu suggesting that this is a keyboard layout selector.">
+    Keyboard
+  </message>
+  <message name="IDS_OOBE_OK_BUTTON_TEXT" desc="Text on 'OK' button" meaning="This is 'OK' text for all 'OK' buttons on ChromeOS initial device setup screens.">
+    OK
+  </message>
+  <message name="IDS_LANGUAGE_SECTION_TITLE" desc="Title of language selection screen" meaning="A title of the dialog where user should select ChromeOS UI language and default keyboard layout during initial device setup.">
+    Choose your language &amp; keyboard
+  </message>
+  <message name="IDS_NETWORK_SECTION_TITLE" desc="Title of network selection screen" meaning="A title of the dialog where user should select network to connect to Internet">
     Connect to network
   </message>
   <message name="IDS_NETWORK_SECTION_HINT" desc="Under-title line on the network selection screen" meaning="A hint to the user why device should be connected to the network">
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
index 69db270..680f38a 100644
--- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
+++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.html
@@ -17,6 +17,7 @@
 <include src="oobe_buttons.html">
 <include src="oobe_card.html">
 <include src="oobe_dialog.html">
+<include src="oobe_i18n_dropdown.html">
 <include src="oobe_welcome.html">
 
 <script src="chrome://oobe/custom_elements.js"></script>
diff --git a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
index 347df431..5ba20e49 100644
--- a/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
+++ b/chrome/browser/resources/chromeos/login/custom_elements_oobe.js
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This inclusion should go first, as <{controller,host}-paring-screen> depend
-// of it.
+// This inclusion is types-only. No actual code to execute.
+<include src="oobe_types.js">
+
+// This inclusion should go before other non-trivial includes, as
+// <{controller,host}-paring-screen> depend of it.
 <include src="oobe-screen.js">
 
 <include src="controller-pairing-screen.js">
@@ -24,4 +27,5 @@
 <include src="oobe_buttons.js">
 <include src="oobe_card.js">
 <include src="oobe_dialog.js">
+<include src="oobe_i18n_dropdown.js">
 <include src="oobe_welcome.js">
diff --git a/chrome/browser/resources/chromeos/login/oobe.js b/chrome/browser/resources/chromeos/login/oobe.js
index 729a695..3a9a4bc 100644
--- a/chrome/browser/resources/chromeos/login/oobe.js
+++ b/chrome/browser/resources/chromeos/login/oobe.js
@@ -305,12 +305,17 @@
       Oobe.setupSelect($('timezone-select'), data.timezoneList);
 
       // ---------- Welcome screen
-      $('oobe-welcome-md').currentLanguage =
-          Oobe.getSelectedTitle(data.languageList);
-
       if (data.newOobeUI == 'on') {
+        var welcomeScreen = $('oobe-welcome-md');
+        welcomeScreen.currentLanguage =
+            Oobe.getSelectedTitle(data.languageList);
+        welcomeScreen.languages = data.languageList;
+
+        welcomeScreen.keyboards = data.inputMethodsList;
+
         $('oobe-connect').hidden = true;
-        $('oobe-welcome-md').hidden = false;
+        welcomeScreen.hidden = false;
+        welcomeScreen.enabled = true;
       } else {
         $('oobe-connect').hidden = false;
         $('oobe-welcome-md').hidden = true;
diff --git a/chrome/browser/resources/chromeos/login/oobe_buttons.html b/chrome/browser/resources/chromeos/login/oobe_buttons.html
index e3d1cf9..657f88b1 100644
--- a/chrome/browser/resources/chromeos/login/oobe_buttons.html
+++ b/chrome/browser/resources/chromeos/login/oobe_buttons.html
@@ -47,3 +47,30 @@
   </template>
 </dom-module>
 
+<!--
+  Material design square button for text-labelled buttons.
+  By default, text is blue, background is white.
+  |inverse| makes text white on a blue background.
+
+  Example:
+    <oobe-icon-button label="OK" inverse></oobe-icon-button>
+    <oobe-icon-button label="CANCEL"></oobe-icon-button>
+
+  Attributes:
+    'label' - text on a button
+    'disabled' - button is disabled when the attribute is set.
+    'inverse' - makes text white and background blue
+-->
+<dom-module id="oobe-text-button">
+  <link rel="stylesheet" href="oobe_text_button.css">
+  <template>
+    <div on-click="onClick_" on-tap="onClick_">
+      <paper-button id="textButton" disabled="[[disabled]]"
+          inverse$="[[inverse]]">
+        [[label]]
+        <content></content>
+      </paper-button>
+    </div>
+  </template>
+</dom-module>
+
diff --git a/chrome/browser/resources/chromeos/login/oobe_buttons.js b/chrome/browser/resources/chromeos/login/oobe_buttons.js
index eff0ba82b..9b3238d 100644
--- a/chrome/browser/resources/chromeos/login/oobe_buttons.js
+++ b/chrome/browser/resources/chromeos/login/oobe_buttons.js
@@ -38,3 +38,24 @@
       e.stopPropagation();
   }
 });
+
+Polymer({
+  is: 'oobe-text-button',
+
+  properties: {
+    disabled: {type: Boolean, value: false, reflectToAttribute: true},
+
+    label: String,
+
+    inverse: Boolean,
+  },
+
+  focus: function() {
+    this.$.textButton.focus();
+  },
+
+  onClick_: function(e) {
+    if (this.disabled)
+      e.stopPropagation();
+  }
+});
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.css b/chrome/browser/resources/chromeos/login/oobe_dialog.css
index 4b4e4959..2599245 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.css
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.css
@@ -33,6 +33,12 @@
   padding: 24px 40px 34px;
 }
 
+#oobe-bottom {
+  box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.14);
+  padding: 24px 40px 34px;
+  z-index: 1;
+}
+
 ::content div.oobe-body-text {
   margin-bottom: 24px;
 }
@@ -58,17 +64,4 @@
   margin-bottom: 0;
 }
 
-.overlay {
-  background-color: rgba(0, 0, 0, 0.5);
-  display: none;
-  height: 100%;
-  position: absolute;
-  right: 0;
-  top: 0;
-  width: 100%;
-  z-index: 11;
-}
-
-:host(.full-disabled) #full-overlay,
-:host(.disabled) #bottom-overlay,
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.html b/chrome/browser/resources/chromeos/login/oobe_dialog.html
index 80b000c..cd0985a 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.html
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.html
@@ -17,6 +17,8 @@
       </div>
       <oobe-input-form class="footer" ...>
       </oobe-input-form>
+      <oobe-text-button class="footer" label="OK" ...>
+      </oobe-text-button>
     </oobe-dialog>
 
   Add class |header| to all which you want to go inside the header.  Similar
@@ -37,9 +39,12 @@
       <div class="footer-container flex vertical layout">
         <content select=".footer"></content>
       </div>
-      <div id="bottom-overlay" class="overlay"></div>
     </div>
-    <div id="full-overlay" class="overlay"></div>
+    <template is="dom-if" if="[[hasButtons]]">
+      <div id="oobe-bottom" class="layout horizontal end-justified">
+        <content select=".bottom-buttons"></content>
+      </div>
+    </template>
   </template>
 </dom-module>
 
diff --git a/chrome/browser/resources/chromeos/login/oobe_dialog.js b/chrome/browser/resources/chromeos/login/oobe_dialog.js
index 8dd5bc3..2a1e083 100644
--- a/chrome/browser/resources/chromeos/login/oobe_dialog.js
+++ b/chrome/browser/resources/chromeos/login/oobe_dialog.js
@@ -2,4 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-Polymer({is: 'oobe-dialog'});
+Polymer({
+  is: 'oobe-dialog',
+
+  properties: {
+    /**
+     * Controls visibility of the bottom-buttons element.
+     */
+    hasButtons: {
+      type: Boolean,
+      value: false,
+    },
+  },
+});
diff --git a/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.html b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.html
new file mode 100644
index 0000000..55dd811
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.html
@@ -0,0 +1,51 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+
+<iron-iconset-svg name="oobe-i18n-dropdown" size="24">
+  <svg>
+    <defs>
+      <!--
+      These icons are copied from Polymer's iron-icons and kept in sorted order.
+      See http://goo.gl/Y1OdAq for instructions on adding additional icons.
+      -->
+      <g id="check">
+        <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z">
+        </path>
+      </g>
+    </defs>
+  </svg>
+</iron-iconset-svg>
+
+<dom-module id="oobe-i18n-dropdown">
+  <template>
+    <style>
+      .selected-icon {
+        color: var(--google-blue-500);
+      } 
+    </style>
+    <paper-dropdown-menu no-label-float>
+      <paper-listbox id="listboxDropdown" class="dropdown-content"
+          on-iron-select="onSelect_"
+          on-iron-deselect="onDeselect_">
+        <template is="dom-repeat" id="domRepeat" items="[[items]]">
+          <paper-item item="[[item]]" disabled="[[item.optionGroupName]]">
+            <div class="flex horizontal layout justified">
+              <div hidden="[[item.optionGroupName]]">
+                [[item.title]]
+              </div>
+              <iron-icon icon="oobe-i18n-dropdown:check" class="selected-icon"
+                  hidden="[[!item.selected]]">
+              </iron-icon>
+            </div>
+            <hr hidden="[[!item.optionGroupName]]">
+          </paper-item>
+        </template>
+      </paper-listbox>
+    </paper-dropdown-menu>
+  </template>
+</dom-module>
diff --git a/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.js b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.js
new file mode 100644
index 0000000..0d3d1c7ab
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/oobe_i18n_dropdown.js
@@ -0,0 +1,97 @@
+// 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.
+
+/**
+ * Polymer class definition for 'oobe-i18n-dropdown'.
+ */
+(function() {
+
+
+/**
+ * Languages/keyboard descriptor to display
+ * @type {!OobeTypes.LanguageDsc|!OobeTypes.IMEDsc}
+ */
+var I18nMenuItem;
+
+Polymer({
+  is: 'oobe-i18n-dropdown',
+
+  properties: {
+    /**
+     * List of languages/keyboards to display
+     * @type {!Array<I18nMenuItem>}
+     */
+    items: {
+      type: Array,
+      observer: 'onItemsChanged_',
+    },
+
+    /**
+     * Accessibility label.
+     * @type {!string}
+     */
+    label: {
+      type: String,
+    },
+  },
+
+  /**
+   * This flag prevents recursive calls of observers and callbacks.
+   */
+  observersDisabled_: false,
+
+  /**
+   * @param {!{detail: !{item: { item: {!I18nMenuItem}}}}} event
+   * @private
+   */
+  onSelect_: function(event) {
+    if (this.observersDisabled_)
+      return;
+
+    var selectedModel = this.$.domRepeat.modelForElement(event.detail.item);
+    if (!selectedModel.item)
+      return;
+
+    selectedModel.set('item.selected', true);
+    this.fire('select-item', selectedModel.item);
+  },
+
+  onDeselect_: function(event) {
+    if (this.observersDisabled_)
+      return;
+
+    var deSelectedModel = this.$.domRepeat.modelForElement(event.detail.item);
+    if (!deSelectedModel.item)
+      return;
+
+    deSelectedModel.set('item.selected', false);
+  },
+
+  onItemsChanged_: function(items) {
+    if (this.observersDisabled_)
+      return;
+
+    if (!items)
+      return;
+
+    this.observersDisabled_ = true;
+
+    var index = items.findIndex(function(item) { return item.selected; });
+    if (index != -1) {
+      // This is needed for selectIndex() to pick up values from updated
+      // this.items (for example, translated into other language).
+      Polymer.dom.flush();
+
+      if (this.$.listboxDropdown.selected == index) {
+        // This is to force update real <input> element value even if selection
+        // index has not changed.
+        this.$.listboxDropdown.selectIndex(null);
+      }
+      this.$.listboxDropdown.selectIndex(index);
+    }
+
+    this.observersDisabled_ = false;
+  },
+});
+})();
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_network.html b/chrome/browser/resources/chromeos/login/oobe_screen_network.html
index 982daee..a43a7000 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_network.html
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_network.html
@@ -5,7 +5,8 @@
 <div class="step hidden animated" id="connect" role="group" hidden>
   <div id="oobe-poly-connect">
     <div class="step-contents">
-      <oobe-welcome-md id="oobe-welcome-md" class="fit"></oobe-welcome-md>
+      <oobe-welcome-md id="oobe-welcome-md" class="fit" hidden>
+      </oobe-welcome-md>
     </div>
   </div>
   <div id="oobe-connect">
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_network.js b/chrome/browser/resources/chromeos/login/oobe_screen_network.js
index bba9c388..3977d51 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_network.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_network.js
@@ -27,27 +27,27 @@
 
     /** @override */
     decorate: function() {
-      var self = this;
-
       Oobe.setupSelect($('language-select'),
                        loadTimeData.getValue('languageList'),
-                       function(languageId) {
-                         self.context.set(CONTEXT_KEY_LOCALE, languageId);
-                         self.commitContextChanges();
-                       });
+                       this.onLanguageSelected_.bind(this));
       Oobe.setupSelect($('keyboard-select'),
                        loadTimeData.getValue('inputMethodsList'),
-                       function(inputMethodId) {
-                         self.context.set(CONTEXT_KEY_INPUT_METHOD,
-                                          inputMethodId);
-                         self.commitContextChanges();
-                       });
+                       this.onKeyboardSelected_.bind(this));
       Oobe.setupSelect($('timezone-select'),
                        loadTimeData.getValue('timezoneList'),
-                       function(timezoneId) {
-                         self.context.set(CONTEXT_KEY_TIMEZONE, timezoneId);
-                         self.commitContextChanges();
-                       });
+                       this.onTimezoneSelected_.bind(this));
+
+      // ---------- Welcome screen
+      var welcomeScreen = $('oobe-welcome-md');
+      welcomeScreen.screen = this;
+
+      var languageList = loadTimeData.getValue('languageList');
+      welcomeScreen.languages = languageList;
+      welcomeScreen.currentLanguage = Oobe.getSelectedTitle(languageList);
+
+      var inputMethodsList = loadTimeData.getValue('inputMethodsList');
+      welcomeScreen.keyboards = inputMethodsList;
+      // -------------------------
 
       this.dropdown_ = $('networks-list');
       cr.ui.DropDown.decorate(this.dropdown_);
@@ -81,6 +81,21 @@
       });
     },
 
+    onLanguageSelected_: function(languageId) {
+      this.context.set(CONTEXT_KEY_LOCALE, languageId);
+      this.commitContextChanges();
+    },
+
+    onKeyboardSelected_: function(inputMethodId) {
+      this.context.set(CONTEXT_KEY_INPUT_METHOD, inputMethodId);
+      this.commitContextChanges();
+    },
+
+    onTimezoneSelected_: function(timezoneId) {
+      this.context.set(CONTEXT_KEY_TIMEZONE, timezoneId);
+      this.commitContextChanges();
+    },
+
     onBeforeShow: function(data) {
       cr.ui.DropDown.show('networks-list', true, -1);
       this.classList.toggle('connect-debugging-view',
diff --git a/chrome/browser/resources/chromeos/login/oobe_text_button.css b/chrome/browser/resources/chromeos/login/oobe_text_button.css
new file mode 100644
index 0000000..42b10d15
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/oobe_text_button.css
@@ -0,0 +1,18 @@
+/* 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. */
+
+#textButton {
+  font-size: 18px;
+  height: 24px;
+}
+
+#textButton:not([inverse]) {
+  background-color: white
+  color: var(--google-blue-500);
+}
+
+#textButton[inverse] {
+  background-color: var(--google-blue-500);
+  color: white;
+}
diff --git a/chrome/browser/resources/chromeos/login/oobe_types.js b/chrome/browser/resources/chromeos/login/oobe_types.js
new file mode 100644
index 0000000..826941b
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/oobe_types.js
@@ -0,0 +1,33 @@
+// 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
+ *
+ * This file contains typedefs for chromeOS OOBE properties.
+ */
+
+var OobeTypes = {};
+
+/**
+ * ChromeOS OOBE language descriptor.
+ * @typedef {{
+ *   code: (String|undefined),
+ *   displayName: (String|undefined),
+ *   textDirection: (String|undefined),
+ *   nativeDisplayName: (String|undefined),
+ * }}
+ */
+OobeTypes.LanguageDsc;
+
+/**
+ * ChromeOS OOBE input method descriptor.
+ * @typedef {{
+ *   value: (String|undefined),
+ *   title: (String|undefined),
+ *   selected: (Boolean|undefined),
+ * }}
+ */
+OobeTypes.IMEDsc;
+
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.css b/chrome/browser/resources/chromeos/login/oobe_welcome.css
index 2dcf4b1d..4e63b014 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.css
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.css
@@ -24,3 +24,11 @@
     --iron-icon-height: 32px;
     --iron-icon-width: 32px;
 }
+
+.language-selection-entry {
+  border-top: 1px solid lightgrey;
+}
+
+.language-selection-entry:last-of-type {
+  border-bottom: 1px solid lightgrey;
+}
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.html b/chrome/browser/resources/chromeos/login/oobe_welcome.html
index d4a2e85..a9c55a55 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.html
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.html
@@ -21,33 +21,76 @@
 <dom-module name="oobe-welcome-md">
   <link rel="stylesheet" href="oobe_welcome.css">
   <template>
-    <oobe-card id="welcomeSection" class="fit" hidden="[[networkSelectionScreenShown]]">
+    <oobe-card id="welcomeSection" class="fit" hidden="[[!welcomeScreenShown]]">
       <div class="header flex vertical layout end-justified start">
         <h1 class="welcome-message" i18n-content="networkScreenGreeting"></h1>
       </div>
       <div class="footer flex vertical layout justified">
         <div class="welcome-next flex vertical layout center">
-          <oobe-next-button id="welcomeNextButton" on-tap="onWelcomeNextButtonClicked_"></oobe-next-button>
+          <oobe-next-button id="welcomeNextButton"
+              on-tap="onWelcomeNextButtonClicked_">
+          </oobe-next-button>
         </div>
         <div class="flex horizontal layout justified">
-          <div class="buttonbox layout vertical">
-            <iron-icon icon="icons:language" class="bottom-button self-center"></iron-icon>
+          <div class="buttonbox layout vertical"
+              on-tap="onWelcomeSelectLanguageButtonClicked_">
+            <iron-icon icon="icons:language" class="bottom-button self-center">
+            </iron-icon>
             <div id="currentLanguage">[[currentLanguage]]</div>
           </div>
           <div class="buttonbox layout vertical">
-            <iron-icon icon="icons:accessibility" class="bottom-button self-center"></iron-icon>
+            <iron-icon icon="icons:accessibility"
+                class="bottom-button self-center">
+            </iron-icon>
             <div id="accessibilityLabel" i18n-content="accessibilityLink"></div>
           </div>
         </div>
       </div>
     </oobe-card>
-    <oobe-dialog id="networkSection" class="fit" hidden="[[!networkSelectionScreenShown]]">
+    <oobe-dialog class="fit" hidden="[[!languageSelectionScreenShown]]"
+        has-buttons>
+      <iron-icon icon="icons:language" class="oobe-icon"></iron-icon>
+      <div class="header flex layout vertical end-justified start">
+        <h1 class="welcome-message" i18n-content="languageSectionTitle"></h1>
+      </div>
+      <div class="footer layout vertical">
+        <template is="dom-if" if="[[enabled]]">
+          <div id="languageDropdownContainer"
+              class="flex layout horizontal justified language-selection-entry">
+            <div class="layout vertical center-justified"
+                i18n-content="languageDropdownTitle">
+            </div>
+            <oobe-i18n-dropdown id="languageSelect" items="[[languages]]"
+                on-select-item="onLanguageSelected_"
+                label="$i18n{languageDropdownTitle}">
+            </oobe-i18n-dropdown>
+          </div>
+          <div id="keyboardDropdownContainer"
+              class="flex layout horizontal justified language-selection-entry">
+            <div class="layout vertical center-justified"
+                i18n-content="keyboardDropdownTitle">
+            </div>
+            <oobe-i18n-dropdown id="keyboardSelect" items="[[keyboards]]"
+                on-select-item="onKeyboardSelected_"
+                label="$i18n{keyboardDropdownTitle}">
+            </oobe-i18n-dropdown>
+          </div>
+        </template>
+      </div>
+      <div class="bottom-buttons layout horizontal">
+        <oobe-text-button inverse on-tap="closeLanguageSection_"
+          i18n-content="oobeOKButtonText">
+        </oobe-text-button>
+      </div>
+    </oobe-dialog>
+    <oobe-dialog id="networkSection" class="fit"
+        hidden="[[!networkSelectionScreenShown]]">
       <iron-icon icon="oobe-welcome:wifi" class="oobe-icon"></iron-icon>
-      <div class="header flex vertical layout end-justified start">
+      <div class="header flex layout vertical end-justified start">
         <h1 class="welcome-message" i18n-content="networkSectionTitle"></h1>
         <h1 class="welcome-message-hint" i18n-content="networkSectionHint"></h1>
       </div>
-      <div class="footer flex vertical layout justified">
+      <div class="footer flex layout vertical justified">
         <cr-network-select id="networkSelect"
             on-network-connected="onNetworkConnected_"
             on-network-item-selected="onNetworkListNetworkItemSelected_"
diff --git a/chrome/browser/resources/chromeos/login/oobe_welcome.js b/chrome/browser/resources/chromeos/login/oobe_welcome.js
index 5b48931..52cb4f9 100644
--- a/chrome/browser/resources/chromeos/login/oobe_welcome.js
+++ b/chrome/browser/resources/chromeos/login/oobe_welcome.js
@@ -11,20 +11,69 @@
 
   properties: {
     /**
-     * Currently selected system language.
+     * Currently selected system language (display name).
      */
     currentLanguage: {
       type: String,
-      value: 'English (US)',
+      value: '',
     },
 
     /**
-     * Flag that switches Welcome screen to Network Selection screen.
+     * List of languages for language selector dropdown.
+     * @type {!Array<OobeTypes.LanguageDsc>}
+     */
+    languages: {
+      type: Array,
+    },
+
+    /**
+     * List of keyboards for keyboard selector dropdown.
+     * @type {!Array<OobeTypes.IMEDsc>}
+     */
+    keyboards: {
+      type: Array,
+    },
+
+    /**
+     * Flag that shows Welcome screen.
+     */
+    welcomeScreenShown: {
+      type: Boolean,
+      value: true,
+    },
+
+    /**
+     * Flag that shows Language Selection screen.
+     */
+    languageSelectionScreenShown: {
+      type: Boolean,
+      value: false,
+    },
+
+    /**
+     * Flag that shows Network Selection screen.
      */
     networkSelectionScreenShown: {
       type: Boolean,
       value: false,
     },
+
+    /**
+     * Flag that enables MD-OOBE.
+     */
+    enabled: {
+      type: Boolean,
+      value: false,
+    },
+  },
+
+  /**
+   * Hides all screens to help switching from one screen to another.
+   */
+  hideAllScreens_: function() {
+    this.welcomeScreenShown = false;
+    this.networkSelectionScreenShown = false;
+    this.languageSelectionScreenShown = false;
   },
 
   /**
@@ -85,10 +134,21 @@
    * @private
    */
   onWelcomeNextButtonClicked_: function() {
+    this.hideAllScreens_();
     this.networkSelectionScreenShown = true;
   },
 
   /**
+   * Handle "Language" button for "Welcome" screen.
+   *
+   * @private
+   */
+  onWelcomeSelectLanguageButtonClicked_: function() {
+    this.hideAllScreens_();
+    this.languageSelectionScreenShown = true;
+  },
+
+  /**
    * Handle Networwork Setup screen "Proxy settings" button.
    *
    * @private
@@ -180,9 +240,44 @@
 
   /**
    * @param {!Event} event
+   * @private
    */
   onNetworkListCustomItemSelected_: function(e) {
     var itemState = e.detail;
     itemState.customData.onTap();
   },
+
+  /**
+   * Handle language selection.
+   *
+   * @param {!{detail: {!OobeTypes.LanguageDsc}}} event
+   * @private
+   */
+  onLanguageSelected_: function(event) {
+    var item = event.detail;
+    var languageId = item.value;
+    this.screen.onLanguageSelected_(languageId);
+  },
+
+  /**
+   * Handle keyboard layout selection.
+   *
+   * @param {!{detail: {!OobeTypes.IMEDsc}}} event
+   * @private
+   */
+  onKeyboardSelected_: function(event) {
+    var item = event.detail;
+    var inputMethodId = item.value;
+    this.screen.onKeyboardSelected_(inputMethodId);
+  },
+
+  /**
+   * Handle "OK" button for "LanguageSelection" screen.
+   *
+   * @private
+   */
+  closeLanguageSection_: function() {
+    this.hideAllScreens_();
+    this.welcomeScreenShown = true;
+  },
 });
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
index 483fc906..6e31d3c 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.cc
@@ -164,8 +164,13 @@
   builder->Add("debuggingFeaturesLink", IDS_NETWORK_ENABLE_DEV_FEATURES_LINK);
 
   // MD-OOBE
-  builder->Add("networkSectionTitle", IDS_NETWORK_SECTION_TITE);
+  builder->Add("oobeOKButtonText", IDS_OOBE_OK_BUTTON_TEXT);
+  builder->Add("languageSectionTitle", IDS_LANGUAGE_SECTION_TITLE);
+  builder->Add("networkSectionTitle", IDS_NETWORK_SECTION_TITLE);
   builder->Add("networkSectionHint", IDS_NETWORK_SECTION_HINT);
+
+  builder->Add("languageDropdownTitle", IDS_LANGUAGE_DROPDOWN_TITLE);
+  builder->Add("keyboardDropdownTitle", IDS_KEYBOARD_DROPDOWN_TITLE);
   builder->Add("proxySettingsMenuName", IDS_PROXY_SETTINGS_MENU_NAME);
   builder->Add("addWiFiNetworkMenuName", IDS_ADD_WI_FI_NETWORK_MENU_NAME);
   builder->Add("addMobileNetworkMenuName", IDS_ADD_MOBILE_NETWORK_MENU_NAME);
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index 19906d78..426b90ba 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -24,10 +24,24 @@
 
 // Records the final request status UMA for an offlining request. This should
 // only be called once per Offliner::LoadAndSave request.
-void RecordOfflinerResultUMA(Offliner::RequestStatus request_status) {
-  UMA_HISTOGRAM_ENUMERATION("OfflinePages.Background.OfflinerRequestStatus",
-                            request_status,
-                            Offliner::RequestStatus::STATUS_COUNT);
+void RecordOfflinerResultUMA(const ClientId& client_id,
+                             Offliner::RequestStatus request_status) {
+  // TODO(dougarnett): Consider exposing AddHistogramSuffix from
+  // offline_page_model_impl.cc as visible utility method.
+  std::string histogram_name("OfflinePages.Background.OfflinerRequestStatus");
+  if (!client_id.name_space.empty()) {
+    histogram_name += "." + client_id.name_space;
+  }
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_ENUMERATION
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+      histogram_name, 1,
+      static_cast<int>(Offliner::RequestStatus::STATUS_COUNT),
+      static_cast<int>(Offliner::RequestStatus::STATUS_COUNT) + 1,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->Add(static_cast<int>(request_status));
 }
 
 }  // namespace
@@ -43,6 +57,7 @@
       factory_(std::move(factory)),
       queue_(std::move(queue)),
       scheduler_(std::move(scheduler)),
+      active_request_(nullptr),
       last_offlining_status_(Offliner::RequestStatus::UNKNOWN),
       offliner_timeout_(base::TimeDelta::FromSeconds(
           policy_->GetSinglePageTimeLimitInSeconds())),
@@ -151,7 +166,12 @@
   // Stopping offliner means it will not call callback.
   last_offlining_status_ =
       Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED;
-  RecordOfflinerResultUMA(last_offlining_status_);
+
+  if (active_request_) {
+    RecordOfflinerResultUMA(active_request_->client_id(),
+                            last_offlining_status_);
+    active_request_.reset();
+  }
 
   // Let the scheduler know we are done processing.
   scheduler_callback_.Run(true);
@@ -229,6 +249,7 @@
 
   DCHECK(!is_busy_);
   is_busy_ = true;
+  active_request_.reset(new SavePageRequest(request));
 
   // Prepare an updated request to attempt.
   SavePageRequest updated_request(request);
@@ -264,10 +285,11 @@
   event_logger_.RecordSavePageRequestUpdated(request.client_id().name_space,
                                              status, request.request_id());
   last_offlining_status_ = status;
-  RecordOfflinerResultUMA(last_offlining_status_);
+  RecordOfflinerResultUMA(request.client_id(), last_offlining_status_);
   watchdog_timer_.Stop();
 
   is_busy_ = false;
+  active_request_.reset(nullptr);
 
   if (status == Offliner::RequestStatus::FOREGROUND_CANCELED) {
     // Update the request for the canceled attempt.
diff --git a/components/offline_pages/background/request_coordinator.h b/components/offline_pages/background/request_coordinator.h
index 1e51f18..5c6c03b 100644
--- a/components/offline_pages/background/request_coordinator.h
+++ b/components/offline_pages/background/request_coordinator.h
@@ -176,6 +176,8 @@
   std::unique_ptr<RequestQueue> queue_;
   // Scheduler. Used to request a callback when network is available.  Owned.
   std::unique_ptr<Scheduler> scheduler_;
+  // Holds copy of the active request, if any.
+  std::unique_ptr<SavePageRequest> active_request_;
   // Status of the most recent offlining.
   Offliner::RequestStatus last_offlining_status_;
   // Class to choose which request to schedule next
diff --git a/content/renderer/media/aec_dump_message_filter.cc b/content/renderer/media/aec_dump_message_filter.cc
index 1d6ac4b..76f104c 100644
--- a/content/renderer/media/aec_dump_message_filter.cc
+++ b/content/renderer/media/aec_dump_message_filter.cc
@@ -9,7 +9,7 @@
 #include "content/renderer/media/webrtc_logging.h"
 #include "ipc/ipc_logging.h"
 #include "ipc/ipc_sender.h"
-#
+
 namespace {
 const int kInvalidDelegateId = -1;
 }
diff --git a/media/gpu/vaapi_tfp_picture.cc b/media/gpu/vaapi_tfp_picture.cc
index ea484211..b099c5e 100644
--- a/media/gpu/vaapi_tfp_picture.cc
+++ b/media/gpu/vaapi_tfp_picture.cc
@@ -1,7 +1,7 @@
 // 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 "media/gpu/vaapi_tfp_picture.h"
 
 #include <X11/Xlib.h>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
index 233a878..bc9ecc7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -43,21 +43,21 @@
     Promise.prototype.then = function()
     {
         var result = origThen.apply(this, arguments);
-        origThen.call(result, undefined, onUncaughtPromiseReject);
+        origThen.call(result, undefined, onUncaughtPromiseReject.bind(null, new Error().stack));
         return result;
     }
 
     Promise.prototype.catch = function()
     {
         var result = origCatch.apply(this, arguments);
-        origThen.call(result, undefined, onUncaughtPromiseReject);
+        origThen.call(result, undefined, onUncaughtPromiseReject.bind(null, new Error().stack));
         return result;
     }
 
-    function onUncaughtPromiseReject(e)
+    function onUncaughtPromiseReject(stack, e)
     {
         var message = (typeof e === "object" && e.stack) || e;
-        InspectorTest.addResult("FAIL: Uncaught exception in promise: " + message);
+        InspectorTest.addResult("FAIL: Uncaught exception in promise: " + message + " " + stack);
         InspectorTest.completeDebuggerTest();
     }
 })();
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
index ab1fb06d..e88ae63 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements-test.js
@@ -437,13 +437,13 @@
 InspectorTest.eventListenersWidget = function()
 {
     var sidebarPane = WebInspector.panels.elements.sidebarPanes.eventListeners;
-    sidebarPane.revealWidget();
+    sidebarPane.revealView();
     return sidebarPane;
 }
 
 InspectorTest.expandAndDumpSelectedElementEventListeners = function(callback)
 {
-    InspectorTest.expandAndDumpEventListeners(InspectorTest.eventListenersWidget()._eventListenersView, null, callback);
+    InspectorTest.expandAndDumpEventListeners(InspectorTest.eventListenersWidget()._eventListenersView, callback);
 }
 
 InspectorTest.dumpObjectPropertySectionDeep = function(section)
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
index e651ae9..a1d8b7c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker-expected.txt
@@ -10,7 +10,7 @@
 
 ======== load ========
 == normal
-[expanded] WindowRemoveevent-listeners-framework-with-service-worker.html:62
+[expanded] WindowRemoveevent-listeners-framework-with-service-worker.html:59
     useCapture: false
     passive: false
     handler: function onload(event) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker.html
index c2863505..dfd8bf9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/event-listeners-framework-with-service-worker.html
@@ -22,12 +22,6 @@
         return InspectorTest.isDedicatedWorker(target);
     }
 
-    function forceUpdate()
-    {
-        objectEventListenersPane.revealWidget();
-        objectEventListenersPane.update();
-    }
-
     function step1(target)
     {
         InspectorTest.waitForExecutionContextInTarget(target, step2);
@@ -39,7 +33,10 @@
         InspectorTest.selectThread(executionContext.target());
         InspectorTest.addResult("Context is dedicated worker: " + isDedicatedWorker());
         InspectorTest.addResult("Dumping listeners");
-        InspectorTest.expandAndDumpEventListeners(objectEventListenersPane._eventListenersView, forceUpdate, step3);
+        objectEventListenersPane.revealView().then(() => {
+            objectEventListenersPane.update();
+            InspectorTest.expandAndDumpEventListeners(objectEventListenersPane._eventListenersView, step3);
+        });
     }
 
     function step3()
@@ -48,7 +45,7 @@
         InspectorTest.selectThread(WebInspector.targetManager.mainTarget());
         InspectorTest.addResult("Context is dedicated worker: " + isDedicatedWorker());
         InspectorTest.addResult("Dumping listeners");
-        InspectorTest.expandAndDumpEventListeners(objectEventListenersPane._eventListenersView, forceUpdate, step4);
+        InspectorTest.expandAndDumpEventListeners(objectEventListenersPane._eventListenersView, step4);
     }
 
     function step4()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index edde124..c734b2d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -369,13 +369,10 @@
     }
 }
 
-InspectorTest.expandAndDumpEventListeners = function(eventListenersView, updateCallback, callback)
+InspectorTest.expandAndDumpEventListeners = function(eventListenersView, callback)
 {
     InspectorTest.addSniffer(WebInspector.EventListenersView.prototype, "_eventListenersArrivedForTest", listenersArrived);
 
-    if (updateCallback)
-        updateCallback();
-
     function listenersArrived()
     {
         var listenerTypes = eventListenersView._treeOutline.rootElement().children();
diff --git a/third_party/WebKit/LayoutTests/inspector/animation/animation-empty-web-animations.html b/third_party/WebKit/LayoutTests/inspector/animation/animation-empty-web-animations.html
index 162c6a5..1f092fe 100644
--- a/third_party/WebKit/LayoutTests/inspector/animation/animation-empty-web-animations.html
+++ b/third_party/WebKit/LayoutTests/inspector/animation/animation-empty-web-animations.html
@@ -15,19 +15,10 @@
 
 function test()
 {
-    InspectorTest.addSniffer(WebInspector.TabbedPane.prototype, "changeTabView", onChangeTabView, true);
     WebInspector.viewManager.showView("animations");
-    var timeline;
-
-    function onChangeTabView(id, view)
-    {
-        if (!timeline && id === "animations") {
-            timeline = view;
-            InspectorTest.assertTrue(timeline instanceof WebInspector.AnimationTimeline);
-            InspectorTest.evaluateInPage("startAnimation()");
-            InspectorTest.addSniffer(WebInspector.AnimationModel.prototype, "animationStarted", animationStarted);
-        }
-    }
+    var timeline = self.runtime.sharedInstance(WebInspector.AnimationTimeline);
+    InspectorTest.evaluateInPage("startAnimation()");
+    InspectorTest.addSniffer(WebInspector.AnimationModel.prototype, "animationStarted", animationStarted);
 
     function animationStarted()
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/animation/animation-timeline.html b/third_party/WebKit/LayoutTests/inspector/animation/animation-timeline.html
index bca1d2e2..40b3f6ca 100644
--- a/third_party/WebKit/LayoutTests/inspector/animation/animation-timeline.html
+++ b/third_party/WebKit/LayoutTests/inspector/animation/animation-timeline.html
@@ -60,19 +60,11 @@
     // Override animation color for testing
     // FIXME: Set animation name of Web Animation instead; not supported yet
     WebInspector.AnimationUI.Color = function() { return "black"; }
-    var timeline;
-    InspectorTest.addSniffer(WebInspector.TabbedPane.prototype, "changeTabView", onChangeTabView, true);
-    WebInspector.viewManager.showView("animations");
 
-    function onChangeTabView(id, view)
-    {
-        if (!timeline && id === "animations") {
-            timeline = view;
-            InspectorTest.assertTrue(timeline instanceof WebInspector.AnimationTimeline);
-            InspectorTest.waitForAnimationAdded(step2);
-            InspectorTest.evaluateInPage("startAnimationWithDelay()");
-        }
-    }
+    WebInspector.viewManager.showView("animations");
+    var timeline = self.runtime.sharedInstance(WebInspector.AnimationTimeline);
+    InspectorTest.evaluateInPage("startAnimationWithDelay()");
+    InspectorTest.waitForAnimationAdded(step2);
 
     function step2(group)
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/animation/animation-web-anim-negative-start-time.html b/third_party/WebKit/LayoutTests/inspector/animation/animation-web-anim-negative-start-time.html
index 2572d48..ce843a0 100644
--- a/third_party/WebKit/LayoutTests/inspector/animation/animation-web-anim-negative-start-time.html
+++ b/third_party/WebKit/LayoutTests/inspector/animation/animation-web-anim-negative-start-time.html
@@ -26,19 +26,11 @@
     // Override animation color for testing
     // FIXME: Set animation name of Web Animation instead; not supported yet
     WebInspector.AnimationUI.Color = function() { return "black"; }
-    var timeline;
-    InspectorTest.addSniffer(WebInspector.TabbedPane.prototype, "changeTabView", onChangeTabView, true);
-    WebInspector.viewManager.showView("animations");
 
-    function onChangeTabView(id, view)
-    {
-        if (!timeline && id === "animations") {
-            timeline = view;
-            InspectorTest.assertTrue(timeline instanceof WebInspector.AnimationTimeline);
-            InspectorTest.waitForAnimationAdded(step2);
-            InspectorTest.evaluateInPage("startAnimation()");
-        }
-    }
+    WebInspector.viewManager.showView("animations");
+    var timeline = self.runtime.sharedInstance(WebInspector.AnimationTimeline);
+    InspectorTest.evaluateInPage("startAnimation()");
+    InspectorTest.waitForAnimationAdded(step2);
 
     function step2(group)
     {
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/accessibility/accessibility-pane-test.js b/third_party/WebKit/LayoutTests/inspector/elements/accessibility/accessibility-pane-test.js
index f5abb99b..06e2e06 100644
--- a/third_party/WebKit/LayoutTests/inspector/elements/accessibility/accessibility-pane-test.js
+++ b/third_party/WebKit/LayoutTests/inspector/elements/accessibility/accessibility-pane-test.js
@@ -7,7 +7,7 @@
 {
     var sidebarPane = _getAccessibilitySidebarPane();
     if (sidebarPane) {
-        sidebarPane.revealWidget();
+        sidebarPane.revealView();
         return InspectorTest.waitForAccessibilityNodeUpdate();
     } else {
         return _waitForViewsLoaded()
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-events.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-events.html
index 0eb9f40..75aaef0a 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-events.html
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-events.html
@@ -12,7 +12,7 @@
     {
         var sidebar = InspectorTest._extensionSidebar();
         InspectorTest.deprecatedRunAfterPendingDispatches(function() {
-            sidebar.revealWidget();
+            sidebar.revealView();
             callback();
         });
     }
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-sidebar.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-sidebar.html
index 0f93226..058e8c0 100644
--- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-sidebar.html
+++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-sidebar.html
@@ -19,7 +19,7 @@
     {
         var sidebar = InspectorTest._extensionSidebar(panelName);
         InspectorTest.deprecatedRunAfterPendingDispatches(function() {
-            sidebar.revealWidget();
+            sidebar.revealView();
             callback();
         });
     }
diff --git a/third_party/WebKit/LayoutTests/inspector/reveal-objects.html b/third_party/WebKit/LayoutTests/inspector/reveal-objects.html
index 52617f7..f8e4c98 100644
--- a/third_party/WebKit/LayoutTests/inspector/reveal-objects.html
+++ b/third_party/WebKit/LayoutTests/inspector/reveal-objects.html
@@ -100,7 +100,7 @@
         InspectorTest.addSniffer(WebInspector.ElementsPanel.prototype, "revealAndSelectNode", nodeRevealed, true);
         InspectorTest.addSniffer(WebInspector.SourcesPanel.prototype, "showUILocation", uiLocationRevealed, true);
         InspectorTest.addSniffer(WebInspector.ResourcesPanel.prototype, "showResource", resourceRevealed, true);
-        InspectorTest.addSniffer(WebInspector.NetworkPanel.prototype, "revealAndHighlightRequest", revealWidgeted, true);
+        InspectorTest.addSniffer(WebInspector.NetworkPanel.prototype, "revealAndHighlightRequest", revealed, true);
     }
 
     function nodeRevealed(node)
@@ -118,7 +118,7 @@
         InspectorTest.addResult("Resource " + resource.displayName + " revealed in the Resources panel");
     }
 
-    function revealWidgeted(request)
+    function revealed(request)
     {
         InspectorTest.addResult("Request " + new WebInspector.ParsedURL(request.url).lastPathComponent + " revealed in the Network panel");
     }
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/error-in-watch-expressions.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/error-in-watch-expressions.html
index 642f7a7e..1b48d8b0 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/error-in-watch-expressions.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/error-in-watch-expressions.html
@@ -8,7 +8,7 @@
 var test = function()
 {
     var watchExpressionsPane = WebInspector.panels.sources.sidebarPanes.watchExpressions;
-    watchExpressionsPane.revealWidget();
+    watchExpressionsPane.revealView();
     watchExpressionsPane.addExpression("#$%");
 
     InspectorTest.deprecatedRunAfterPendingDispatches(step1);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-panel-switch.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-panel-switch.html
index 7dc82c5..b286431 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-panel-switch.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-panel-switch.html
@@ -24,13 +24,13 @@
     function step1()
     {
         watchExpressionsPane = WebInspector.panels.sources.sidebarPanes.watchExpressions;
-        watchExpressionsPane.revealWidget();
-        watchExpressionsPane.addExpression("window.document");
-        watchExpressionsPane.addExpression("windowa.document");
-
-        var testName = InspectorTest.mainTarget.inspectedURL();
-        testName = testName.substring(testName.lastIndexOf('/') + 1);
-        InspectorTest.showScriptSource(testName, didShowScriptSource);
+        watchExpressionsPane.revealView().then(() => {
+            watchExpressionsPane.addExpression("window.document");
+            watchExpressionsPane.addExpression("windowa.document");
+            var testName = InspectorTest.mainTarget.inspectedURL();
+            testName = testName.substring(testName.lastIndexOf('/') + 1);
+            InspectorTest.showScriptSource(testName, didShowScriptSource);
+        });
     }
 
     function didShowScriptSource(sourceFrame)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-preserve-expansion.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-preserve-expansion.html
index d4299de..ffaf000 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-preserve-expansion.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-ui/watch-expressions-preserve-expansion.html
@@ -27,7 +27,7 @@
 var test = function()
 {
     var watchExpressionsPane = WebInspector.panels.sources.sidebarPanes.watchExpressions;
-    watchExpressionsPane.revealWidget();
+    watchExpressionsPane.revealView();
     watchExpressionsPane.addExpression("globalObject");
     watchExpressionsPane.addExpression("windowAlias");
     watchExpressionsPane.addExpression("array");
diff --git a/third_party/WebKit/LayoutTests/inspector/tabbed-pane-closeable-persistence.html b/third_party/WebKit/LayoutTests/inspector/tabbed-pane-closeable-persistence.html
index 7be8a911..29325a07 100644
--- a/third_party/WebKit/LayoutTests/inspector/tabbed-pane-closeable-persistence.html
+++ b/third_party/WebKit/LayoutTests/inspector/tabbed-pane-closeable-persistence.html
@@ -4,29 +4,40 @@
 <script type="text/javascript">
 var test = function()
 {
-    function logPersistenceSetting()
-    {
-        InspectorTest.addResult("Closeable tabs to restore: " + JSON.stringify(tabbedPaneController._closeableTabSetting.get()));
-    }
+    var tabbedLocation = WebInspector.viewManager.createTabbedLocation();
+    logPersistenceSetting();
 
-    var tabbedPaneController = WebInspector.inspectorView._drawerTabbedLocation;
-    logPersistenceSetting();
     // Show a closeable tab.
-    tabbedPaneController.showView("sensors");
+    var sensors = new WebInspector.SimpleView("sensors");
+    sensors.isCloseable = function() { return true; }
+    tabbedLocation.showView(sensors);
     logPersistenceSetting();
-    tabbedPaneController.showView("sensors");
+
+    // Repeat.
+    tabbedLocation.showView(sensors);
     logPersistenceSetting();
+
     // Show a permanent tab.
-    tabbedPaneController.showView("console");
+    var console = new WebInspector.SimpleView("console");
+    tabbedLocation.showView(console);
     logPersistenceSetting();
-    // Show temporary tab.
-    tabbedPaneController.showView("sources.history");
+
+    // Show transient tab.
+    var history = new WebInspector.SimpleView("history");
+    history.isTransient = function() { return true; }
+    tabbedLocation.showView(history);
     logPersistenceSetting();
+
     // Close closeable tab.
-    tabbedPaneController.tabbedPane().closeTab("sensors");
+    tabbedLocation.tabbedPane().closeTab("sensors");
     logPersistenceSetting();
 
     InspectorTest.completeTest();
+
+    function logPersistenceSetting()
+    {
+        InspectorTest.addResult("Closeable tabs to restore: " + JSON.stringify(tabbedLocation._closeableTabSetting.get()));
+    }
 }
 </script>
 </head>
diff --git a/third_party/WebKit/Source/core/frame/FrameViewTest.cpp b/third_party/WebKit/Source/core/frame/FrameViewTest.cpp
index f567725..5438ffa3 100644
--- a/third_party/WebKit/Source/core/frame/FrameViewTest.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameViewTest.cpp
@@ -38,7 +38,9 @@
     bool m_hasScheduledAnimation;
 };
 
-class FrameViewTestBase : public testing::Test {
+class FrameViewTestBase
+    : public testing::Test
+    , public testing::WithParamInterface<FrameSettingOverrideFunction> {
 protected:
     FrameViewTestBase()
         : m_chromeClient(new MockChromeClient)
@@ -56,6 +58,8 @@
         clients.chromeClient = m_chromeClient.get();
         m_pageHolder = DummyPageHolder::create(IntSize(800, 600), &clients);
         m_pageHolder->page().settings().setAcceleratedCompositingEnabled(true);
+        if (GetParam())
+            (*GetParam())(m_pageHolder->page().settings());
     }
 
     Document& document() { return m_pageHolder->document(); }
@@ -100,17 +104,25 @@
     RuntimeEnabledFeatures::Backup m_featuresBackup;
 };
 
+INSTANTIATE_TEST_CASE_P(All, FrameViewTest, ::testing::Values(
+    nullptr,
+    &RootLayerScrollsFrameSettingOverride));
+
+INSTANTIATE_TEST_CASE_P(All, FrameViewSlimmingPaintV2Test, ::testing::Values(
+    nullptr,
+    &RootLayerScrollsFrameSettingOverride));
+
 // These tests ensure that FrameView informs the ChromeClient of changes to the
 // paint artifact so that they can be shown to the user (e.g. via the
 // compositor).
-TEST_F(FrameViewSlimmingPaintV2Test, PaintOnce)
+TEST_P(FrameViewSlimmingPaintV2Test, PaintOnce)
 {
     EXPECT_CALL(chromeClient(), didPaint(_));
     document().body()->setInnerHTML("Hello world", ASSERT_NO_EXCEPTION);
     document().view()->updateAllLifecyclePhases();
 }
 
-TEST_F(FrameViewSlimmingPaintV2Test, PaintAndRepaint)
+TEST_P(FrameViewSlimmingPaintV2Test, PaintAndRepaint)
 {
     EXPECT_CALL(chromeClient(), didPaint(_)).Times(2);
     document().body()->setInnerHTML("Hello", ASSERT_NO_EXCEPTION);
@@ -119,7 +131,7 @@
     document().view()->updateAllLifecyclePhases();
 }
 
-TEST_F(FrameViewTest, SetPaintInvalidationDuringUpdateAllLifecyclePhases)
+TEST_P(FrameViewTest, SetPaintInvalidationDuringUpdateAllLifecyclePhases)
 {
     document().body()->setInnerHTML("<div id='a' style='color: blue'>A</div>", ASSERT_NO_EXCEPTION);
     document().view()->updateAllLifecyclePhases();
@@ -129,7 +141,7 @@
     EXPECT_FALSE(chromeClient().m_hasScheduledAnimation);
 }
 
-TEST_F(FrameViewTest, SetPaintInvalidationOutOfUpdateAllLifecyclePhases)
+TEST_P(FrameViewTest, SetPaintInvalidationOutOfUpdateAllLifecyclePhases)
 {
     document().body()->setInnerHTML("<div id='a' style='color: blue'>A</div>", ASSERT_NO_EXCEPTION);
     document().view()->updateAllLifecyclePhases();
@@ -146,13 +158,13 @@
 
 // If we don't hide the tooltip on scroll, it can negatively impact scrolling
 // performance. See crbug.com/586852 for details.
-TEST_F(FrameViewTest, HideTooltipWhenScrollPositionChanges)
+TEST_P(FrameViewTest, HideTooltipWhenScrollPositionChanges)
 {
     document().body()->setInnerHTML("<div style='width:1000px;height:1000px'></div>", ASSERT_NO_EXCEPTION);
     document().view()->updateAllLifecyclePhases();
 
     EXPECT_CALL(chromeClient(), setToolTip(String(), _));
-    document().view()->setScrollPosition(DoublePoint(1, 1), UserScroll);
+    document().view()->layoutViewportScrollableArea()->setScrollPosition(DoublePoint(1, 1), UserScroll);
 }
 
 } // namespace
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index cb5500a..ddffbe8 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -375,6 +375,10 @@
     quadForFakeMouseMoveEvent = paintInvalidationContainer.localToAbsoluteQuad(quadForFakeMouseMoveEvent);
     frame->eventHandler().dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
 
+    Page* page = frame->page();
+    if (page)
+        page->chromeClient().clearToolTip();
+
     bool requiresPaintInvalidation = true;
 
     if (box().view()->compositor()->inCompositingMode()) {
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index d248345..fa5e387 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2127,8 +2127,7 @@
     }
     if (cursor.imageScaleFactor() != 1) {
         result.append(" scale=");
-        NumberToStringBuffer buffer;
-        result.append(numberToFixedPrecisionString(cursor.imageScaleFactor(), 8, buffer, true));
+        result.appendNumber(cursor.imageScaleFactor(), 8);
     }
 
     return result.toString();
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index 131ce28..5ab2704d 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -307,7 +307,6 @@
             'front_end/ui/ThrottledView.js',
             'front_end/ui/UIUtils.js',
             'front_end/ui/View.js',
-            'front_end/ui/ViewContainers.js',
             'front_end/ui/ViewportControl.js',
             'front_end/ui/Widget.js',
             'front_end/ui/ZoomManager.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
index 90b49dd3..7197e06 100644
--- a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
+++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilitySidebarView.js
@@ -10,12 +10,12 @@
 {
     WebInspector.ThrottledView.call(this, WebInspector.UIString("Accessibility"));
     this._node = null;
-    this._sidebarPaneStack = new WebInspector.View.ExpandableStackContainer();
+    this._sidebarPaneStack = WebInspector.viewManager.createStackLocation();
     this._ariaSubPane = new WebInspector.ARIAAttributesPane();
-    this._sidebarPaneStack.appendView(this._ariaSubPane, true);
+    this._sidebarPaneStack.showView(this._ariaSubPane);
     this._axNodeSubPane = new WebInspector.AXNodeSubPane();
-    this._sidebarPaneStack.appendView(this._axNodeSubPane, true);
-    this._sidebarPaneStack.show(this.element);
+    this._sidebarPaneStack.showView(this._axNodeSubPane);
+    this._sidebarPaneStack.widget().show(this.element);
     WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._pullNode, this);
     this._pullNode();
 }
@@ -123,12 +123,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {string} name
  */
 WebInspector.AccessibilitySubPane = function(name)
 {
-    WebInspector.View.call(this, name);
+    WebInspector.SimpleView.call(this, name);
 
     this._axNode = null;
     this.registerRequiredCSS("accessibility/accessibilityNode.css");
@@ -186,5 +186,5 @@
         return treeOutline;
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js
index b496b3b..23423c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditResultView.js
@@ -30,12 +30,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.AuditCategoryResult} categoryResult
  */
 WebInspector.AuditCategoryResultPane = function(categoryResult)
 {
-    WebInspector.View.call(this, categoryResult.title);
+    WebInspector.SimpleView.call(this, categoryResult.title);
     this._treeOutline = new TreeOutlineInShadow();
     this._treeOutline.registerRequiredCSS("audits/auditResultTree.css");
     this._treeOutline.element.classList.add("audit-result-tree");
@@ -57,7 +57,7 @@
         var treeElement = this._appendResult(this._treeOutline.rootElement(), ruleResult, ruleResult.severity);
         treeElement.listItemElement.classList.add("audit-result");
     }
-    this.revealWidget();
+    this.revealView();
 }
 
 WebInspector.AuditCategoryResultPane.prototype = {
@@ -105,5 +105,5 @@
         return treeElement;
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
index a51f8ee8..dbacdd497 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditsPanel.js
@@ -129,14 +129,14 @@
      */
     showResults: function(categoryResults)
     {
-        if (!categoryResults._resultView) {
+        if (!categoryResults._resultLocation) {
             categoryResults.sort((a, b) => (a.title || "").localeCompare(b.title || ""));
-            var resultView = new WebInspector.View.ExpandableStackContainer();
+            var resultView = WebInspector.viewManager.createStackLocation();
             for (var i = 0; i < categoryResults.length; ++i)
-                resultView.appendView(new WebInspector.AuditCategoryResultPane(categoryResults[i]), true);
-            categoryResults._resultView = resultView;
+                resultView.showView(new WebInspector.AuditCategoryResultPane(categoryResults[i]));
+            categoryResults._resultLocation = resultView;
         }
-        this.visibleView = categoryResults._resultView;
+        this.visibleView = categoryResults._resultLocation.widget();
     },
 
     showLauncherView: function()
diff --git a/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js b/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js
index 07c6b5f..251248e 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/BreakpointsSidebarPaneBase.js
@@ -30,12 +30,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {string} title
  */
 WebInspector.BreakpointsSidebarPaneBase = function(title)
 {
-    WebInspector.View.call(this, title);
+    WebInspector.SimpleView.call(this, title);
     this.registerRequiredCSS("components/breakpointsList.css");
 
     this.listElement = createElement("ol");
@@ -92,5 +92,5 @@
         }
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
index 7f7b6ccc..51424e1 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/DOMBreakpointsSidebarPane.js
@@ -326,7 +326,7 @@
         var element = this._breakpointElements[breakpointId];
         if (!element)
             return;
-        this.revealWidget();
+        this.revealView();
         element.classList.add("breakpoint-hit");
         this._highlightedElement = element;
     },
@@ -419,13 +419,13 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.DOMBreakpointsSidebarPane} pane
  * @param {!WebInspector.Panel} panel
  */
 WebInspector.DOMBreakpointsSidebarPane.Proxy = function(pane, panel)
 {
-    WebInspector.View.call(this, WebInspector.UIString("DOM Breakpoints"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("DOM Breakpoints"));
     this.registerRequiredCSS("components/breakpointsList.css");
 
     this._wrappedPane = pane;
@@ -435,7 +435,7 @@
 WebInspector.DOMBreakpointsSidebarPane.Proxy.prototype = {
     wasShown: function()
     {
-        WebInspector.View.prototype.wasShown.call(this);
+        WebInspector.SimpleView.prototype.wasShown.call(this);
         this._reattachBody();
     },
 
@@ -445,7 +445,7 @@
             this._wrappedPane.show(this.element);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
index 5b647e44..024fda3 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -101,7 +101,7 @@
     _revealProperty: function(cssProperty)
     {
         var stylesSidebarPane = this.sidebarPanes.styles;
-        this.sidebarPaneView.selectTab(WebInspector.UIString("Styles"));
+        this.sidebarPaneView.showView(stylesSidebarPane);
         stylesSidebarPane.revealProperty(/** @type {!WebInspector.CSSProperty} */(cssProperty));
         return Promise.resolve();
     },
@@ -863,21 +863,19 @@
         if (this.sidebarPaneView && horizontally === !this._splitWidget.isVertical())
             return;
 
-        if (this.sidebarPaneView && this.sidebarPaneView.shouldHideOnDetach())
+        if (this.sidebarPaneView && this.sidebarPaneView.tabbedPane().shouldHideOnDetach())
             return; // We can't reparent extension iframes.
 
-        var selectedTabId = this.sidebarPaneView ? this.sidebarPaneView.selectedTabId : null;
-
         var extensionSidebarPanes = WebInspector.extensionServer.sidebarPanes();
         if (this.sidebarPaneView) {
-            this.sidebarPaneView.detach();
-            this._splitWidget.uninstallResizer(this.sidebarPaneView.headerElement());
+            this.sidebarPaneView.tabbedPane().detach();
+            this._splitWidget.uninstallResizer(this.sidebarPaneView.tabbedPane().headerElement());
         }
 
         this._splitWidget.setVertical(!horizontally);
         this.showToolbarPane(null);
 
-        var computedPane = new WebInspector.View(WebInspector.UIString("Computed"));
+        var computedPane = new WebInspector.SimpleView(WebInspector.UIString("Computed"));
         computedPane.element.classList.add("composite");
         computedPane.element.classList.add("fill");
         computedPane.element.classList.add("metrics-and-computed");
@@ -915,17 +913,18 @@
                 showMetrics.call(this, false);
         }
 
-        this.sidebarPaneView = new WebInspector.View.TabbedPaneContainer();
-        this.sidebarPaneView.element.addEventListener("contextmenu", this._sidebarContextMenuEventFired.bind(this), false);
+        this.sidebarPaneView = WebInspector.viewManager.createTabbedLocation(() => WebInspector.inspectorView.setCurrentPanel(this), "elements-sidebar");
+        var tabbedPane = this.sidebarPaneView.tabbedPane();
+        tabbedPane.element.addEventListener("contextmenu", this._sidebarContextMenuEventFired.bind(this), false);
         if (this._popoverHelper)
             this._popoverHelper.hidePopover();
-        this._popoverHelper = new WebInspector.PopoverHelper(this.sidebarPaneView.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
+        this._popoverHelper = new WebInspector.PopoverHelper(tabbedPane.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
         this._popoverHelper.setTimeout(0);
 
         if (horizontally) {
-            this._splitWidget.installResizer(this.sidebarPaneView.headerElement());
+            this._splitWidget.installResizer(tabbedPane.headerElement());
 
-            var compositePane = new WebInspector.View(WebInspector.UIString("Styles"));
+            var compositePane = new WebInspector.SimpleView(WebInspector.UIString("Styles"));
             compositePane.element.classList.add("flex-auto");
 
             var splitWidget = new WebInspector.SplitWidget(true, true, "stylesPaneSplitViewState", 215);
@@ -936,16 +935,26 @@
 
             computedPane.show(computedStylePanesWrapper.element);
             this.sidebarPaneView.appendView(compositePane);
+
+            // TODO: remove
+            this.sidebarPanes.styles.setParentViewForReveal(compositePane);
+            this.sidebarPanes.computedStyle.setParentViewForReveal(compositePane);
+            this.sidebarPanes.metrics.setParentViewForReveal(compositePane);
         } else {
-            var stylesPane = new WebInspector.View(WebInspector.UIString("Styles"));
+            var stylesPane = new WebInspector.SimpleView(WebInspector.UIString("Styles"));
             stylesPane.element.classList.add("flex-auto", "metrics-and-styles");
 
             matchedStylesContainer.show(stylesPane.element);
             computedStylePanesWrapper.show(computedPane.element);
 
-            this.sidebarPaneView.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, tabSelected, this);
+            tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, tabSelected, this);
             this.sidebarPaneView.appendView(stylesPane);
             this.sidebarPaneView.appendView(computedPane);
+
+            // TODO: remove
+            this.sidebarPanes.styles.setParentViewForReveal(stylesPane);
+            this.sidebarPanes.computedStyle.setParentViewForReveal(computedPane);
+            this.sidebarPanes.metrics.setParentViewForReveal(computedPane);
         }
 
         this.sidebarPanes.styles.show(matchedStylePanesWrapper.element);
@@ -964,10 +973,7 @@
         for (var i = 0; i < extensionSidebarPanes.length; ++i)
             this._addExtensionSidebarPane(extensionSidebarPanes[i]);
 
-        this._splitWidget.setSidebarWidget(this.sidebarPaneView);
-
-        if (selectedTabId)
-            this.sidebarPaneView.selectTab(selectedTabId);
+        this._splitWidget.setSidebarWidget(this.sidebarPaneView.tabbedPane());
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js
index c934bb8..3af1ba3e 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js
@@ -4,12 +4,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {string} title
  */
 WebInspector.ElementsSidebarPane = function(title)
 {
-    WebInspector.View.call(this, title);
+    WebInspector.SimpleView.call(this, title);
     this.element.classList.add("flex-none");
     this._computedStyleModel = new WebInspector.ComputedStyleModel();
     this._computedStyleModel.addEventListener(WebInspector.ComputedStyleModel.Events.ComputedStyleChanged, this.onCSSModelChanged, this);
@@ -63,7 +63,7 @@
 
     wasShown: function()
     {
-        WebInspector.View.prototype.wasShown.call(this);
+        WebInspector.SimpleView.prototype.wasShown.call(this);
         if (this._updateWhenVisible)
             this.update();
     },
@@ -73,5 +73,5 @@
      */
     onCSSModelChanged: function(event) { },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
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 21e291c..5d7b27d 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -425,7 +425,7 @@
      */
     _addBlankSection: function(insertAfterSection, styleSheetId, ruleLocation)
     {
-        this.revealWidget();
+        this.revealView();
         var node = this.node();
         var blankSection = new WebInspector.BlankStylePropertiesSection(this, insertAfterSection._matchedStyles, node ? WebInspector.DOMPresentationUtils.simpleSelector(node) : "", styleSheetId, ruleLocation, insertAfterSection._style);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionPanel.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionPanel.js
index 3f4408d1..973cf7b1 100644
--- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionPanel.js
@@ -173,7 +173,7 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.ExtensionServer} server
  * @param {string} panelName
  * @param {string} title
@@ -181,7 +181,7 @@
  */
 WebInspector.ExtensionSidebarPane = function(server, panelName, title, id)
 {
-    WebInspector.View.call(this, title);
+    WebInspector.SimpleView.call(this, title);
     this.element.classList.add("fill");
     this._panelName = panelName;
     this._server = server;
@@ -305,5 +305,5 @@
         callback();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index ba90e89..64c796c 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -131,6 +131,8 @@
     {
         console.timeStamp("Main._createApp");
 
+        WebInspector.viewManager = new WebInspector.ViewManager();
+
         // Request filesystems early, we won't create connections until callback is fired. Things will happen in parallel.
         WebInspector.isolatedFileSystemManager = new WebInspector.IsolatedFileSystemManager();
         WebInspector.isolatedFileSystemManager.initialize(this._didInitializeFileSystemManager.bind(this));
diff --git a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
index 45ce5c3..aa1c7a01 100644
--- a/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
+++ b/third_party/WebKit/Source/devtools/front_end/network/RequestPreviewView.js
@@ -72,9 +72,9 @@
         {
             this._previewView = view;
             view.show(this.element);
-            if (view instanceof WebInspector.View) {
+            if (view instanceof WebInspector.SimpleView) {
                 var toolbar = new WebInspector.Toolbar("network-item-preview-toolbar", this.element);
-                for (var item of /** @type {!WebInspector.View} */ (view).toolbarItems())
+                for (var item of /** @type {!WebInspector.SimpleView} */ (this._previewView).syncToolbarItems())
                     toolbar.appendToolbarItem(item);
             }
             this._previewViewHandledForTest(view);
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
index 7b804eb..141a175 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -32,13 +32,13 @@
  * @constructor
  * @implements {WebInspector.ProfileType.DataDisplayDelegate}
  * @implements {WebInspector.Searchable}
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.ProfileType.DataDisplayDelegate} dataDisplayDelegate
  * @param {!WebInspector.HeapProfileHeader} profile
  */
 WebInspector.HeapSnapshotView = function(dataDisplayDelegate, profile)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Heap Snapshot"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Heap Snapshot"));
 
     this.element.classList.add("heap-snapshot-view");
 
@@ -526,7 +526,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         var result = [this._perspectiveSelect, this._classNameFilter];
         if (this._profile.profileType() !== WebInspector.ProfileTypeRegistry.instance.trackingHeapSnapshotProfileType)
@@ -1011,7 +1011,7 @@
             this._trackingOverviewGrid.dispose();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/ProfileView.js b/third_party/WebKit/Source/devtools/front_end/profiler/ProfileView.js
index 267a90f..fbec243a 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/ProfileView.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/ProfileView.js
@@ -5,13 +5,13 @@
 /**
  * @constructor
  * @implements {WebInspector.Searchable}
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.ProfileDataGridNode.Formatter} nodeFormatter
  * @param {!Array<string>=} viewTypes
  */
 WebInspector.ProfileView = function(nodeFormatter, viewTypes)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Profile"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Profile"));
 
     this._searchableView = new WebInspector.SearchableView(this);
     this._searchableView.setPlaceholder(WebInspector.UIString("Find by cost (>50ms), name or file"));
@@ -113,7 +113,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this.viewSelectComboBox, this.focusButton, this.excludeButton, this.resetButton];
     },
@@ -367,7 +367,7 @@
         this.refresh();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
index 29521719..746c8c71 100644
--- a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
@@ -815,7 +815,7 @@
 
         this._profileViewToolbar.removeToolbarItems();
 
-        var toolbarItems = view.toolbarItems();
+        var toolbarItems = view.syncToolbarItems();
         for (var i = 0; i < toolbarItems.length; ++i)
             this._profileViewToolbar.appendToolbarItem(toolbarItems[i]);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
index 1a6e601..fe25f6c 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -25,11 +25,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.ApplicationCacheItemsView = function(model, frameId)
 {
-    WebInspector.View.call(this, WebInspector.UIString("AppCache"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("AppCache"));
 
     this._model = model;
 
@@ -65,7 +65,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [
             this._deleteButton,
@@ -258,6 +258,6 @@
         // this._update();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
index 1b58eee..09d58bc 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/CookieItemsView.js
@@ -29,11 +29,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.CookieItemsView = function(treeElement, cookieDomain)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Cookies"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Cookies"));
 
     this.element.classList.add("storage-view");
 
@@ -62,7 +62,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._refreshButton, this._clearButton, this._deleteButton];
     },
@@ -187,5 +187,5 @@
         }
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/DOMStorageItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/DOMStorageItemsView.js
index 055b675..9b988ce 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/DOMStorageItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/DOMStorageItemsView.js
@@ -26,11 +26,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.DOMStorageItemsView = function(domStorage)
 {
-    WebInspector.View.call(this, WebInspector.UIString("DOM Storage"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("DOM Storage"));
 
     this.domStorage = domStorage;
 
@@ -54,7 +54,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this.refreshButton, this.deleteButton];
     },
@@ -259,5 +259,5 @@
             this.domStorage.removeItem(node.data.key);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js
index ada854f8..3d7ac44 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/DatabaseTableView.js
@@ -25,11 +25,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.DatabaseTableView = function(database, tableName)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Database"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Database"));
 
     this.database = database;
     this.tableName = tableName;
@@ -54,7 +54,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this.refreshButton, this._visibleColumnsInput];
     },
@@ -143,5 +143,5 @@
         this.update();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
index 7be9acc..63b5ed95 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/IndexedDBViews.js
@@ -97,7 +97,7 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.IndexedDBModel} model
  * @param {!WebInspector.IndexedDBModel.DatabaseId} databaseId
  * @param {!WebInspector.IndexedDBModel.ObjectStore} objectStore
@@ -105,7 +105,7 @@
  */
 WebInspector.IDBDataView = function(model, databaseId, objectStore, index)
 {
-    WebInspector.View.call(this, WebInspector.UIString("IDB"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("IDB"));
     this.registerRequiredCSS("resources/indexedDBViews.css");
 
     this._model = model;
@@ -337,7 +337,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._refreshButton, this._clearButton];
     },
@@ -348,7 +348,7 @@
         this._entries = [];
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
index cd2d34b2..86fdd77 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ResourcesPanel.js
@@ -662,7 +662,7 @@
         this.visibleView = view;
 
         this._storageViewToolbar.removeToolbarItems();
-        var toolbarItems = view.toolbarItems ? view.toolbarItems() : null;
+        var toolbarItems = view instanceof WebInspector.SimpleView ? view.syncToolbarItems() : null;
         for (var i = 0; toolbarItems && i < toolbarItems.length; ++i)
             this._storageViewToolbar.appendToolbarItem(toolbarItems[i]);
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
index 3acf838..e9d1b95b 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ServiceWorkerCacheViews.js
@@ -4,13 +4,13 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.ServiceWorkerCacheModel} model
  * @param {!WebInspector.ServiceWorkerCacheModel.Cache} cache
  */
 WebInspector.ServiceWorkerCacheView = function(model, cache)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Cache"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Cache"));
     this.registerRequiredCSS("resources/serviceWorkerCacheViews.css");
 
     this._model = model;
@@ -148,7 +148,7 @@
      * @override
      * @return {!Array.<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._refreshButton];
     },
@@ -159,5 +159,5 @@
         this._entries = [];
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
index 15a0ec0..9b48adf 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/RemoteObject.js
@@ -514,7 +514,7 @@
             }
 
             if (!this._objectId) {
-                reject(null);
+                reject(new Error("No object id specified"));
                 return;
             }
 
@@ -528,7 +528,7 @@
             function mycallback(error, payloads)
             {
                 if (error) {
-                    reject(null);
+                    reject(new Error(error));
                     return;
                 }
                 fulfill(payloads.map(createEventListener.bind(this)));
diff --git a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
index cea3b876..bd5964b 100644
--- a/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
+++ b/third_party/WebKit/Source/devtools/front_end/settings/SettingsScreen.js
@@ -44,7 +44,7 @@
     var settingsLabelElement = createElementWithClass("div", "help-window-label");
     settingsLabelElement.createTextChild(WebInspector.UIString("Settings"));
 
-    this._tabbedLocation = WebInspector.viewManager.createTabbedLocation("settings-view");
+    this._tabbedLocation = WebInspector.viewManager.createTabbedLocation(() => WebInspector.SettingsScreen._showSettingsScreen(), "settings-view");
     var tabbedPane = this._tabbedLocation.tabbedPane();
     tabbedPane.insertBeforeTabStrip(settingsLabelElement);
     tabbedPane.setShrinkableTabs(false);
@@ -63,10 +63,12 @@
 WebInspector.SettingsScreen._showSettingsScreen = function(name)
 {
     var settingsScreen = /** @type {!WebInspector.SettingsScreen} */ (self.runtime.sharedInstance(WebInspector.SettingsScreen));
+    if (settingsScreen.isShowing())
+        return;
     var dialog = new WebInspector.Dialog();
     dialog.addCloseButton();
     settingsScreen.show(dialog.element);
-    settingsScreen.selectTab(name || "preferences");
+    settingsScreen._selectTab(name || "preferences");
     dialog.show();
 }
 
@@ -77,18 +79,17 @@
      * @param {string} locationName
      * @return {?WebInspector.ViewLocation}
      */
-    revealLocation: function(locationName)
+    resolveLocation: function(locationName)
     {
-        WebInspector.SettingsScreen._showSettingsScreen();
         return this._tabbedLocation;
     },
 
     /**
      * @param {string} name
      */
-    selectTab: function(name)
+    _selectTab: function(name)
     {
-        this._tabbedLocation.showView(name);
+        WebInspector.viewManager.showView(name);
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js
index 4aee681..210d9703 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js
@@ -28,13 +28,13 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {string} mimeType
  * @param {!WebInspector.ContentProvider} contentProvider
  */
 WebInspector.FontView = function(mimeType, contentProvider)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Font"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Font"));
     this.registerRequiredCSS("source_frame/fontView.css");
     this.element.classList.add("font-view");
     this._url = contentProvider.contentURL();
@@ -54,7 +54,7 @@
      * @override
      * @return {!Array<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._mimeTypeLabel];
     },
@@ -157,5 +157,5 @@
         this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js
index d6e7dcd..48530cbb 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js
@@ -27,14 +27,14 @@
  */
 
 /**
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @constructor
  * @param {string} mimeType
  * @param {!WebInspector.ContentProvider} contentProvider
  */
 WebInspector.ImageView = function(mimeType, contentProvider)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Image"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Image"));
     this.registerRequiredCSS("source_frame/imageView.css");
     this.element.classList.add("image-view");
     this._url = contentProvider.contentURL();
@@ -51,7 +51,7 @@
      * @override
      * @return {!Array<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._sizeLabel, new WebInspector.ToolbarSeparator(), this._dimensionsLabel, new WebInspector.ToolbarSeparator(), this._mimeTypeLabel];
     },
@@ -136,5 +136,5 @@
         InspectorFrontendHost.openInNewTab(this._url);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js
index aedc881..b3b29bc 100644
--- a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js
@@ -30,7 +30,7 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @implements {WebInspector.Searchable}
  * @implements {WebInspector.Replaceable}
  * @param {string} url
@@ -38,7 +38,7 @@
  */
 WebInspector.SourceFrame = function(url, lazyContent)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Source"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Source"));
 
     this._url = url;
     this._lazyContent = lazyContent;
@@ -106,7 +106,7 @@
      * @override
      * @return {!Array<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
         return [this._sourcePosition];
     },
@@ -638,7 +638,7 @@
             e.consume(true);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
index a176254..2126ac1 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/CallStackSidebarPane.js
@@ -25,11 +25,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.CallStackSidebarPane = function()
 {
-    WebInspector.View.call(this, WebInspector.UIString("Call Stack"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Call Stack"));
     this.element.addEventListener("keydown", this._keyDown.bind(this), true);
     this.element.tabIndex = 0;
     this.callFrameList = new WebInspector.UIList();
@@ -426,7 +426,7 @@
             event.consume(true);
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
index 733b963..5876d0b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/EventListenerBreakpointsSidebarPane.js
@@ -4,12 +4,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @implements {WebInspector.TargetManager.Observer}
  */
 WebInspector.EventListenerBreakpointsSidebarPane = function()
 {
-    WebInspector.View.call(this, WebInspector.UIString("Event Listener Breakpoints"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Event Listener Breakpoints"));
     this.registerRequiredCSS("components/breakpointsList.css");
 
     this._eventListenerBreakpointsSetting = WebInspector.settings.createLocalSetting("eventListenerBreakpoints", []);
@@ -303,7 +303,7 @@
             breakpointItem = this._findBreakpointItem(eventName, WebInspector.EventListenerBreakpointsSidebarPane.eventTargetAny);
         if (!breakpointItem)
             return;
-        this.revealWidget();
+        this.revealView();
         breakpointItem.parent.element.expand();
         breakpointItem.element.listItemElement.classList.add("breakpoint-hit");
         this._highlightedElement = breakpointItem.element.listItemElement;
@@ -344,5 +344,5 @@
         }
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
index 00262c3..25c2186 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptBreakpointsSidebarPane.js
@@ -4,13 +4,13 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {!WebInspector.BreakpointManager} breakpointManager
  * @param {function(!WebInspector.UISourceCode, number=, number=, boolean=)} showSourceLineDelegate
  */
 WebInspector.JavaScriptBreakpointsSidebarPane = function(breakpointManager, showSourceLineDelegate)
 {
-    WebInspector.View.call(this, WebInspector.UIString("Breakpoints"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Breakpoints"));
     this.registerRequiredCSS("components/breakpointsList.css");
 
     this._breakpointManager = breakpointManager;
@@ -144,7 +144,7 @@
             return;
         breakpointItem.element.classList.add("breakpoint-hit");
         this._highlightedBreakpointItem = breakpointItem;
-        this.revealWidget();
+        this.revealView();
     },
 
     clearBreakpointHighlight: function()
@@ -255,5 +255,5 @@
         this._items.clear();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index ece3e7a..ecf07a0c 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -83,9 +83,9 @@
      * @override
      * @return {!Array<!WebInspector.ToolbarItem>}
      */
-    toolbarItems: function()
+    syncToolbarItems: function()
     {
-        var result = WebInspector.UISourceCodeFrame.prototype.toolbarItems.call(this);
+        var result = WebInspector.UISourceCodeFrame.prototype.syncToolbarItems.call(this);
         var originURL = WebInspector.CompilerScriptMapping.uiSourceCodeOrigin(this.uiSourceCode());
         if (originURL) {
             var parsedURL = originURL.asParsedURL();
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ObjectEventListenersSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/ObjectEventListenersSidebarPane.js
index 8dafcb1..ccc04e3e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ObjectEventListenersSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ObjectEventListenersSidebarPane.js
@@ -4,11 +4,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.ObjectEventListenersSidebarPane = function()
 {
-    WebInspector.View.call(this, "Event Listeners");
+    WebInspector.SimpleView.call(this, "Event Listeners");
     this.element.classList.add("event-listeners-sidebar-pane");
 
     this._refreshButton = new WebInspector.ToolbarButton(WebInspector.UIString("Refresh"), "refresh-toolbar-item");
@@ -40,7 +40,7 @@
 
     wasShown: function()
     {
-        WebInspector.View.prototype.wasShown.call(this);
+        WebInspector.SimpleView.prototype.wasShown.call(this);
         WebInspector.context.addFlavorChangeListener(WebInspector.ExecutionContext, this.update, this);
         this._refreshButton.setEnabled(true);
         this.update();
@@ -48,7 +48,7 @@
 
     willHide: function()
     {
-        WebInspector.View.prototype.willHide.call(this);
+        WebInspector.SimpleView.prototype.willHide.call(this);
         WebInspector.context.removeFlavorChangeListener(WebInspector.ExecutionContext, this.update, this);
         this._refreshButton.setEnabled(false);
     },
@@ -89,5 +89,5 @@
         this.update();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
index 8be8742..858a67e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ScopeChainSidebarPane.js
@@ -26,11 +26,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.ScopeChainSidebarPane = function()
 {
-    WebInspector.View.call(this, WebInspector.UIString("Scope"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Scope"));
     this._expandController = new WebInspector.ObjectPropertiesSectionExpandController();
     this._linkifier = new WebInspector.Linkifier();
 }
@@ -138,5 +138,5 @@
 
     _sidebarPaneUpdatedForTest: function() { },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
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 6059607..9f97ef7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -64,7 +64,7 @@
     this._splitWidget.setMainWidget(this.editorView);
 
     // Create navigator tabbed pane with toolbar.
-    this._navigatorTabbedLocation = WebInspector.viewManager.createTabbedLocation("navigator-view", true);
+    this._navigatorTabbedLocation = WebInspector.viewManager.createTabbedLocation(this._setAsCurrentPanel.bind(this), "navigator-view", true);
     var tabbedPane = this._navigatorTabbedLocation.tabbedPane();
     tabbedPane.setMinimumSize(100, 25);
     tabbedPane.setShrinkableTabs(true);
@@ -96,8 +96,6 @@
     this.sidebarPanes.eventListenerBreakpoints = new WebInspector.EventListenerBreakpointsSidebarPane();
     this.sidebarPanes.objectEventListeners = new WebInspector.ObjectEventListenersSidebarPane();
 
-    this._lastSelectedTabSetting = WebInspector.settings.createLocalSetting("lastSelectedSourcesSidebarPaneTab", WebInspector.UIString("Scope"));
-
     this._installDebuggerSidebarController();
 
     WebInspector.moduleSetting("sidebarPosition").addChangeListener(this._updateSidebarPosition.bind(this));
@@ -139,7 +137,7 @@
         if (hasThreads && !this.sidebarPanes.threads) {
             this.sidebarPanes.threads = new WebInspector.ThreadsSidebarPane();
             if (this._sidebarPaneStack) {
-                this._sidebarPaneStack.insertViewBefore(this.sidebarPanes.threads, this._splitWidget.isVertical() ? this.sidebarPanes.watchExpressions : this.sidebarPanes.callstack, true);
+                this._sidebarPaneStack.showView(this.sidebarPanes.threads, this._splitWidget.isVertical() ? this.sidebarPanes.watchExpressions : this.sidebarPanes.callstack);
             }
         }
     },
@@ -219,9 +217,8 @@
      * @param {string} locationName
      * @return {?WebInspector.ViewLocation}
      */
-    revealLocation: function(locationName)
+    resolveLocation: function(locationName)
     {
-        WebInspector.inspectorView.setCurrentPanel(WebInspector.SourcesPanel.instance());
         return this._navigatorTabbedLocation;
     },
 
@@ -1125,44 +1122,47 @@
         var vbox = new WebInspector.VBox();
         vbox.element.appendChild(this._debugToolbarDrawer);
         vbox.setMinimumAndPreferredSizes(25, 25, WebInspector.SourcesPanel.minToolbarWidth, 100);
-        this._sidebarPaneStack = new WebInspector.View.ExpandableStackContainer();
-        this._sidebarPaneStack.show(vbox.element);
+        this._sidebarPaneStack = WebInspector.viewManager.createStackLocation(this._setAsCurrentPanel.bind(this), "sources-sidebar");
+        this._sidebarPaneStack.widget().show(vbox.element);
         vbox.element.appendChild(this._debugToolbar.element);
 
+        if (this.sidebarPanes.threads)
+            this._sidebarPaneStack.showView(this.sidebarPanes.threads);
+
         if (!vertically) {
-            // Populate the only stack.
+            if (this.sidebarPanes.watchExpressions.hasExpressions())
+                this._sidebarPaneStack.showView(this.sidebarPanes.watchExpressions);
+            else
+                this._sidebarPaneStack.appendView(this.sidebarPanes.watchExpressions);
+        }
+
+        this._sidebarPaneStack.showView(this.sidebarPanes.callstack);
+        this._sidebarPaneStack.showView(this.sidebarPanes.scopechain);
+        this._sidebarPaneStack.showView(this.sidebarPanes.jsBreakpoints);
+
+        if (!vertically) {
+            // Populate the rest of the stack.
             for (var pane in this.sidebarPanes) {
                 if (this.sidebarPanes[pane])
                     this._sidebarPaneStack.appendView(this.sidebarPanes[pane]);
             }
             this._extensionSidebarPanesContainer = this._sidebarPaneStack;
             this.sidebarPaneView = vbox;
-
-            this.sidebarPanes.scopechain.revealWidget();
-            this.sidebarPanes.watchExpressions.expandIfNecessary();
         } else {
             var splitWidget = new WebInspector.SplitWidget(true, true, "sourcesPanelDebuggerSidebarSplitViewState", 0.5);
             splitWidget.setMainWidget(vbox);
 
             // Populate the left stack.
-            if (this.sidebarPanes.threads)
-                this._sidebarPaneStack.appendView(this.sidebarPanes.threads);
-            this._sidebarPaneStack.appendView(this.sidebarPanes.callstack);
-            this._sidebarPaneStack.appendView(this.sidebarPanes.jsBreakpoints);
             this._sidebarPaneStack.appendView(this.sidebarPanes.domBreakpoints);
             this._sidebarPaneStack.appendView(this.sidebarPanes.xhrBreakpoints);
             this._sidebarPaneStack.appendView(this.sidebarPanes.eventListenerBreakpoints);
             this._sidebarPaneStack.appendView(this.sidebarPanes.objectEventListeners);
 
-            var tabbedPane = new WebInspector.View.TabbedPaneContainer();
-            splitWidget.setSidebarWidget(tabbedPane);
-            tabbedPane.appendView(this.sidebarPanes.scopechain);
-            tabbedPane.appendView(this.sidebarPanes.watchExpressions);
-            if (this.sidebarPanes.serviceWorkers)
-                tabbedPane.appendView(this.sidebarPanes.serviceWorkers);
-            tabbedPane.selectTab(this._lastSelectedTabSetting.get());
-            tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
-            this._extensionSidebarPanesContainer = tabbedPane;
+            var tabbedLocation = WebInspector.viewManager.createTabbedLocation(this._setAsCurrentPanel.bind(this), "sources-sidebar-tabs");
+            splitWidget.setSidebarWidget(tabbedLocation.tabbedPane());
+            tabbedLocation.appendView(this.sidebarPanes.scopechain);
+            tabbedLocation.appendView(this.sidebarPanes.watchExpressions);
+            this._extensionSidebarPanesContainer = tabbedLocation;
             this.sidebarPaneView = splitWidget;
         }
 
@@ -1171,18 +1171,11 @@
             this._addExtensionSidebarPane(extensionSidebarPanes[i]);
 
         this._splitWidget.setSidebarWidget(this.sidebarPaneView);
-        if (this.sidebarPanes.threads)
-            this.sidebarPanes.threads.revealWidget();
-        this.sidebarPanes.jsBreakpoints.revealWidget();
-        this.sidebarPanes.callstack.revealWidget();
     },
 
-    /**
-     * @param {!WebInspector.Event} event
-     */
-    _tabSelected: function(event)
+    _setAsCurrentPanel: function()
     {
-        this._lastSelectedTabSetting.set(event.data.tabId);
+        WebInspector.inspectorView.setCurrentPanel(this);
     },
 
     /**
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 2b57bda..eea0d2d7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -270,8 +270,8 @@
     {
         this._scriptViewToolbar.removeToolbarItems();
         var view = this.visibleView()
-        if (view instanceof WebInspector.View) {
-            for (var item of (/** @type {?WebInspector.View} */(view)).toolbarItems())
+        if (view instanceof WebInspector.SimpleView) {
+            for (var item of (/** @type {?WebInspector.SimpleView} */(view)).syncToolbarItems())
                 this._scriptViewToolbar.appendToolbarItem(item);
         }
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js
index 5b7d53c..dbd0fc7 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/ThreadsSidebarPane.js
@@ -4,12 +4,12 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @implements {WebInspector.TargetManager.Observer}
  */
 WebInspector.ThreadsSidebarPane = function()
 {
-    WebInspector.View.call(this, WebInspector.UIString("Threads"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Threads"));
 
     /** @type {!Map.<!WebInspector.DebuggerModel, !WebInspector.UIList.Item>} */
     this._debuggerModelToListItems = new Map();
@@ -137,5 +137,5 @@
     },
 
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
index 54ef09fb..bbcdf0fe 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/WatchExpressionsSidebarPane.js
@@ -30,11 +30,11 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  */
 WebInspector.WatchExpressionsSidebarPane = function()
 {
-    WebInspector.View.call(this, WebInspector.UIString("Watch"));
+    WebInspector.SimpleView.call(this, WebInspector.UIString("Watch"));
     this.registerRequiredCSS("components/objectValue.css");
 
     this._requiresUpdate = true;
@@ -75,7 +75,7 @@
      */
     addExpression: function(expressionString)
     {
-        this.revealWidget();
+        this.revealView();
         if (this._requiresUpdate) {
             this._rebuildWatchExpressions();
             delete this._requiresUpdate;
@@ -84,10 +84,12 @@
         this._saveExpressions();
     },
 
-    expandIfNecessary: function()
+    /**
+     * @return {boolean}
+     */
+    hasExpressions: function()
     {
-        if (this._watchExpressionsSetting.get().length)
-            this.revealWidget();
+        return !!this._watchExpressionsSetting.get().length;
     },
 
     _saveExpressions: function()
@@ -116,7 +118,7 @@
     {
         if (event)
             event.consume(true);
-        this.revealWidget();
+        this.revealView();
         this._createWatchExpression(null).startEditing();
     },
 
@@ -213,7 +215,7 @@
         this._rebuildWatchExpressions();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
index 251e80a..e6a37edd 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/XHRBreakpointsSidebarPane.js
@@ -52,7 +52,7 @@
         if (event)
             event.consume();
 
-        this.revealWidget();
+        this.revealView();
 
         var inputElementContainer = createElementWithClass("p", "breakpoint-condition");
         inputElementContainer.textContent = WebInspector.UIString("Break when URL contains:");
@@ -217,7 +217,7 @@
         var element = this._breakpointElements.get(url);
         if (!element)
             return;
-        this.revealWidget();
+        this.revealView();
         element.classList.add("breakpoint-hit");
         this._highlightedElement = element;
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/module.json b/third_party/WebKit/Source/devtools/front_end/sources/module.json
index ec5299f..e70e693 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sources/module.json
@@ -342,7 +342,7 @@
             "location": "drawer-view",
             "id": "sources.history",
             "title": "History",
-            "persistence": "temporary",
+            "persistence": "transient",
             "className": "WebInspector.RevisionHistoryView"
         },
         {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
index 87f968c..571f8f0 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/InspectorView.js
@@ -47,7 +47,8 @@
     this._drawerSplitWidget.show(this.element);
 
     // Create drawer tabbed pane.
-    this._drawerTabbedLocation = WebInspector.viewManager.createTabbedLocation("drawer-view", true, true);
+    this._drawerTabbedLocation = WebInspector.viewManager.createTabbedLocation(this.showDrawer.bind(this), "drawer-view", true);
+    this._drawerTabbedLocation.enableMoreTabsButton();
     this._drawerTabbedPane = this._drawerTabbedLocation.tabbedPane();
     this._drawerTabbedPane.setMinimumSize(0, 27);
     var drawerToolbar = new WebInspector.Toolbar("drawer-close-toolbar");
@@ -123,9 +124,8 @@
      * @param {string} locationName
      * @return {?WebInspector.ViewLocation}
      */
-    revealLocation: function(locationName)
+    resolveLocation: function(locationName)
     {
-        this.showDrawer();
         return this._drawerTabbedLocation;
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
index 1eb8004..119d844 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/TabbedPane.js
@@ -852,25 +852,6 @@
         this._automaticReorder = automatic;
     },
 
-    /**
-     * @override
-     * @param {!WebInspector.Widget} child
-     * @return {boolean}
-     */
-    revealChild: function(child)
-    {
-        if (this._currentTabLocked)
-            return false;
-
-        for (var tabId of this.tabIds()) {
-            if (this.tabView(tabId) === child) {
-                this.selectTab(tabId);
-                return true;
-            }
-        }
-        return false;
-    },
-
     __proto__: WebInspector.VBox.prototype
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ThrottledView.js b/third_party/WebKit/Source/devtools/front_end/ui/ThrottledView.js
index 0a657da..650d552 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ThrottledView.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ThrottledView.js
@@ -4,13 +4,13 @@
 
 /**
  * @constructor
- * @extends {WebInspector.View}
+ * @extends {WebInspector.SimpleView}
  * @param {string} title
  * @param {boolean=} isWebComponent
  */
 WebInspector.ThrottledView = function(title, isWebComponent)
 {
-    WebInspector.View.call(this, title, isWebComponent);
+    WebInspector.SimpleView.call(this, title, isWebComponent);
     this._updateThrottler = new WebInspector.Throttler(100);
     this._updateWhenVisible = false;
 }
@@ -52,10 +52,10 @@
      */
     wasShown: function()
     {
-        WebInspector.View.prototype.wasShown.call(this);
+        WebInspector.SimpleView.prototype.wasShown.call(this);
         if (this._updateWhenVisible)
             this.update();
     },
 
-    __proto__: WebInspector.View.prototype
+    __proto__: WebInspector.SimpleView.prototype
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/View.js b/third_party/WebKit/Source/devtools/front_end/ui/View.js
index 5863780..608bb09 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/View.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/View.js
@@ -3,12 +3,52 @@
 // found in the LICENSE file.
 
 /**
+ * @interface
+ */
+WebInspector.View = function()
+{
+}
+
+WebInspector.View.prototype = {
+    /**
+     * @return {string}
+     */
+    viewId: function() { },
+
+    /**
+     * @return {string}
+     */
+    title: function() { },
+
+    /**
+     * @return {boolean}
+     */
+    isCloseable: function() { },
+
+    /**
+     * @return {boolean}
+     */
+    isTransient: function() { },
+
+    /**
+     * @return {!Promise<!Array<!WebInspector.ToolbarItem>>}
+     */
+    toolbarItems: function() { },
+
+    /**
+     * @return {!Promise<!WebInspector.Widget>}
+     */
+    widget: function() { }
+}
+
+/**
  * @constructor
  * @extends {WebInspector.VBox}
+ * @implements {WebInspector.View}
  * @param {string} title
  * @param {boolean=} isWebComponent
  */
-WebInspector.View = function(title, isWebComponent)
+WebInspector.SimpleView = function(title, isWebComponent)
 {
     WebInspector.VBox.call(this, isWebComponent);
     this._title = title;
@@ -16,8 +56,18 @@
     this._toolbarItems = [];
 }
 
-WebInspector.View.prototype = {
+WebInspector.SimpleView.prototype = {
     /**
+     * @override
+     * @return {string}
+     */
+    viewId: function()
+    {
+        return this._title;
+    },
+
+    /**
+     * @override
      * @return {string}
      */
     title: function()
@@ -26,6 +76,50 @@
     },
 
     /**
+     * @override
+     * @return {boolean}
+     */
+    isCloseable: function()
+    {
+        return false;
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    isTransient: function()
+    {
+        return false;
+    },
+
+    /**
+     * @override
+     * @return {!Promise<!Array<!WebInspector.ToolbarItem>>}
+     */
+    toolbarItems: function()
+    {
+        return Promise.resolve(this.syncToolbarItems());
+    },
+
+    /**
+     * @return {!Array<!WebInspector.ToolbarItem>}
+     */
+    syncToolbarItems: function()
+    {
+        return this._toolbarItems;
+    },
+
+    /**
+     * @override
+     * @return {!Promise<!WebInspector.Widget>}
+     */
+    widget: function()
+    {
+        return /** @type {!Promise<!WebInspector.Widget>} */ (Promise.resolve(this));
+    },
+
+    /**
      * @param {!WebInspector.ToolbarItem} item
      */
     addToolbarItem: function(item)
@@ -34,26 +128,108 @@
     },
 
     /**
-     * @return {!Array<!WebInspector.ToolbarItem>}
+     * @return {!Promise}
      */
-    toolbarItems: function()
+    revealView: function()
     {
-        return this._toolbarItems;
+        return WebInspector.viewManager.revealView(this._parentViewToReveal || this);
+    },
+
+    /**
+     * @param {!WebInspector.View} view
+     */
+    setParentViewForReveal: function(view)
+    {
+        this._parentViewToReveal = view;
     },
 
     __proto__: WebInspector.VBox.prototype
 }
 
 /**
+ * @constructor
+ * @implements {WebInspector.View}
+ * @param {!Runtime.Extension} extension
+ */
+WebInspector.ProvidedView = function(extension)
+{
+    this._extension = extension;
+}
+
+WebInspector.ProvidedView.prototype = {
+    /**
+     * @override
+     * @return {string}
+     */
+    viewId: function()
+    {
+        return this._extension.descriptor()["id"];
+    },
+
+    /**
+     * @override
+     * @return {string}
+     */
+    title: function()
+    {
+        return this._extension.title();
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    isCloseable: function()
+    {
+        return this._extension.descriptor()["persistence"] === "closeable";
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    isTransient: function()
+    {
+        return this._extension.descriptor()["persistence"] === "transient";
+    },
+
+    /**
+     * @override
+     * @return {!Promise<!Array<!WebInspector.ToolbarItem>>}
+     */
+    toolbarItems: function()
+    {
+        return Promise.resolve([]);
+    },
+
+    /**
+     * @override
+     * @return {!Promise<!WebInspector.Widget>}
+     */
+    widget: function()
+    {
+        return  /** @type {!Promise<!WebInspector.Widget>} */ (this._extension.instance());
+    }
+}
+
+/**
  * @interface
  */
 WebInspector.ViewLocation = function() { }
 
 WebInspector.ViewLocation.prototype = {
     /**
-     * @param {string} viewId
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
      */
-    showView: function(viewId) { },
+    appendView: function(view, insertBefore) { },
+
+    /**
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
+     * @return {!Promise}
+     */
+    showView: function(view, insertBefore) { },
 
     /**
      * @return {!WebInspector.Widget}
@@ -72,6 +248,8 @@
      * @return {!WebInspector.TabbedPane}
      */
     tabbedPane: function() { },
+
+    enableMoreTabsButton: function() { }
 }
 
 /**
@@ -84,7 +262,7 @@
      * @param {string} location
      * @return {?WebInspector.ViewLocation}
      */
-    revealLocation: function(location) { }
+    resolveLocation: function(location) { }
 }
 
 /**
@@ -92,91 +270,290 @@
  */
 WebInspector.ViewManager = function()
 {
+    /** @type {!Map<string, !WebInspector.View>} */
+    this._views = new Map();
+    /** @type {!Map<string, string>} */
+    this._locationNameByViewId = new Map();
+
+    for (var extension of self.runtime.extensions("view")) {
+        var descriptor = extension.descriptor();
+        this._views.set(descriptor["id"], new WebInspector.ProvidedView(extension));
+        this._locationNameByViewId.set(descriptor["id"], descriptor["location"]);
+    }
 }
 
 WebInspector.ViewManager.prototype = {
     /**
+     * @param {!WebInspector.View} view
+     * @return {!Promise}
+     */
+    revealView: function(view)
+    {
+        var location = /** @type {?WebInspector.ViewManager._Location} */ (view[WebInspector.ViewManager._Location.symbol]);
+        if (!location)
+            return Promise.resolve();
+        location._reveal();
+        return location.showView(view);
+    },
+
+    /**
      * @param {string} viewId
+     * @return {!Promise}
      */
     showView: function(viewId)
     {
-        var extensions = self.runtime.extensions("view").filter(extension => extension.descriptor()["id"] === viewId);
-        if (!extensions.length) {
-            console.error("Could not find view for id: '" + viewId + "'");
-            return;
+        var view = this._views.get(viewId);
+        if (!view) {
+            console.error("Could not find view for id: '" + viewId + "' " + new Error().stack);
+            return Promise.resolve();
         }
-        var extension = extensions[0];
-        var location = extensions[0].descriptor()["location"];
-        if (location === "drawer-view")
+        var locationName = this._locationNameByViewId.get(viewId);
+        if (locationName === "drawer-view")
             WebInspector.userMetrics.drawerShown(viewId);
+
+        return this._resolveLocation(locationName).then(location => {
+            if (!location)
+                return;
+            location._reveal();
+            return location.showView(view);
+        });
+    },
+
+    /**
+     * @param {string=} location
+     * @return {!Promise<?WebInspector.ViewManager._Location>}
+     */
+    _resolveLocation: function(location)
+    {
+        if (!location)
+            return /** @type {!Promise<?WebInspector.ViewManager._Location>} */ (Promise.resolve(null));
+
         var resolverExtensions = self.runtime.extensions(WebInspector.ViewLocationResolver).filter(extension => extension.descriptor()["name"] === location);
         if (!resolverExtensions.length)
-            return;
+            return /** @type {!Promise<?WebInspector.ViewManager._Location>} */ (Promise.resolve(null));
         var resolverExtension = resolverExtensions[0];
-        resolverExtension.instance().then(this._revealLocation.bind(this, viewId, location));
+        return resolverExtension.instance().then(resolver => /** @type {?WebInspector.ViewManager._Location} */(resolver.resolveLocation(location)));
     },
 
     /**
-     * @param {string} location
+     * @param {function()=} revealCallback
+     * @param {string=} location
      * @param {boolean=} restoreSelection
-     * @param {boolean=} enableMoreTabsButton
      * @return {!WebInspector.TabbedViewLocation}
      */
-    createTabbedLocation: function(location, restoreSelection, enableMoreTabsButton)
+    createTabbedLocation: function(revealCallback, location, restoreSelection)
     {
-        return new WebInspector.ViewManager._TabbedLocation(this, location, restoreSelection, enableMoreTabsButton);
+        return new WebInspector.ViewManager._TabbedLocation(this, revealCallback, location, restoreSelection);
     },
 
     /**
-     * @param {string} viewId
-     * @param {string} location
-     * @param {!WebInspector.ViewLocationResolver} resolver
+     * @param {function()=} revealCallback
+     * @param {string=} location
+     * @return {!WebInspector.ViewLocation}
      */
-    _revealLocation: function(viewId, location, resolver)
+    createStackLocation: function(revealCallback, location)
     {
-        var viewLocation = resolver.revealLocation(location);
-        if (viewLocation)
-            viewLocation.showView(viewId);
+        return new WebInspector.ViewManager._StackLocation(this, revealCallback, location);
     },
 
     /**
      * @param {string} location
-     * @return {!Array<!Runtime.Extension>}
+     * @return {!Array<!WebInspector.View>}
      */
     _viewsForLocation: function(location)
     {
-        return self.runtime.extensions("view").filter(extension => extension.descriptor()["location"] === location);
+        var result = [];
+        for (var id of this._views.keys()) {
+            if (this._locationNameByViewId.get(id) === location)
+                result.push(this._views.get(id));
+        }
+        return result;
+    }
+}
+
+
+/**
+ * @param {!Element} element
+ * @param {!Array<!WebInspector.ToolbarItem>} toolbarItems
+ */
+WebInspector.ViewManager._populateToolbar = function(element, toolbarItems)
+{
+    if (!toolbarItems.length)
+        return;
+    var toolbar = new WebInspector.Toolbar("");
+    element.insertBefore(toolbar.element, element.firstChild);
+    for (var item of toolbarItems)
+        toolbar.appendToolbarItem(item);
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.VBox}
+ * @param {!WebInspector.View} view
+ */
+WebInspector.ViewManager._ContainerWidget = function(view)
+{
+    WebInspector.VBox.call(this);
+    this.element.classList.add("flex-auto", "view-container", "overflow-auto");
+    this._view = view;
+}
+
+WebInspector.ViewManager._ContainerWidget.prototype = {
+    /**
+     * @return {!Promise}
+     */
+    _materialize: function()
+    {
+        if (this._materializePromise)
+            return this._materializePromise;
+        var promises = [];
+        promises.push(this._view.toolbarItems().then(WebInspector.ViewManager._populateToolbar.bind(WebInspector.ViewManager, this.element)));
+        promises.push(this._view.widget().then(widget => widget.show(this.element)));
+        this._materializePromise = Promise.all(promises);
+        return this._materializePromise;
+    },
+
+    __proto__: WebInspector.VBox.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.VBox}
+ * @param {!WebInspector.View} view
+ */
+WebInspector.ViewManager._ExpandableContainerWidget = function(view)
+{
+    WebInspector.VBox.call(this, true);
+    this.element.classList.add("flex-none");
+    this.registerRequiredCSS("ui/viewContainers.css");
+
+    this._titleElement = createElementWithClass("div", "expandable-view-title");
+    this._titleElement.textContent = view.title();
+    this._titleElement.tabIndex = 0;
+    this._titleElement.addEventListener("click", this._toggleExpanded.bind(this), false);
+    this._titleElement.addEventListener("keydown", this._onTitleKeyDown.bind(this), false);
+    this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
+
+    this.contentElement.createChild("content");
+    this._view = view;
+    view[WebInspector.ViewManager._ExpandableContainerWidget._symbol] = this;
+}
+
+WebInspector.ViewManager._ExpandableContainerWidget._symbol = Symbol("container");
+
+WebInspector.ViewManager._ExpandableContainerWidget.prototype = {
+    /**
+     * @return {!Promise}
+     */
+    _materialize: function()
+    {
+        if (this._materializePromise)
+            return this._materializePromise;
+        var promises = [];
+        promises.push(this._view.toolbarItems().then(WebInspector.ViewManager._populateToolbar.bind(WebInspector.ViewManager, this._titleElement)));
+        promises.push(this._view.widget().then(widget => {
+            this._widget = widget;
+            widget.show(this.element);
+        }));
+        this._materializePromise = Promise.all(promises);
+        return this._materializePromise;
+    },
+
+    /**
+     * @return {!Promise}
+     */
+    _expand: function()
+    {
+        if (this._titleElement.classList.contains("expanded"))
+            return this._materialize();
+        this._titleElement.classList.add("expanded");
+        return this._materialize().then(() => this._widget.show(this.element));
+    },
+
+    _collapse: function()
+    {
+        if (!this._titleElement.classList.contains("expanded"))
+            return;
+        this._titleElement.classList.remove("expanded");
+        this._materialize().then(() => this._widget.detach());
+    },
+
+    _toggleExpanded: function()
+    {
+        if (this._titleElement.classList.contains("expanded"))
+            this._collapse();
+        else
+            this._expand();
+    },
+
+    /**
+     * @param {!Event} event
+     */
+    _onTitleKeyDown: function(event)
+    {
+        if (isEnterKey(event) || event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code)
+            this._toggleExpanded();
+    },
+
+    __proto__: WebInspector.VBox.prototype
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.ViewManager} manager
+ * @param {!WebInspector.Widget} widget
+ * @param {function()=} revealCallback
+ * @param {string=} location
+ */
+WebInspector.ViewManager._Location = function(manager, widget, revealCallback, location)
+{
+    this._manager = manager;
+    this._revealCallback = revealCallback;
+    this._location = location;
+    this._widget = widget;
+}
+
+WebInspector.ViewManager._Location.symbol = Symbol("location");
+
+WebInspector.ViewManager._Location.prototype = {
+    /**
+     * @return {!WebInspector.Widget}
+     */
+    widget: function()
+    {
+        return this._widget;
+    },
+
+    _reveal: function()
+    {
+        if (this._revealCallback)
+            this._revealCallback();
     }
 }
 
 /**
  * @constructor
+ * @extends {WebInspector.ViewManager._Location}
  * @implements {WebInspector.TabbedViewLocation}
  * @param {!WebInspector.ViewManager} manager
- * @param {string} location
+ * @param {function()=} revealCallback
+ * @param {string=} location
  * @param {boolean=} restoreSelection
- * @param {boolean=} enableMoreTabsButton
  */
-WebInspector.ViewManager._TabbedLocation = function(manager, location, restoreSelection, enableMoreTabsButton)
+WebInspector.ViewManager._TabbedLocation = function(manager, revealCallback, location, restoreSelection)
 {
-    this._manager = manager;
     this._tabbedPane = new WebInspector.TabbedPane();
-    this._location = location;
-    /** @type {!Object.<string, !Promise.<?WebInspector.Widget>>} */
-    this._promiseForId = {};
+    WebInspector.ViewManager._Location.call(this, manager, this._tabbedPane, revealCallback, location);
 
     this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
     this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
     this._closeableTabSetting = WebInspector.settings.createSetting(location + "-closeableTabs", {});
     if (restoreSelection)
         this._lastSelectedTabSetting = WebInspector.settings.createSetting(location + "-selectedTab", "");
-    this._initialize();
-    if (enableMoreTabsButton) {
-        var toolbar = new WebInspector.Toolbar("drawer-toolbar");
-        toolbar.appendToolbarItem(new WebInspector.ToolbarMenuButton(this._appendTabsToMenu.bind(this)));
-        this._tabbedPane.insertBeforeTabStrip(toolbar.element);
-        this._tabbedPane.disableOverflowMenu();
-    }
+
+    /** @type {!Map.<string, !WebInspector.View>} */
+    this._views = new Map();
+    this._populateLocation();
 }
 
 WebInspector.ViewManager._TabbedLocation.prototype = {
@@ -198,19 +575,31 @@
         return this._tabbedPane;
     },
 
-    _initialize: function()
+    /**
+     * @override
+     */
+    enableMoreTabsButton: function()
     {
-        /** @type {!Map.<string, !Runtime.Extension>} */
-        this._extensions = new Map();
-        var extensions = this._manager._viewsForLocation(this._location);
+        var toolbar = new WebInspector.Toolbar("drawer-toolbar");
+        toolbar.appendToolbarItem(new WebInspector.ToolbarMenuButton(this._appendTabsToMenu.bind(this)));
+        this._tabbedPane.insertBeforeTabStrip(toolbar.element);
+        this._tabbedPane.disableOverflowMenu();
+    },
 
-        for (var i = 0; i < extensions.length; ++i) {
-            var id = extensions[i].descriptor()["id"];
-            this._extensions.set(id, extensions[i]);
-            if (this._isPermanentTab(id))
-                this._appendTab(extensions[i]);
-            else if (this._isCloseableTab(id) && this._closeableTabSetting.get()[id])
-                this._appendTab(extensions[i]);
+    _populateLocation: function()
+    {
+        if (!this._location)
+            return;
+        for (var view of this._manager._viewsForLocation(this._location)) {
+            var id = view.viewId();
+            this._views.set(id, view);
+            view[WebInspector.ViewManager._Location.symbol] = this;
+            if (view.isTransient())
+                continue;
+            if (!view.isCloseable())
+                this._appendTab(view);
+            else if (this._closeableTabSetting.get()[id])
+                this._appendTab(view);
         }
     },
 
@@ -224,59 +613,52 @@
     },
 
     /**
-     * @param {string} id
-     * @return {boolean}
-     */
-    _isPermanentTab: function(id)
-    {
-        return this._extensions.get(id).descriptor()["persistence"] === "permanent" || !this._extensions.get(id).descriptor()["persistence"];
-    },
-
-    /**
-     * @param {string} id
-     * @return {boolean}
-     */
-    _isCloseableTab: function(id)
-    {
-        return this._extensions.get(id).descriptor()["persistence"] === "closeable";
-    },
-
-    /**
      * @param {!WebInspector.ContextMenu} contextMenu
      */
     _appendTabsToMenu: function(contextMenu)
     {
-        var extensions = self.runtime.extensions("view", undefined, true);
-        for (var extension of extensions) {
-            if (extension.descriptor()["location"] !== this._location)
-                continue;
-            var title = WebInspector.UIString(extension.title());
-            contextMenu.appendItem(title, this.showView.bind(this, extension.descriptor()["id"]));
+        for (var view of this._views.values()) {
+            var title = WebInspector.UIString(view.title());
+            contextMenu.appendItem(title, this.showView.bind(this, view));
         }
     },
 
     /**
-     * @param {!Runtime.Extension} extension
+     * @param {!WebInspector.View} view
      */
-    _appendTab: function(extension)
+    _appendTab: function(view)
     {
-        var descriptor = extension.descriptor();
-        var id = descriptor["id"];
-        var title = WebInspector.UIString(extension.title());
-        var closeable = descriptor["persistence"] === "closeable" || descriptor["persistence"] === "temporary";
-        this._tabbedPane.appendTab(id, title, new WebInspector.Widget(), undefined, false, closeable);
+        this._tabbedPane.appendTab(view.viewId(), view.title(), new WebInspector.ViewManager._ContainerWidget(view), undefined, false, view.isCloseable() || view.isTransient());
     },
 
     /**
      * @override
-     * @param {string} id
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
      */
-    showView: function(id)
+    appendView: function(view, insertBefore)
     {
-        if (!this._tabbedPane.hasTab(id))
-            this._appendTab(/** @type {!Runtime.Extension} */(this._extensions.get(id)));
+        if (insertBefore)
+            throw new Error("Insert before in tabbed pane is not supported");
+        if (!this._tabbedPane.hasTab(view.viewId())) {
+            view[WebInspector.ViewManager._Location.symbol] = this;
+            this._views.set(view.viewId(), view);
+            this._appendTab(view);
+        }
+    },
+
+    /**
+     * @override
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
+     * @return {!Promise}
+     */
+    showView: function(view, insertBefore)
+    {
+        this.appendView(view, insertBefore);
         this._tabbedPane.focus();
-        this._tabbedPane.selectTab(id);
+        this._tabbedPane.selectTab(view.viewId());
+        return this._materializeWidget(view);
     },
 
     /**
@@ -287,13 +669,13 @@
         var tabId = /** @type {string} */ (event.data.tabId);
         if (this._lastSelectedTabSetting && event.data["isUserGesture"])
             this._lastSelectedTabSetting.set(tabId);
-        if (!this._extensions.has(tabId))
+        var view = this._views.get(tabId);
+        if (!view)
             return;
 
-        this._viewForId(tabId);
+        this._materializeWidget(view);
 
-        var descriptor = this._extensions.get(tabId).descriptor();
-        if (descriptor["persistence"] === "closeable") {
+        if (view.isCloseable()) {
             var tabs = this._closeableTabSetting.get();
             if (!tabs[tabId]) {
                 tabs[tabId] = true;
@@ -313,33 +695,87 @@
             delete tabs[id];
             this._closeableTabSetting.set(tabs);
         }
-        delete this._promiseForId[id];
     },
 
     /**
-     * @param {string} id
-     * @return {!Promise.<?WebInspector.Widget>}
+     * @param {!WebInspector.View} view
+     * @return {!Promise}
      */
-    _viewForId: function(id)
+    _materializeWidget: function(view)
     {
-        if (this._promiseForId[id])
-            return this._promiseForId[id];
+        var widget = /** @type {!WebInspector.ViewManager._ContainerWidget} */ (this._tabbedPane.tabView(view.viewId()));
+        return widget._materialize();
+    },
 
-        var promise = this._extensions.get(id).instance();
-        this._promiseForId[id] = /** @type {!Promise.<?WebInspector.Widget>} */ (promise);
-        return promise.then(cacheView.bind(this));
-
-        /**
-         * @param {!Object} object
-         * @this {WebInspector.ViewManager._TabbedLocation}
-         */
-        function cacheView(object)
-        {
-            var view = /** @type {!WebInspector.Widget} */ (object);
-            this._tabbedPane.changeTabView(id, view);
-            return view;
-        }
-    }
+    __proto__: WebInspector.ViewManager._Location.prototype
 }
 
-WebInspector.viewManager = new WebInspector.ViewManager();
+/**
+ * @constructor
+ * @extends {WebInspector.ViewManager._Location}
+ * @implements {WebInspector.ViewLocation}
+ * @param {!WebInspector.ViewManager} manager
+ * @param {function()=} revealCallback
+ * @param {string=} location
+ */
+WebInspector.ViewManager._StackLocation = function(manager, revealCallback, location)
+{
+    this._vbox = new WebInspector.VBox();
+    WebInspector.ViewManager._Location.call(this, manager, this._vbox, revealCallback, location);
+
+    /** @type {!Map<string, !WebInspector.ViewManager._ExpandableContainerWidget>} */
+    this._expandableContainers = new Map();
+    this._populateLocation();
+}
+
+WebInspector.ViewManager._StackLocation.prototype = {
+
+    /**
+     * @override
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
+     */
+    appendView: function(view, insertBefore)
+    {
+        var container = this._expandableContainers.get(view.viewId());
+        if (!container) {
+            view[WebInspector.ViewManager._Location.symbol] = this;
+            container = new WebInspector.ViewManager._ExpandableContainerWidget(view);
+            var beforeElement = null;
+            if (insertBefore) {
+                var beforeContainer = insertBefore[WebInspector.ViewManager._ExpandableContainerWidget._symbol];
+                beforeElement = beforeContainer ? beforeContainer.element : null;
+            }
+            container.show(this._vbox.contentElement, beforeElement);
+            this._expandableContainers.set(view.viewId(), container);
+        }
+    },
+
+    /**
+     * @override
+     * @param {!WebInspector.View} view
+     * @param {?WebInspector.View=} insertBefore
+     * @return {!Promise}
+     */
+    showView: function(view, insertBefore)
+    {
+        this.appendView(view, insertBefore);
+        var container = this._expandableContainers.get(view.viewId());
+        return container._expand();
+    },
+
+    _populateLocation: function()
+    {
+        if (!this._location)
+            return;
+        for (var view of this._manager._viewsForLocation(this._location))
+            this.appendView(view);
+    },
+
+    __proto__: WebInspector.ViewManager._Location.prototype
+}
+
+/**
+ * @type {!WebInspector.ViewManager}
+ */
+WebInspector.viewManager;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js b/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js
deleted file mode 100644
index df45b20..0000000
--- a/third_party/WebKit/Source/devtools/front_end/ui/ViewContainers.js
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @constructor
- * @extends {WebInspector.VBox}
- * @param {!WebInspector.View} view
- */
-WebInspector.View._ContainerWidget = function(view)
-{
-    WebInspector.VBox.call(this);
-    this.element.classList.add("flex-auto", "view-container", "overflow-auto");
-
-    var toolbarItems = view.toolbarItems();
-    if (toolbarItems.length) {
-        var toolbar = new WebInspector.Toolbar("", this.element);
-        for (var item of toolbarItems)
-            toolbar.appendToolbarItem(item);
-    }
-
-    view.show(this.element);
-}
-
-WebInspector.View._ContainerWidget.prototype = {
-    __proto__: WebInspector.VBox.prototype
-}
-
-/**
- * @constructor
- * @extends {WebInspector.VBox}
- * @param {!WebInspector.View} view
- * @param {boolean} expanded
- */
-WebInspector.View._ExpandableContainerWidget = function(view, expanded)
-{
-    WebInspector.VBox.call(this, true);
-    this.element.classList.add("flex-none");
-    this.registerRequiredCSS("ui/viewContainers.css");
-
-    this._titleElement = createElementWithClass("div", "expandable-view-title");
-    this._titleElement.textContent = view.title();
-    this._titleElement.tabIndex = 0;
-    this._titleElement.addEventListener("click", this._toggleExpanded.bind(this), false);
-    this._titleElement.addEventListener("keydown", this._onTitleKeyDown.bind(this), false);
-    this.contentElement.insertBefore(this._titleElement, this.contentElement.firstChild);
-
-    var toolbarElement = this.contentElement.createChild("div");
-    var toolbarItems = view.toolbarItems();
-    if (toolbarItems.length) {
-        this._toolbar = new WebInspector.Toolbar("");
-        for (var item of toolbarItems)
-            this._toolbar.appendToolbarItem(item);
-    }
-
-    this.contentElement.createChild("content");
-    this._view = view;
-    this._view.attach(this);
-    this._view[WebInspector.View._ExpandableContainerWidget._elementSymbol] = this.element;
-    if (expanded)
-        this.revealChild(this._view);
-}
-
-WebInspector.View._ExpandableContainerWidget._elementSymbol = Symbol("container-widget-element");
-
-WebInspector.View._ExpandableContainerWidget.prototype = {
-    /**
-     * @override
-     * @param {!WebInspector.Widget} child
-     * @return {boolean}
-     */
-    revealChild: function(child)
-    {
-        if (this._titleElement.classList.contains("expanded"))
-            return true;
-        if (this._toolbar)
-            this._titleElement.appendChild(this._toolbar.element);
-        this._titleElement.classList.add("expanded");
-        this._view.showWidget(this.element);
-        return true;
-    },
-
-    _collapse: function()
-    {
-        if (!this._titleElement.classList.contains("expanded"))
-            return;
-        if (this._toolbar)
-            this._toolbar.element.remove();
-        this._titleElement.classList.remove("expanded");
-        this._view.hideWidget();
-    },
-
-    _toggleExpanded: function()
-    {
-        if (this._titleElement.classList.contains("expanded"))
-            this._collapse();
-        else
-            this.revealChild(this._view);
-    },
-
-    /**
-     * @param {!Event} event
-     */
-    _onTitleKeyDown: function(event)
-    {
-        if (isEnterKey(event) || event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code)
-            this._toggleExpanded();
-    },
-
-    /**
-     * @param {!WebInspector.Widget} widget
-     * @override
-     */
-    childWasDetached: function(widget)
-    {
-        WebInspector.VBox.prototype.childWasDetached.call(this, widget);
-        delete this._view[WebInspector.View._ExpandableContainerWidget._elementSymbol];
-    },
-
-    __proto__: WebInspector.VBox.prototype
-}
-
-/**
- * @interface {WebInspector.TabbedPane}
- */
-WebInspector.View.Container = function()
-{
-}
-
-WebInspector.View.Container.prototype = {
-    /**
-     * @param {!WebInspector.View} view
-     * @param {boolean=} reveal
-     */
-    appendView: function(view, reveal) { },
-
-    /**
-     * @param {!WebInspector.View} view
-     * @param {?WebInspector.View} insertBefore
-     * @param {boolean=} reveal
-     */
-    insertViewBefore: function(view, insertBefore, reveal) { }
-}
-
-/**
- * @constructor
- * @extends {WebInspector.TabbedPane}
- * @implements {WebInspector.View.Container}
- */
-WebInspector.View.TabbedPaneContainer = function()
-{
-    WebInspector.TabbedPane.call(this);
-}
-
-WebInspector.View.TabbedPaneContainer.prototype = {
-    /**
-     * @param {!WebInspector.View} view
-     * @param {boolean=} reveal
-     * @override
-     */
-    appendView: function(view, reveal)
-    {
-        this.insertViewBefore(view, null, reveal);
-    },
-
-    /**
-     * @param {!WebInspector.View} view
-     * @param {?WebInspector.View} insertBefore
-     * @param {boolean=} reveal
-     * @override
-     */
-    insertViewBefore: function(view, insertBefore, reveal)
-    {
-        var widgets = this.tabViews();
-        var index = 0;
-        for (var i = 0; insertBefore && i < widgets.length; ++i) {
-            if (widgets[i]._view === insertBefore) {
-                index = i;
-                break;
-            }
-        }
-        this.appendTab(view.title(), view.title(), new WebInspector.View._ContainerWidget(view), undefined, false, false, insertBefore ? index : undefined);
-        if (reveal)
-            this.selectTab(view.title());
-    },
-
-    __proto__: WebInspector.TabbedPane.prototype
-}
-
-/**
- * @constructor
- * @extends {WebInspector.VBox}
- * @implements {WebInspector.View.Container}
- */
-WebInspector.View.ExpandableStackContainer = function()
-{
-    WebInspector.VBox.call(this);
-    this.element.classList.add("flex-auto", "overflow-auto");
-}
-
-WebInspector.View.ExpandableStackContainer.prototype = {
-
-    /**
-     * @param {!WebInspector.View} view
-     * @param {boolean=} reveal
-     * @override
-     */
-    appendView: function(view, reveal)
-    {
-        this.insertViewBefore(view, null, reveal);
-    },
-
-    /**
-     * @param {!WebInspector.View} view
-     * @param {?WebInspector.View} insertBefore
-     * @param {boolean=} reveal
-     * @override
-     */
-    insertViewBefore: function(view, insertBefore, reveal)
-    {
-        new WebInspector.View._ExpandableContainerWidget(view, reveal || false).show(this.contentElement, insertBefore ? insertBefore[WebInspector.View._ExpandableContainerWidget._elementSymbol] : null);
-    },
-
-    __proto__: WebInspector.VBox.prototype
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
index 5be8034..8b6954c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
@@ -555,25 +555,6 @@
             this._parentWidget.doLayout();
     },
 
-    /**
-     * @return {boolean}
-     */
-    revealWidget: function()
-    {
-        if (!this._parentWidget)
-            return this._isRoot;
-        if (!this._parentWidget.revealChild(this))
-            return false;
-        return this._parentWidget.revealWidget();
-    },
-
-    /**
-     * @param {!WebInspector.Widget} widget
-     * @return {boolean}
-     * @protected
-     */
-    revealChild: function(widget) { return true; },
-
     __proto__: WebInspector.Object.prototype
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/module.json b/third_party/WebKit/Source/devtools/front_end/ui/module.json
index ae85e8ba..54ac23fd 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/ui/module.json
@@ -46,7 +46,6 @@
         "SuggestBox.js",
         "TabbedPane.js",
         "UIUtils.js",
-        "ViewContainers.js",
         "ViewportControl.js",
         "ZoomManager.js"
     ],
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
index dc2fe7e..a0a595620 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/viewContainers.css
@@ -49,6 +49,10 @@
     border-bottom: 1px solid #ddd;
 }
 
+.expandable-view-title:not(.expanded) .toolbar {
+    display: none;
+}
+
 .expandable-view-title::before {
     -webkit-mask-image: url(Images/toolbarButtonGlyphs.png);
     -webkit-mask-size: 352px 168px;
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
index 1771965..449ff3b6 100755
--- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
+++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -87,8 +87,8 @@
 type_checked_jsdoc_tags_list = ['param', 'return', 'type', 'enum']
 type_checked_jsdoc_tags_or = '|'.join(type_checked_jsdoc_tags_list)
 
-# Basic regex for invalid JsDoc types: an object type name ([A-Z][A-Za-z0-9.]+[A-Za-z0-9]) not preceded by '!', '?', ':' (this, new), or '.' (object property).
-invalid_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{.*(?<![!?:.A-Za-z0-9])([A-Z][A-Za-z0-9.]+[A-Za-z0-9])[^/]*\}')
+# Basic regex for invalid JsDoc types: an object type name ([A-Z][_A-Za-z0-9.]+[A-Za-z0-9]) not preceded by '!', '?', ':' (this, new), or '.' (object property).
+invalid_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{.*(?<![!?:._A-Za-z0-9])([A-Z][_A-Za-z0-9.]+[A-Za-z0-9])[^/]*\}')
 invalid_type_designator_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*.*(?<![{: ])([?!])=?\}')
 invalid_non_object_type_regex = re.compile(r'@(?:' + type_checked_jsdoc_tags_or + r')\s*\{.*(![a-z]+)[^/]*\}')
 error_warning_regex = re.compile(r'WARNING|ERROR')
diff --git a/third_party/WebKit/Source/modules/indexeddb/IndexedDBNames.in b/third_party/WebKit/Source/modules/indexeddb/IndexedDBNames.in
index 39a9f00c..71a601c 100644
--- a/third_party/WebKit/Source/modules/indexeddb/IndexedDBNames.in
+++ b/third_party/WebKit/Source/modules/indexeddb/IndexedDBNames.in
@@ -1,5 +1,7 @@
 namespace="IndexedDB"
 
+IndexedDB
+
 # http://www.w3.org/TR/IndexedDB/#idl-def-IDBCursorDirection
 next
 nextunique
diff --git a/third_party/WebKit/Source/modules/indexeddb/WebIDBCallbacksImpl.cpp b/third_party/WebKit/Source/modules/indexeddb/WebIDBCallbacksImpl.cpp
index abecd340..f8a3fa4 100644
--- a/third_party/WebKit/Source/modules/indexeddb/WebIDBCallbacksImpl.cpp
+++ b/third_party/WebKit/Source/modules/indexeddb/WebIDBCallbacksImpl.cpp
@@ -30,6 +30,7 @@
 
 #include "core/dom/DOMException.h"
 #include "core/inspector/InspectorInstrumentation.h"
+#include "modules/IndexedDBNames.h"
 #include "modules/indexeddb/IDBMetadata.h"
 #include "modules/indexeddb/IDBRequest.h"
 #include "modules/indexeddb/IDBValue.h"
@@ -62,7 +63,7 @@
 WebIDBCallbacksImpl::WebIDBCallbacksImpl(IDBRequest* request)
     : m_request(request)
 {
-    InspectorInstrumentation::asyncTaskScheduled(m_request->getExecutionContext(), "IndexedDB", this, true);
+    InspectorInstrumentation::asyncTaskScheduled(m_request->getExecutionContext(), IndexedDBNames::IndexedDB, this, true);
 }
 
 WebIDBCallbacksImpl::~WebIDBCallbacksImpl()
diff --git a/third_party/WebKit/Source/platform/graphics/Color.cpp b/third_party/WebKit/Source/platform/graphics/Color.cpp
index cc973b6..3ba79ed4 100644
--- a/third_party/WebKit/Source/platform/graphics/Color.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Color.cpp
@@ -212,10 +212,7 @@
     result.appendNumber(static_cast<unsigned char>(blue()));
     if (colorHasAlpha) {
         result.append(", ");
-
-        NumberToStringBuffer buffer;
-        const char* alphaString = numberToFixedPrecisionString(alpha() / 255.0f, 6, buffer, true);
-        result.append(alphaString, strlen(alphaString));
+        result.appendNumber(alpha() / 255.0f, 6);
     }
 
     result.append(')');
diff --git a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
index 5e18e7d..bed2c5e4 100644
--- a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
+++ b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
@@ -106,7 +106,7 @@
 void DateTimeChooserImpl::writeDocument(SharedBuffer* data)
 {
     String stepString = String::number(m_parameters.step);
-    String stepBaseString = String::number(m_parameters.stepBase, 11, WTF::TruncateTrailingZeros);
+    String stepBaseString = String::number(m_parameters.stepBase, 11);
     String todayLabelString;
     String otherDateLabelString;
     if (m_parameters.type == InputTypeNames::month) {
diff --git a/third_party/WebKit/Source/wtf/dtoa.cpp b/third_party/WebKit/Source/wtf/dtoa.cpp
index db2826b7..b2309e9 100644
--- a/third_party/WebKit/Source/wtf/dtoa.cpp
+++ b/third_party/WebKit/Source/wtf/dtoa.cpp
@@ -87,7 +87,7 @@
     return builder.Finalize();
 }
 
-const char* numberToFixedPrecisionString(double d, unsigned significantFigures, NumberToStringBuffer buffer, bool truncateTrailingZeros)
+const char* numberToFixedPrecisionString(double d, unsigned significantFigures, NumberToStringBuffer buffer)
 {
     // Mimic String::format("%.[precision]g", ...), but use dtoas rounding facilities.
     // "g": Signed value printed in f or e format, whichever is more compact for the given value and precision.
@@ -97,8 +97,6 @@
     double_conversion::StringBuilder builder(buffer, NumberToStringBufferLength);
     const double_conversion::DoubleToStringConverter& converter = double_conversion::DoubleToStringConverter::EcmaScriptConverter();
     converter.ToPrecision(d, significantFigures, &builder);
-    if (!truncateTrailingZeros)
-        return builder.Finalize();
     // FIXME: Trailing zeros should never be added in the first place. The
     // current implementation does not strip when there is an exponent, eg.
     // 1.50000e+10.
diff --git a/third_party/WebKit/Source/wtf/dtoa.h b/third_party/WebKit/Source/wtf/dtoa.h
index 6d9cda2..c09f3c6c 100644
--- a/third_party/WebKit/Source/wtf/dtoa.h
+++ b/third_party/WebKit/Source/wtf/dtoa.h
@@ -33,7 +33,7 @@
 typedef char NumberToStringBuffer[NumberToStringBufferLength];
 
 WTF_EXPORT const char* numberToString(double, NumberToStringBuffer);
-WTF_EXPORT const char* numberToFixedPrecisionString(double, unsigned significantFigures, NumberToStringBuffer, bool truncateTrailingZeros = false);
+WTF_EXPORT const char* numberToFixedPrecisionString(double, unsigned significantFigures, NumberToStringBuffer);
 WTF_EXPORT const char* numberToFixedWidthString(double, unsigned decimalPlaces, NumberToStringBuffer);
 
 WTF_EXPORT double parseDouble(const LChar* string, size_t length, size_t& parsedLength);
diff --git a/third_party/WebKit/Source/wtf/dtoa_test.cpp b/third_party/WebKit/Source/wtf/dtoa_test.cpp
index 2fd8c3c..852cc1a 100644
--- a/third_party/WebKit/Source/wtf/dtoa_test.cpp
+++ b/third_party/WebKit/Source/wtf/dtoa_test.cpp
@@ -13,40 +13,31 @@
     NumberToStringBuffer buffer;
 
     // There should be no trailing decimal or zeros.
-    numberToFixedPrecisionString(0.0, 6, buffer, true);
+    numberToFixedPrecisionString(0.0, 6, buffer);
     EXPECT_STREQ("0", buffer);
 
     // Up to 6 leading zeros.
-    numberToFixedPrecisionString(0.00000123123123, 6, buffer, true);
+    numberToFixedPrecisionString(0.00000123123123, 6, buffer);
     EXPECT_STREQ("0.00000123123", buffer);
 
-    numberToFixedPrecisionString(0.000000123123123, 6, buffer, true);
+    numberToFixedPrecisionString(0.000000123123123, 6, buffer);
     EXPECT_STREQ("1.23123e-7", buffer);
 
     // Up to 6 places before the decimal.
-    numberToFixedPrecisionString(123123.123, 6, buffer, true);
+    numberToFixedPrecisionString(123123.123, 6, buffer);
     EXPECT_STREQ("123123", buffer);
 
-    numberToFixedPrecisionString(1231231.23, 6, buffer, true);
+    numberToFixedPrecisionString(1231231.23, 6, buffer);
     EXPECT_STREQ("1.23123e+6", buffer);
 
     // Don't strip trailing zeros in exponents.
     // http://crbug.com/545711
-    numberToFixedPrecisionString(0.000000000123123, 6, buffer, true);
+    numberToFixedPrecisionString(0.000000000123123, 6, buffer);
     EXPECT_STREQ("1.23123e-10", buffer);
 
     // FIXME: Trailing zeros before exponents should be stripped.
-    numberToFixedPrecisionString(0.0000000001, 6, buffer, true);
+    numberToFixedPrecisionString(0.0000000001, 6, buffer);
     EXPECT_STREQ("1.00000e-10", buffer);
 }
 
-TEST(DtoaTest, TestNumberToFixedPrecisionString_DontTruncateTrailingZeros)
-{
-    NumberToStringBuffer buffer;
-
-    // There should be a trailing decimal and zeros.
-    numberToFixedPrecisionString(0.0, 6, buffer, false);
-    EXPECT_STREQ("0.00000", buffer);
-}
-
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.cpp b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
index e787fd6..31da70cc9 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.cpp
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
@@ -124,10 +124,10 @@
     return integerToAtomicString(number);
 }
 
-AtomicString AtomicString::number(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy)
+AtomicString AtomicString::number(double number, unsigned precision)
 {
     NumberToStringBuffer buffer;
-    return AtomicString(numberToFixedPrecisionString(number, precision, buffer, trailingZerosTruncatingPolicy == TruncateTrailingZeros));
+    return AtomicString(numberToFixedPrecisionString(number, precision, buffer));
 }
 
 std::ostream& operator<<(std::ostream& out, const AtomicString& s)
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.h b/third_party/WebKit/Source/wtf/text/AtomicString.h
index eb95915..ed2a0ce 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.h
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.h
@@ -112,7 +112,7 @@
     static AtomicString number(long long);
     static AtomicString number(unsigned long long);
 
-    static AtomicString number(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
+    static AtomicString number(double, unsigned precision = 6);
 
     bool isNull() const { return m_string.isNull(); }
     bool isEmpty() const { return m_string.isEmpty(); }
diff --git a/third_party/WebKit/Source/wtf/text/StringBuilder.cpp b/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
index 84b332a..f8e36ae5 100644
--- a/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringBuilder.cpp
@@ -241,10 +241,10 @@
     appendIntegerInternal(*this, number);
 }
 
-void StringBuilder::appendNumber(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy)
+void StringBuilder::appendNumber(double number, unsigned precision)
 {
     NumberToStringBuffer buffer;
-    append(numberToFixedPrecisionString(number, precision, buffer, trailingZerosTruncatingPolicy == TruncateTrailingZeros));
+    append(numberToFixedPrecisionString(number, precision, buffer));
 }
 
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/text/StringBuilder.h b/third_party/WebKit/Source/wtf/text/StringBuilder.h
index 70b986e..3b2c36556 100644
--- a/third_party/WebKit/Source/wtf/text/StringBuilder.h
+++ b/third_party/WebKit/Source/wtf/text/StringBuilder.h
@@ -154,7 +154,7 @@
     void appendNumber(unsigned long);
     void appendNumber(long long);
     void appendNumber(unsigned long long);
-    void appendNumber(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
+    void appendNumber(double, unsigned precision = 6);
 
     String toString();
     AtomicString toAtomicString();
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.cpp b/third_party/WebKit/Source/wtf/text/WTFString.cpp
index d7e0be4..e6692f8 100644
--- a/third_party/WebKit/Source/wtf/text/WTFString.cpp
+++ b/third_party/WebKit/Source/wtf/text/WTFString.cpp
@@ -515,10 +515,10 @@
     return integerToString(number);
 }
 
-String String::number(double number, unsigned precision, TrailingZerosTruncatingPolicy trailingZerosTruncatingPolicy)
+String String::number(double number, unsigned precision)
 {
     NumberToStringBuffer buffer;
-    return String(numberToFixedPrecisionString(number, precision, buffer, trailingZerosTruncatingPolicy == TruncateTrailingZeros));
+    return String(numberToFixedPrecisionString(number, precision, buffer));
 }
 
 String String::numberToStringECMAScript(double number)
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.h b/third_party/WebKit/Source/wtf/text/WTFString.h
index 13d42c5..9236f86 100644
--- a/third_party/WebKit/Source/wtf/text/WTFString.h
+++ b/third_party/WebKit/Source/wtf/text/WTFString.h
@@ -43,11 +43,6 @@
 class CString;
 struct StringHash;
 
-enum TrailingZerosTruncatingPolicy {
-    KeepTrailingZeros,
-    TruncateTrailingZeros
-};
-
 enum UTF8ConversionMode {
     LenientUTF8Conversion,
     StrictUTF8Conversion,
@@ -168,7 +163,7 @@
     static String number(long long);
     static String number(unsigned long long);
 
-    static String number(double, unsigned precision = 6, TrailingZerosTruncatingPolicy = TruncateTrailingZeros);
+    static String number(double, unsigned precision = 6);
 
     // Number to String conversion following the ECMAScript definition.
     static String numberToStringECMAScript(double);
@@ -608,7 +603,6 @@
 WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(String);
 
 using WTF::CString;
-using WTF::KeepTrailingZeros;
 using WTF::StrictUTF8Conversion;
 using WTF::StrictUTF8ConversionReplacingUnpairedSurrogatesWithFFFD;
 using WTF::String;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 1d17473..7dd4a384 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -99941,6 +99941,7 @@
   <suffix name="async_loading" label="Offline async loaded pages"/>
   <suffix name="custom_tabs" label="Offline custom tabs"/>
   <suffix name="download" label="Offline downloaded pages"/>
+  <affected-histogram name="OfflinePages.Background.OfflinerRequestStatus"/>
   <affected-histogram name="OfflinePages.DeletePage.AccessCount"/>
   <affected-histogram name="OfflinePages.DeletePage.LastOpenToCreated"/>
   <affected-histogram name="OfflinePages.DeletePage.PageSize"/>